From 53fd9a441c2d1e2822388603019dc7f14e2979cd Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Wed, 2 Oct 2024 18:33:27 +0800 Subject: [PATCH 001/209] Working on first ledger release --- config/environment.js | 5 + package.json | 9 +- pnpm-lock.yaml | 1305 +++++++++++++++++++++++++++++++++-------- 3 files changed, 1056 insertions(+), 263 deletions(-) diff --git a/config/environment.js b/config/environment.js index f6a19f8..3814eb7 100644 --- a/config/environment.js +++ b/config/environment.js @@ -5,6 +5,11 @@ module.exports = function (environment) { let ENV = { modulePrefix: name, environment, + 'ember-leaflet': { + excludeCSS: true, + excludeJS: true, + excludeImages: true, + }, }; return ENV; diff --git a/package.json b/package.json index 595e276..bdf7822 100644 --- a/package.json +++ b/package.json @@ -43,14 +43,16 @@ "publish:github": "npm config set '@fleetbase:registry' https://npm.pkg.github.com/ && npm publish" }, "dependencies": { - "@fleetbase/ember-core": "^0.2.13", - "@fleetbase/ember-ui": "^0.2.19", - "@fleetbase/fleetops-data": "^0.1.17", + "@fleetbase/ember-core": "^0.2.19", + "@fleetbase/ember-ui": "^0.2.32", + "@fleetbase/fleetops-data": "^0.1.18", "@fortawesome/ember-fontawesome": "^2.0.0", "@fortawesome/fontawesome-svg-core": "6.4.0", + "@fortawesome/free-brands-svg-icons": "6.4.0", "@fortawesome/free-solid-svg-icons": "6.4.0", "@babel/core": "^7.23.2", "broccoli-funnel": "^3.0.8", + "ember-auto-import": "^2.7.4", "ember-cli-babel": "^8.2.0", "ember-cli-htmlbars": "^6.3.0", "ember-intl": "6.3.2", @@ -69,7 +71,6 @@ "@glimmer/tracking": "^1.1.2", "broccoli-asset-rev": "^3.0.0", "concurrently": "^8.2.2", - "ember-auto-import": "^2.6.3", "ember-cli": "~5.4.1", "ember-cli-clean-css": "^3.0.0", "ember-cli-dependency-checker": "^3.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98957c3..1f5a725 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,26 +12,32 @@ importers: specifier: ^7.23.2 version: 7.23.2 '@fleetbase/ember-core': - specifier: ^0.2.13 - version: 0.2.13(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0) - '@fleetbase/ember-ui': specifier: ^0.2.19 - version: 0.2.19(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(postcss@8.4.35)(tracked-built-ins@3.3.0)(webpack@5.89.0) + version: 0.2.19(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + '@fleetbase/ember-ui': + specifier: ^0.2.32 + version: 0.2.32(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(postcss@8.4.35)(rollup@2.79.1)(tracked-built-ins@3.3.0)(webpack@5.89.0) '@fleetbase/fleetops-data': - specifier: ^0.1.17 - version: 0.1.17(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0) + specifier: ^0.1.18 + version: 0.1.18(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) '@fortawesome/ember-fontawesome': specifier: ^2.0.0 - version: 2.0.0(ember-source@5.4.0)(webpack@5.89.0) + version: 2.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0) '@fortawesome/fontawesome-svg-core': specifier: 6.4.0 version: 6.4.0 + '@fortawesome/free-brands-svg-icons': + specifier: 6.4.0 + version: 6.4.0 '@fortawesome/free-solid-svg-icons': specifier: 6.4.0 version: 6.4.0 broccoli-funnel: specifier: ^3.0.8 version: 3.0.8 + ember-auto-import: + specifier: ^2.7.4 + version: 2.8.1(webpack@5.89.0) ember-cli-babel: specifier: ^8.2.0 version: 8.2.0(@babel/core@7.23.2) @@ -43,7 +49,7 @@ importers: version: 6.3.2(@babel/core@7.23.2)(webpack@5.89.0) ember-leaflet: specifier: ^5.1.1 - version: 5.1.1(@babel/core@7.23.2)(ember-source@5.4.0)(leaflet@1.9.4)(webpack@5.89.0) + version: 5.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(leaflet@1.9.4)(webpack@5.89.0) ember-radio-button: specifier: ^3.0.0-beta.1 version: 3.0.0-beta.1 @@ -65,7 +71,7 @@ importers: version: 2.0.0 '@ember/test-helpers': specifier: ^3.2.0 - version: 3.2.0(ember-source@5.4.0)(webpack@5.89.0) + version: 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) '@embroider/test-setup': specifier: ^3.0.2 version: 3.0.2 @@ -81,18 +87,15 @@ importers: concurrently: specifier: ^8.2.2 version: 8.2.2 - ember-auto-import: - specifier: ^2.6.3 - version: 2.6.3(webpack@5.89.0) ember-cli: specifier: ~5.4.1 - version: 5.4.1 + version: 5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6) ember-cli-clean-css: specifier: ^3.0.0 version: 3.0.0 ember-cli-dependency-checker: specifier: ^3.3.2 - version: 3.3.2(ember-cli@5.4.1) + version: 3.3.2(ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6)) ember-cli-inject-live-reload: specifier: ^2.1.0 version: 2.1.0 @@ -107,34 +110,34 @@ importers: version: 5.0.0 ember-concurrency: specifier: ^3.1.1 - version: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0) + version: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-concurrency-decorators: specifier: ^2.0.3 version: 2.0.3(@babel/core@7.23.2) ember-data: specifier: ^4.12.5 - version: 4.12.5(@babel/core@7.23.2)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(webpack@5.89.0) + version: 4.12.5(@babel/core@7.23.2)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) ember-engines: specifier: ^0.9.0 - version: 0.9.0(ember-source@5.4.0) + version: 0.9.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-load-initializers: specifier: ^2.1.2 version: 2.1.2(@babel/core@7.23.2) ember-math-helpers: specifier: ^4.0.0 - version: 4.0.0(ember-source@5.4.0) + version: 4.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-page-title: specifier: ^8.0.0 version: 8.0.0 ember-qunit: specifier: ^8.0.1 - version: 8.0.1(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(qunit@2.20.0) + version: 8.0.1(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(qunit@2.20.0) ember-resolver: specifier: ^11.0.1 - version: 11.0.1(ember-source@5.4.0) + version: 11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-source: specifier: ~5.4.0 - version: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + version: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) ember-source-channel-url: specifier: ^3.0.0 version: 3.0.0 @@ -158,7 +161,7 @@ importers: version: 16.2.0(eslint@8.52.0) eslint-plugin-prettier: specifier: ^5.0.1 - version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.52.0)(prettier@3.0.3) + version: 5.0.1(@types/eslint@8.56.2)(eslint-config-prettier@9.0.0(eslint@8.52.0))(eslint@8.52.0)(prettier@3.0.3) eslint-plugin-qunit: specifier: ^8.0.1 version: 8.0.1(eslint@8.52.0) @@ -1245,6 +1248,10 @@ packages: resolution: {integrity: sha512-JGOQNRj3UR0NdWEg8MsM2eqPLncEwSB1IX+rwntIj22TEKj8biqx7GDgSbeH+ZedijmCh354Hf2c5rthrdzUAw==} engines: {node: 12.* || 14.* || >= 16} + '@embroider/addon-shim@1.8.9': + resolution: {integrity: sha512-qyN64T1jMHZ99ihlk7VFHCWHYZHLE1DOdHi0J7lmn5waV1DoW7gD8JLi1i7FregzXtKhbDc7shyEmTmWPTs8MQ==} + engines: {node: 12.* || 14.* || >= 16} + '@embroider/addon@0.30.0': resolution: {integrity: sha512-hBgskhX38RMIyHcnUpRt+KbddLMPLVOFdLp4qhv7Vs881SPDwsbo7pir4KpILmnoqcvBMh1MCVY970tYaAyMcQ==} engines: {node: 10.* || >= 12} @@ -1266,6 +1273,10 @@ packages: resolution: {integrity: sha512-jNDJ9YlV6Qp9Na9v17qirUewVuq6T0t32nn+bbnFlCRTvmllKluZdYPSC5RuRnEZKTloVYRSF0+f1rgkTIEvxQ==} engines: {node: 12.* || 14.* || >= 16} + '@embroider/shared-internals@2.7.0': + resolution: {integrity: sha512-ISaVmGvTI+y7QRwo+Qku9mDm1p35DV4Gi7luSoizL88PlC2UZHuK6nOEEF2hjsqUnHwmEv0jd3/tpOCohwgk6w==} + engines: {node: 12.* || 14.* || >= 16} + '@embroider/test-setup@3.0.2': resolution: {integrity: sha512-cq/xp06CAB8rAGnObeJux7qALnAX2MatMVLjWyGDr3ogS5lHTNXZVCv4ltTM3pJ8EsZWpPM32dtUZqSJFkGibQ==} engines: {node: 12.* || 14.* || >= 16} @@ -1318,16 +1329,16 @@ packages: peerDependencies: ember-source: '>= 4.0.0' - '@fleetbase/ember-core@0.2.13': - resolution: {integrity: sha512-XIKDaUX+VIjGnrRXZi2f0DoMUPT7Sr0VpOmIGFI7kfBwIOCroZ4yoh/7Pr9Y7AnZ/a0g4+pab9i69SNDfRHpKA==} + '@fleetbase/ember-core@0.2.19': + resolution: {integrity: sha512-xXRBp+dqZ975bPyAxvxlw1K+kcVxu1XZ9/Db+eySNPS2ua+wswg8+KyegnU6hkJflDgFjo7xTqBL30WVrjRUiQ==} engines: {node: '>= 18'} - '@fleetbase/ember-ui@0.2.19': - resolution: {integrity: sha512-VxWjr56T7CpkjTBNquGSyZIQz+cpIzJW26UY0DVnPYgczRXq/h0XgBzyxSc5Ubr6IeLKxhK0r1+lcKvdSLCw+w==} + '@fleetbase/ember-ui@0.2.32': + resolution: {integrity: sha512-+6lPyziomGKA405ILe6DSY9tBfehMTO1pSpe/8ZUQrez06wda6Ci4C2DCNd5vWmOlOtiC91cRKLUcN6Myx9dwQ==} engines: {node: '>= 18'} - '@fleetbase/fleetops-data@0.1.17': - resolution: {integrity: sha512-cT3MgW0klMByRtUZMJO5d5CfaWCg4Ss9vVr/YA1iUL5DtHP5RgpCmndFLqa0nyYpncIwhkCykfWAUts4PUl+sg==} + '@fleetbase/fleetops-data@0.1.18': + resolution: {integrity: sha512-SBiL992igloYgEGMbUX65uW95nv8k32u2QSoqVm7HrWfhCwMEeHubEOA916otDkBalkHNSE6QgWigaJDMNnW4A==} engines: {node: '>= 18'} '@floating-ui/core@1.6.0': @@ -1576,6 +1587,9 @@ packages: resolution: {integrity: sha512-JSrpQUFCs4vY1D5tOmj7qBb+oE2j/lO6341giEdUpvYf3FijY8CY13l8rPjfHV2y3m//utzl0An+q+qx14S6Nw==} engines: {node: '>=16.14'} + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + '@rollup/plugin-node-resolve@15.2.3': resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} engines: {node: '>=14.0.0'} @@ -1616,6 +1630,195 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' + '@tiptap/core@2.8.0': + resolution: {integrity: sha512-xsqDI4BNzYRWRtBq7+/38ThhqEr7uG9Njip1x+9/wgR3vWPBFnBkYJTz6jSxS35NRE6BSnERm4/B/vrLuY1Hdw==} + peerDependencies: + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-blockquote@2.8.0': + resolution: {integrity: sha512-m3CKrOIvV7fY1Ak2gYf5LkKiz6AHxHpg6wxfVaJvdBqXgLyVtHo552N+A4oSHOSRbB4AG9EBQ2NeBM8cdEQ4MA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-bold@2.8.0': + resolution: {integrity: sha512-U1YkZBxDkSLNvPNiqxB5g42IeJHr27C7zDb/yGQN2xL4UBeg4O9xVhCFfe32f6tLwivSL0dar4ScElpaCJuqow==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-bullet-list@2.8.0': + resolution: {integrity: sha512-H4O2X0ozbc/ce9/XF1H98sqWVUdtt7jzy7hMBunwmY8ZxI4dHtcRkeg81CZbpKTqOqRrMCLWjE3M2tgiDXrDkA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/extension-list-item': ^2.7.0 + '@tiptap/extension-text-style': ^2.7.0 + + '@tiptap/extension-code-block@2.8.0': + resolution: {integrity: sha512-POuA5Igx+Dto0DTazoBFAQTj/M/FCdkqRVD9Uhsxhv49swPyANTJRr05vgbgtHB+NDDsZfCawVh7pI0IAD/O0w==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-code@2.8.0': + resolution: {integrity: sha512-VSFn3sFF6qPpOGkXFhik8oYRH5iByVJpFEFd/duIEftmS0MdPzkbSItOpN3mc9xsJ5dCX80LYaResSj5hr5zkA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-color@2.8.0': + resolution: {integrity: sha512-b0ZIDaZKTDVdTb0PMgtOiPzgCkYhvDldjzdWyPLsjWup5x9/zPasH5X/2SfMuwtjt+cKj6YBPveJjF7w5ApK7w==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/extension-text-style': ^2.7.0 + + '@tiptap/extension-document@2.8.0': + resolution: {integrity: sha512-mp7Isx1sVc/ifeW4uW/PexGQ9exN3NRUOebSpnLfqXeWYk4y1RS1PA/3+IHkOPVetbnapgPjFx/DswlCP3XLjA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-dropcursor@2.8.0': + resolution: {integrity: sha512-rAFvx44YuT6dtS1c+ALw0ROAGI16l5L1HxquL4hR1gtxDcTieST5xhw5bkshXlmrlfotZXPrhokzqA7qjhZtJw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-font-family@2.8.0': + resolution: {integrity: sha512-v35PeyC6+iIRXnXDDg8xJVCEEtRcGqcUvm5lO9kKqBcoMg20BXF1+mhY3pSigQ1VMtZfh9XO+BHlfTDC02S9QQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/extension-text-style': ^2.7.0 + + '@tiptap/extension-gapcursor@2.8.0': + resolution: {integrity: sha512-Be1LWCmvteQInOnNVN+HTqc1XWsj1bCl+Q7et8qqNjtGtTaCbdCp8ppcH1SKJxNTM/RLUtPyJ8FDgOTj51ixCA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-hard-break@2.8.0': + resolution: {integrity: sha512-vqiIfviNiCmy/pJTHuDSCAGL2O4QDEdDmAvGJu8oRmElUrnlg8DbJUfKvn6DWQHNSQwRb+LDrwWlzAYj1K9u6A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-heading@2.8.0': + resolution: {integrity: sha512-4inWgrTPiqlivPmEHFOM5ck2UsmOsbKKPtqga6bALvWPmCv24S6/EBwFp8Jz4YABabXDnkviihmGu0LpP9D69w==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-highlight@2.8.0': + resolution: {integrity: sha512-vyqX7D449nuARhI0AyRqtIZReFg3sfc/U/q1p3JOjtUoW6z2jmDTzshiKRrSg+Jf7Hhzj1pqwU+6+CpelPPDpA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-history@2.8.0': + resolution: {integrity: sha512-u5YS0J5Egsxt8TUWMMAC3QhPZaak+IzQeyHch4gtqxftx96tprItY7AD/A3pGDF2uCSnN+SZrk6yVexm6EncDw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-horizontal-rule@2.8.0': + resolution: {integrity: sha512-Sn/MI8WVFBoIYSIHA9NJryJIyCEzZdRysau8pC5TFnfifre0QV1ksPz2bgF+DyCD69ozQiRdBBHDEwKe47ZbfQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-image@2.8.0': + resolution: {integrity: sha512-5CReomgHGTUgxaX8P3i6qiC9VRWcWQgVoYtds4ZM52LVx/oGwMxQ4ECyzdVYKaRW+6PrNnAe6ew3Qpd5Wk0cIg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-italic@2.8.0': + resolution: {integrity: sha512-PwwSE2LTYiHI47NJnsfhBmPiLE8IXZYqaSoNPU6flPrk1KxEzqvRI1joKZBmD9wuqzmHJ93VFIeZcC+kfwi8ZA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-list-item@2.8.0': + resolution: {integrity: sha512-o7OGymGxB0B9x3x2prp3KBDYFuBYGc5sW69O672jk8G52DqhzzndgPnkk0qUn8nXAUKuDGbJmpmHVA2kagqnRg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-ordered-list@2.8.0': + resolution: {integrity: sha512-sCvNbcTS1+5QTTXwUPFa10vf5I1pr8sGcOTIh0G+a5ZkS5+6FxT12k7VLzPt39QyNbOi+77U2o4Xr4XyaEkfSg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/extension-list-item': ^2.7.0 + '@tiptap/extension-text-style': ^2.7.0 + + '@tiptap/extension-paragraph@2.8.0': + resolution: {integrity: sha512-XgxxNNbuBF48rAGwv7/s6as92/xjm/lTZIGTq9aG13ClUKFtgdel7C33SpUCcxg3cO2WkEyllXVyKUiauFZw/A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-placeholder@2.8.0': + resolution: {integrity: sha512-BMqv/C9Tcjd7L1/OphUAJTZhWfpWs0rTQJ0bs3RRGsC8L+K20Fg+li45vw7M0teojpfrw57zwJogJd/m23Zr1Q==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-strike@2.8.0': + resolution: {integrity: sha512-ezkDiXxQ3ME/dDMMM7tAMkKRi6UWw7tIu+Mx7Os0z8HCGpVBk1gFhLlhEd8I5rJaPZr4tK1wtSehMA9bscFGQw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-subscript@2.8.0': + resolution: {integrity: sha512-m14K5M7E+SqqrBul+B9t5sjN4zqTddV+Q+vd+RIm+OHG6AQhwewNoFyghZz5dGZ2Xj7HqiEyusBN+iHwfgJpmg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-superscript@2.8.0': + resolution: {integrity: sha512-3rAVyRvzhoM51vaeIAEXmr2PkucIwv7ptgyxg6zx6STxcyzMchafGee0LJL7Kcn9uE/n7Yt7ek6bDqo8jU8CtA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-table-cell@2.8.0': + resolution: {integrity: sha512-IZpxONWyOd474L8+k4bHrFNRhbsl9eRwbNs5O877JkVFItc2WUz1DIhbJzjmBRsqExtWQJuOsiqWFab1kpiwGQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-table-header@2.8.0': + resolution: {integrity: sha512-B67A96yMQlG96IFzZBc7D5dnn7O29hcjuDLtjyZkKvU5D/RlFKPMmC9nVphCV3CnbkvEOZUdK9pNaOpen64naw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-table-row@2.8.0': + resolution: {integrity: sha512-Iezej6l7X+WqKzGLmCgAwmpL+QsfjFv1g8yVH5d0/3Pkcj3G9nDn+GSm4bZnbfYFyqInHG94PZ5PMReiALrJtA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-table@2.8.0': + resolution: {integrity: sha512-dm9CitjacXyJuE5SZfV2lUc3uOiP2sxo6fygIzMz7iuxHqQueyONWG+TBkK7HjqzXOiMPsvOf/25NazzIG8HMg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-text-align@2.8.0': + resolution: {integrity: sha512-Y6s/DF+P4lxpAnvSrnmt4xGwQT/AJJJm0aA1wu5GuPKpAQ+K4C7K6rE6uGNAXtR39GlewC7KdmcvA+CYhL8xlw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-text-style@2.8.0': + resolution: {integrity: sha512-jJp0vcZ2Ty7RvIL0VU6dm1y+fTfXq1lN2GwtYzYM0ueFuESa+Qo8ticYOImyWZ3wGJGVrjn7OV9r0ReW0/NYkQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-text@2.8.0': + resolution: {integrity: sha512-EDAdFFzWOvQfVy7j3qkKhBpOeE5thkJaBemSWfXI93/gMVc0ZCdLi24mDvNNgUHlT+RjlIoQq908jZaaxLKN2A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-underline@2.8.0': + resolution: {integrity: sha512-1ouuHwZJphT8OosAmp6x8e+Wly3cUd1pNWBiOutJX+6QRGBXJnIKFCzn8YOTlWhg1YQigisG7dNF3YdlyuRNHw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-youtube@2.8.0': + resolution: {integrity: sha512-mE80+XOkvbUvWYOZnDTtftIUfZhpBJdNKRY73Fyg20GApspdpLejo1x/lhJbAFk09jyRMvnBw292Spy2JRcF0g==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/pm@2.8.0': + resolution: {integrity: sha512-eMGpRooUMvKz/vOpnKKppApMSoNM325HxTdAJvTlVAmuHp5bOY5kyY1kfUlePRiVx1t1UlFcXs3kecFwkkBD3Q==} + + '@tiptap/starter-kit@2.8.0': + resolution: {integrity: sha512-r7UwaTrECkQoheWVZKFDqtL5tBx07x7IFT+prfgnsVlYFutGWskVVqzCDvD3BDmrg5PzeCWYZrQGlPaLib7tjg==} + '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -1674,6 +1877,15 @@ packages: '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -2135,6 +2347,10 @@ packages: resolution: {integrity: sha512-N1ZfNprtf/37x0R05J0QCW/9pCAcuI+bjZIK9tlu0JEkwEST7ssdD++gxHRbD58AiG5QE5OuNYhRoEFsc1wESw==} engines: {node: '>= 12.*'} + babel-import-util@3.0.0: + resolution: {integrity: sha512-4YNPkuVsxAW5lnSTa6cn4Wk49RX6GAB6vX+M6LqEtN0YePqoFczv1/x0EyLK/o+4E1j9jEuYj5Su7IEPab5JHQ==} + engines: {node: '>= 12.*'} + babel-loader@8.3.0: resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==} engines: {node: '>= 8.9'} @@ -2259,6 +2475,10 @@ packages: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} engines: {node: '>= 0.8'} + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -2660,7 +2880,6 @@ packages: chokidar@2.1.8: resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} - deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} @@ -2813,6 +3032,9 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + common-ancestor-path@1.0.1: + resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} + common-tags@1.8.2: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} @@ -3111,6 +3333,9 @@ packages: create-hmac@1.1.7: resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cross-spawn@6.0.5: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} @@ -3227,6 +3452,9 @@ packages: resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} engines: {node: '>=4'} + decorator-transforms@2.2.2: + resolution: {integrity: sha512-NHCSJXOUQ29YFli1QzstXWo72EyASpoVx+s0YdkMwswpovf/iAJP580nD1tB0Ph9exvtbfWdVrSAloXrWVo1Xg==} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -3388,12 +3616,8 @@ packages: resolution: {integrity: sha512-gLqML2k77AuUiXxWNon1FSzuG1DV7PEPpCLCU5aJvf6fdL6rmFfElsZRh+8ELEB/qP9dT+LHjNEunVzd2dYc8A==} engines: {node: '>= 10.*'} - ember-auto-import@2.6.3: - resolution: {integrity: sha512-uLhrRDJYWCRvQ4JQ1e64XlSrqAKSd6PXaJ9ZsZI6Tlms9T4DtQFxNXasqji2ZRJBVrxEoLCRYX3RTldsQ0vNGQ==} - engines: {node: 12.* || 14.* || >= 16} - - ember-auto-import@2.7.2: - resolution: {integrity: sha512-pkWIljmJClYL17YBk8FjO7NrZPQoY9v0b+FooJvaHf/xlDQIBYVP7OaDHbNuNbpj7+wAwSDAnnwxjCoLsmm4cw==} + ember-auto-import@2.8.1: + resolution: {integrity: sha512-R5RpJmhycU6YKryzsIL/wP42r0e2PPfLRsFECoGvb1st2eEnU1Q7XyLVC1txd/XvURfu7x3Z7hKtZtYUxy61oQ==} engines: {node: 12.* || 14.* || >= 16} ember-basic-dropdown@7.3.0: @@ -3412,6 +3636,14 @@ packages: peerDependencies: ember-source: ^3.13.0 || ^4.0.0 || >= 5.0.0 + ember-can@6.0.0: + resolution: {integrity: sha512-/8TnWxU9Yu0HXCk04qCHK3nnjrNMe3j6wrJJjW9ffLsnBBHKTT8yNP1f54EsHaHoNtWd73JGSSTmtcpBHhWAyw==} + peerDependencies: + '@ember/string': ^3.1.1 || ^4.0.0 + ember-inflector: ^4.0.2 || ^5.0.1 + ember-resolver: '>= 8.0.0' + ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0 + ember-cli-babel-plugin-helpers@1.1.1: resolution: {integrity: sha512-sKvOiPNHr5F/60NLd7SFzMpYPte/nnGkq/tMIfXejfKHIhaiIkYFqX8Z9UFTKWLLn+V7NOaby6niNPZUdvKCRw==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3675,6 +3907,12 @@ packages: resolution: {integrity: sha512-uNmv1cPG/4qsac8oIf5txJ2FZ8p88LEpG4P3dNcjsJS98Y8hd0GPMFwVqpnzI78Lz7VYRGQWY4jnE4qm5R3j4g==} engines: {node: 12.* || 14.* || >= 16} + ember-gridstack@4.0.0: + resolution: {integrity: sha512-qcl3E+k7wWO7D/zqTzU4jtu6ruVYFT/SbBoqaOBZR017aBDOo3zcavU80z6w8zNYqUG6gVWSXFKNTtbE/D2wlg==} + engines: {node: 14.* || 16.* || >= 18} + peerDependencies: + ember-source: ^4.0.0 + ember-in-element-polyfill@1.0.1: resolution: {integrity: sha512-eHs+7D7PuQr8a1DPqsJTsEyo3FZ1XuH6WEZaEBPDa9s0xLlwByCNKl8hi1EbXOgvgEZNHHi9Rh0vjxyfakrlgg==} engines: {node: 10.* || >= 12} @@ -3699,6 +3937,13 @@ packages: ember-source: ^4.0.0 leaflet: '>=0.7' + ember-leaflet@5.1.3: + resolution: {integrity: sha512-7rzZePUCjapMzkE1SXsgSDQ28nG1w/WIMt80wf72UG4LIMHOGHibenk3naFllu1Np9wApCHxLB6x4ig8clt2Aw==} + engines: {node: 14.* || 16.* || >= 18} + peerDependencies: + ember-source: ^4.0.0 || ^5.0.0 + leaflet: '>=0.7' + ember-load-initializers@2.1.2: resolution: {integrity: sha512-CYR+U/wRxLbrfYN3dh+0Tb6mFaxJKfdyz+wNql6cqTrA0BBi9k6J3AaKXj273TqvEpyyXegQFFkZEiuZdYtgJw==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3909,6 +4154,10 @@ packages: resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} engines: {node: '>=0.12'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + errlop@2.2.0: resolution: {integrity: sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==} engines: {node: '>=0.8'} @@ -4437,7 +4686,7 @@ packages: resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} engines: {node: '>= 4.0'} os: [darwin] - deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 + deprecated: Upgrade to fsevents v2 to mitigate potential security issues fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} @@ -4618,6 +4867,9 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + gridstack@7.3.0: + resolution: {integrity: sha512-JKZgsHzm1ljkn1NnBZpf8j4NDOBCXTuw0m1ZC0sr6NKUh0BFWzXAONIxtX1hWGUVeKLj5l1VcmnTwCXw5ypDNw==} + growly@1.3.0: resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} @@ -5030,6 +5282,10 @@ packages: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} @@ -5251,6 +5507,9 @@ packages: linkify-it@4.0.1: resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==} + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + livereload-js@3.4.1: resolution: {integrity: sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==} @@ -5456,6 +5715,10 @@ packages: resolution: {integrity: sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==} hasBin: true + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + matcher-collection@1.1.2: resolution: {integrity: sha512-YQ/teqaOIIfUHedRam08PB3NK7Mjct6BvzRnJmpGDm8uFXpNr1sbY4yuflI5JcEs6COpYA0FpRQhSDBf1tT95g==} @@ -5475,6 +5738,9 @@ packages: mdurl@1.0.1: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -5850,6 +6116,9 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + os-browserify@0.3.0: resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} @@ -6077,6 +6346,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-entry-points@1.1.0: + resolution: {integrity: sha512-9vL2T/he5Kb97GVY+V3Ih4jCC1lF3PQGIDUJIUqKM4Q6twmhrUSAa0OFj+kb8IEs4wYzEgB6kcc4oYy21kZnQw==} + pkg-up@2.0.0: resolution: {integrity: sha512-fjAPuiws93rm7mPUu21RdBnkeZNrbfCFCwfAhPWY+rR3zG0ubpe5cEReHOw5fIbfmsxEV/g2kSxGTATY3Bpnwg==} engines: {node: '>=4'} @@ -6423,6 +6695,64 @@ packages: proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + prosemirror-changeset@2.2.1: + resolution: {integrity: sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.6.0: + resolution: {integrity: sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==} + + prosemirror-dropcursor@1.8.1: + resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} + + prosemirror-gapcursor@1.3.2: + resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} + + prosemirror-history@1.4.1: + resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==} + + prosemirror-inputrules@1.4.0: + resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==} + + prosemirror-keymap@1.2.2: + resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} + + prosemirror-markdown@1.13.1: + resolution: {integrity: sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==} + + prosemirror-menu@1.2.4: + resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} + + prosemirror-model@1.22.3: + resolution: {integrity: sha512-V4XCysitErI+i0rKFILGt/xClnFJaohe/wrrlT2NSZ+zk8ggQfDH4x2wNK7Gm0Hp4CIoWizvXFP7L9KMaCuI0Q==} + + prosemirror-schema-basic@1.2.3: + resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==} + + prosemirror-schema-list@1.4.1: + resolution: {integrity: sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==} + + prosemirror-state@1.4.3: + resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} + + prosemirror-tables@1.5.0: + resolution: {integrity: sha512-VMx4zlYWm7aBlZ5xtfJHpqa3Xgu3b7srV54fXYnXgsAcIGRqKSrhiK3f89omzzgaAgAtDOV4ImXnLKhVfheVNQ==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.10.0: + resolution: {integrity: sha512-9UOgFSgN6Gj2ekQH5CTDJ8Rp/fnKR2IkYfGdzzp5zQMFsS4zDllLVx/+jGcX86YlACpG7UR5fwAXiWzxqWtBTg==} + + prosemirror-view@1.34.3: + resolution: {integrity: sha512-mKZ54PrX19sSaQye+sef+YjBbNu2voNwLS1ivb6aD2IRmxRGW64HU9B644+7OfJStGLyxvOreKqEgfvXa91WIA==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -6442,6 +6772,10 @@ packages: pumpify@1.5.1: resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@1.4.1: resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} @@ -6716,6 +7050,9 @@ packages: engines: {node: '>=10.0.0'} hasBin: true + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + route-recognizer@0.3.4: resolution: {integrity: sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g==} @@ -7487,6 +7824,9 @@ packages: uc.micro@1.0.6: resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + uglify-js@3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} engines: {node: '>=0.8.0'} @@ -7625,6 +7965,9 @@ packages: vm-browserify@1.1.2: resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + walk-sync@0.2.7: resolution: {integrity: sha512-OH8GdRMowEFr0XSHQeX5fGweO6zSVHo7bG/0yJQx6LAj9Oukz0C8heI3/FYectT66gY0IPGe89kOvU410/UNpg==} @@ -8665,22 +9008,22 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@csstools/cascade-layer-name-parser@1.0.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3)': + '@csstools/cascade-layer-name-parser@1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': dependencies: '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/color-helpers@4.0.0': {} - '@csstools/css-calc@1.1.6(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3)': + '@csstools/css-calc@1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': dependencies: '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 - '@csstools/css-color-parser@1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3)': + '@csstools/css-color-parser@1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': dependencies: '@csstools/color-helpers': 4.0.0 - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 @@ -8690,7 +9033,7 @@ snapshots: '@csstools/css-tokenizer@2.2.3': {} - '@csstools/media-query-list-parser@2.1.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3)': + '@csstools/media-query-list-parser@2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': dependencies: '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 @@ -8703,7 +9046,7 @@ snapshots: '@csstools/postcss-color-function@3.0.9(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) @@ -8711,7 +9054,7 @@ snapshots: '@csstools/postcss-color-mix-function@2.0.9(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) @@ -8719,7 +9062,7 @@ snapshots: '@csstools/postcss-exponential-functions@1.0.3(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 postcss: 8.4.35 @@ -8731,14 +9074,14 @@ snapshots: '@csstools/postcss-gamut-mapping@1.0.2(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 postcss: 8.4.35 '@csstools/postcss-gradients-interpolation-method@4.0.9(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) @@ -8746,7 +9089,7 @@ snapshots: '@csstools/postcss-hwb-function@3.0.8(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 postcss: 8.4.35 @@ -8791,17 +9134,17 @@ snapshots: '@csstools/postcss-media-minmax@1.1.2(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 - '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) postcss: 8.4.35 '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.5(postcss@8.4.35)': dependencies: '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 - '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) postcss: 8.4.35 '@csstools/postcss-nested-calc@3.0.1(postcss@8.4.35)': @@ -8816,7 +9159,7 @@ snapshots: '@csstools/postcss-oklab-function@3.0.9(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) @@ -8829,7 +9172,7 @@ snapshots: '@csstools/postcss-relative-color-syntax@2.0.9(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) @@ -8842,7 +9185,7 @@ snapshots: '@csstools/postcss-stepped-value-functions@3.0.4(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 postcss: 8.4.35 @@ -8855,7 +9198,7 @@ snapshots: '@csstools/postcss-trigonometric-functions@3.0.4(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 postcss: 8.4.35 @@ -8868,10 +9211,10 @@ snapshots: dependencies: postcss-selector-parser: 6.0.15 - '@ember-data/adapter@4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)': + '@ember-data/adapter@4.12.5(@ember-data/store@4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(@ember/string@3.1.1)(ember-inflector@4.0.2)': dependencies: '@ember-data/private-build-infra': 4.12.5 - '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0) + '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/string': 3.1.1 '@embroider/macros': 1.13.5 ember-cli-babel: 7.26.11 @@ -8884,11 +9227,11 @@ snapshots: '@ember-data/debug@4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(webpack@5.89.0)': dependencies: '@ember-data/private-build-infra': 4.12.5 - '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0) + '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/edition-utils': 1.2.0 '@ember/string': 3.1.1 '@embroider/macros': 1.13.5 - ember-auto-import: 2.7.2(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 transitivePeerDependencies: - '@glint/template' @@ -8898,7 +9241,7 @@ snapshots: '@ember-data/graph@4.12.5(@ember-data/store@4.12.5)': dependencies: '@ember-data/private-build-infra': 4.12.5 - '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0) + '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/edition-utils': 1.2.0 '@embroider/macros': 1.13.5 ember-cli-babel: 7.26.11 @@ -8910,7 +9253,7 @@ snapshots: dependencies: '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) '@ember-data/private-build-infra': 4.12.5 - '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0) + '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/edition-utils': 1.2.0 '@embroider/macros': 1.13.5 ember-cli-babel: 7.26.11 @@ -8920,33 +9263,35 @@ snapshots: '@ember-data/legacy-compat@4.12.5(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)': dependencies: - '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) - '@ember-data/json-api': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/store@4.12.5) '@ember-data/private-build-infra': 4.12.5 '@embroider/macros': 1.13.5 ember-cli-babel: 7.26.11 + optionalDependencies: + '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) + '@ember-data/json-api': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/store@4.12.5) transitivePeerDependencies: - '@glint/template' - supports-color - '@ember-data/model@4.12.5(@babel/core@7.23.2)(@ember-data/debug@4.12.5)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/store@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-source@5.4.0)': + '@ember-data/model@4.12.5(@babel/core@7.23.2)(@ember-data/debug@4.12.5)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/store@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': dependencies: - '@ember-data/debug': 4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(webpack@5.89.0) - '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) - '@ember-data/json-api': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/store@4.12.5) '@ember-data/legacy-compat': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5) '@ember-data/private-build-infra': 4.12.5 - '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0) + '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember-data/tracking': 4.12.5 '@ember/edition-utils': 1.2.0 '@ember/string': 3.1.1 '@embroider/macros': 1.13.5 - ember-cached-decorator-polyfill: 1.0.2(@babel/core@7.23.2)(ember-source@5.4.0) + ember-cached-decorator-polyfill: 1.0.2(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 7.26.11 ember-cli-string-utils: 1.1.0 ember-cli-test-info: 1.0.0 ember-inflector: 4.0.2 inflection: 2.0.1 + optionalDependencies: + '@ember-data/debug': 4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(webpack@5.89.0) + '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) + '@ember-data/json-api': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/store@4.12.5) transitivePeerDependencies: - '@babel/core' - '@glint/template' @@ -8996,10 +9341,10 @@ snapshots: '@ember-data/rfc395-data@0.0.4': {} - '@ember-data/serializer@4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)': + '@ember-data/serializer@4.12.5(@ember-data/store@4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(@ember/string@3.1.1)(ember-inflector@4.0.2)': dependencies: '@ember-data/private-build-infra': 4.12.5 - '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0) + '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/string': 3.1.1 '@embroider/macros': 1.13.5 ember-cli-babel: 7.26.11 @@ -9009,19 +9354,20 @@ snapshots: - '@glint/template' - supports-color - '@ember-data/store@4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)': + '@ember-data/store@4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': dependencies: - '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) - '@ember-data/json-api': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/store@4.12.5) - '@ember-data/legacy-compat': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5) - '@ember-data/model': 4.12.5(@babel/core@7.23.2)(@ember-data/debug@4.12.5)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/store@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-source@5.4.0) '@ember-data/private-build-infra': 4.12.5 '@ember-data/tracking': 4.12.5 '@ember/string': 3.1.1 '@embroider/macros': 1.13.5 '@glimmer/tracking': 1.1.2 - ember-cached-decorator-polyfill: 1.0.2(@babel/core@7.23.2)(ember-source@5.4.0) + ember-cached-decorator-polyfill: 1.0.2(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 7.26.11 + optionalDependencies: + '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) + '@ember-data/json-api': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/store@4.12.5) + '@ember-data/legacy-compat': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5) + '@ember-data/model': 4.12.5(@babel/core@7.23.2)(@ember-data/debug@4.12.5)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/store@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) transitivePeerDependencies: - '@babel/core' - '@glint/template' @@ -9070,12 +9416,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@ember/render-modifiers@2.1.0(@babel/core@7.23.2)(ember-source@5.4.0)': + '@ember/render-modifiers@2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': dependencies: '@embroider/macros': 1.13.5 ember-cli-babel: 7.26.11 ember-modifier-manager-polyfill: 1.2.0(@babel/core@7.23.2) - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@babel/core' - supports-color @@ -9086,17 +9432,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@ember/test-helpers@3.2.0(ember-source@5.4.0)(webpack@5.89.0)': + '@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)': dependencies: '@ember/test-waiters': 3.1.0 '@embroider/macros': 1.13.5 '@simple-dom/interface': 1.4.0 broccoli-debug: 0.6.5 broccoli-funnel: 3.0.8 - ember-auto-import: 2.6.3(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@glint/template' - supports-color @@ -9124,6 +9470,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@embroider/addon-shim@1.8.9': + dependencies: + '@embroider/shared-internals': 2.7.0 + broccoli-funnel: 3.0.8 + common-ancestor-path: 1.0.1 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + '@embroider/addon@0.30.0': dependencies: ember-cli-babel: 7.26.11 @@ -9168,17 +9523,32 @@ snapshots: transitivePeerDependencies: - supports-color + '@embroider/shared-internals@2.7.0': + dependencies: + babel-import-util: 2.0.1 + debug: 4.3.4 + ember-rfc176-data: 0.3.18 + fs-extra: 9.1.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + minimatch: 3.1.2 + resolve-package-path: 4.0.3 + semver: 7.6.0 + typescript-memoize: 1.1.1 + transitivePeerDependencies: + - supports-color + '@embroider/test-setup@3.0.2': dependencies: lodash: 4.17.21 resolve: 1.22.8 - '@embroider/util@1.12.1(ember-source@5.4.0)': + '@embroider/util@1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': dependencies: '@embroider/macros': 1.13.5 broccoli-funnel: 3.0.8 ember-cli-babel: 7.26.11 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -9205,25 +9575,26 @@ snapshots: '@eslint/js@8.52.0': {} - '@fleetbase/ember-accounting@0.0.1(ember-source@5.4.0)': + '@fleetbase/ember-accounting@0.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': dependencies: '@babel/core': 7.23.2 ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color - '@fleetbase/ember-core@0.2.13(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0)': + '@fleetbase/ember-core@0.2.19(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)': dependencies: '@babel/core': 7.23.2 compress-json: 3.1.0 date-fns: 2.30.0 - ember-auto-import: 2.7.2(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) + ember-can: 6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 ember-cli-notifications: 9.0.0 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0) + ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-concurrency-decorators: 2.0.3(@babel/core@7.23.2) ember-decorators: 6.1.1 ember-get-config: 2.1.1 @@ -9231,29 +9602,31 @@ snapshots: ember-intl: 6.3.2(@babel/core@7.23.2)(webpack@5.89.0) ember-loading: 2.0.0(@babel/core@7.23.2) ember-local-storage: 2.0.7(@babel/core@7.23.2) - ember-simple-auth: 6.0.0(@ember/test-helpers@3.2.0) + ember-simple-auth: 6.0.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)) ember-wormhole: 0.6.0 socketcluster-client: 17.2.2 transitivePeerDependencies: + - '@ember/string' - '@ember/test-helpers' - '@glint/template' - bufferutil + - ember-resolver - ember-source - supports-color - typescript - utf-8-validate - webpack - '@fleetbase/ember-ui@0.2.19(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(postcss@8.4.35)(tracked-built-ins@3.3.0)(webpack@5.89.0)': + '@fleetbase/ember-ui@0.2.32(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(postcss@8.4.35)(rollup@2.79.1)(tracked-built-ins@3.3.0)(webpack@5.89.0)': dependencies: '@babel/core': 7.23.2 - '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0) + '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/string': 3.1.1 '@embroider/addon': 0.30.0 '@embroider/macros': 1.13.5 - '@fleetbase/ember-accounting': 0.0.1(ember-source@5.4.0) + '@fleetbase/ember-accounting': 0.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@floating-ui/dom': 1.6.3 - '@fortawesome/ember-fontawesome': 2.0.0(ember-source@5.4.0)(webpack@5.89.0) + '@fortawesome/ember-fontawesome': 2.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0) '@fortawesome/fontawesome-svg-core': 6.4.0 '@fortawesome/free-brands-svg-icons': 6.4.0 '@fortawesome/free-solid-svg-icons': 6.4.0 @@ -9262,43 +9635,64 @@ snapshots: '@fullcalendar/interaction': 6.1.10(@fullcalendar/core@6.1.10) '@makepanic/ember-power-calendar-date-fns': 0.4.2 '@tailwindcss/forms': 0.5.7(tailwindcss@3.4.1) + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/extension-color': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) + '@tiptap/extension-font-family': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) + '@tiptap/extension-highlight': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-image': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-placeholder': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) + '@tiptap/extension-subscript': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-superscript': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-table': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) + '@tiptap/extension-table-cell': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-table-header': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-table-row': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-text-align': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-underline': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-youtube': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/pm': 2.8.0 + '@tiptap/starter-kit': 2.8.0(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) air-datepicker: 3.4.0 autonumeric: 4.10.5 autoprefixer: 10.4.17(postcss@8.4.35) - broccoli-funnel: 3.0.8 - broccoli-merge-trees: 4.2.0 chart.js: 4.4.1 chartjs-adapter-date-fns: 3.0.0(chart.js@4.4.1)(date-fns@2.30.0) date-fns: 2.30.0 - ember-animated: 1.1.4(@ember/test-helpers@3.2.0)(ember-source@5.4.0) - ember-auto-import: 2.7.2(webpack@5.89.0) - ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0) + ember-animated: 1.1.4(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-auto-import: 2.8.1(webpack@5.89.0) + ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-can: 6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 ember-cli-postcss: 8.2.0 ember-cli-string-helpers: 6.1.0 ember-composable-helpers: 5.0.0 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0) + ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-concurrency-decorators: 2.0.3(@babel/core@7.23.2) - ember-concurrency-test-waiter: 0.4.0(ember-concurrency@3.1.1) - ember-file-upload: 8.4.0(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-modifier@4.1.0)(tracked-built-ins@3.3.0)(webpack@5.89.0) - ember-focus-trap: 1.1.0(ember-source@5.4.0) + ember-concurrency-test-waiter: 0.4.0(ember-concurrency@3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))) + ember-file-upload: 8.4.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-modifier@4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(tracked-built-ins@3.3.0)(webpack@5.89.0) + ember-focus-trap: 1.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-get-config: 2.1.1 + ember-gridstack: 4.0.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) ember-inflector: 4.0.2 + ember-leaflet: 5.1.3(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(leaflet@1.9.4)(webpack@5.89.0) ember-loading: 2.0.0(@babel/core@7.23.2) - ember-math-helpers: 4.0.0(ember-source@5.4.0) - ember-modifier: 4.1.0(ember-source@5.4.0) + ember-math-helpers: 4.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-on-helper: 0.1.0 - ember-power-calendar: 0.18.0(@babel/core@7.23.2)(ember-source@5.4.0) - ember-power-select: 7.2.0(@babel/core@7.23.2)(ember-source@5.4.0)(webpack@5.89.0) + ember-power-calendar: 0.18.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-power-select: 7.2.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) ember-ref-bucket: 4.1.0(@babel/core@7.23.2) ember-responsive: 5.0.0 - ember-style-modifier: 3.1.1(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0) - ember-truth-helpers: 4.0.3(ember-source@5.4.0) - ember-window-mock: 0.9.0(ember-source@5.4.0) + ember-style-modifier: 3.1.1(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-truth-helpers: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-window-mock: 0.9.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-wormhole: 0.6.0 + gridstack: 7.3.0 imask: 6.6.3 intl-tel-input: 22.0.2 + leaflet: 1.9.4 postcss-at-rules-variables: 0.3.0(postcss@8.4.35) postcss-conditionals-renewed: 1.0.0(postcss@8.4.35) postcss-each: 1.1.0(postcss@8.4.35) @@ -9313,6 +9707,7 @@ snapshots: - '@glint/environment-ember-loose' - '@glint/template' - ember-cli-mirage + - ember-resolver - ember-source - miragejs - postcss @@ -9324,17 +9719,19 @@ snapshots: - webpack-cli - webpack-command - '@fleetbase/fleetops-data@0.1.17(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0)': + '@fleetbase/fleetops-data@0.1.18(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)': dependencies: '@babel/core': 7.23.2 - '@fleetbase/ember-core': 0.2.13(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0) + '@fleetbase/ember-core': 0.2.19(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) date-fns: 2.30.0 ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 transitivePeerDependencies: + - '@ember/string' - '@ember/test-helpers' - '@glint/template' - bufferutil + - ember-resolver - ember-source - supports-color - typescript @@ -9398,10 +9795,10 @@ snapshots: intl-messageformat: 10.5.11 tslib: 2.6.2 - '@fortawesome/ember-fontawesome@2.0.0(ember-source@5.4.0)(webpack@5.89.0)': + '@fortawesome/ember-fontawesome@2.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0)': dependencies: '@fortawesome/fontawesome-svg-core': 6.4.0 - '@rollup/plugin-node-resolve': 15.2.3 + '@rollup/plugin-node-resolve': 15.2.3(rollup@2.79.1) array-unique: 0.3.2 broccoli-file-creator: 2.1.1 broccoli-merge-trees: 4.2.0 @@ -9410,11 +9807,11 @@ snapshots: broccoli-source: 3.0.1 camel-case: 4.1.2 ember-ast-helpers: 0.4.0 - ember-auto-import: 2.7.2(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 ember-get-config: 2.1.1 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) find-yarn-workspace-root: 2.0.0 glob: 10.3.10 transitivePeerDependencies: @@ -9725,20 +10122,26 @@ snapshots: '@pnpm/error': 5.0.2 find-up: 5.0.0 - '@rollup/plugin-node-resolve@15.2.3': + '@remirror/core-constants@3.0.0': {} + + '@rollup/plugin-node-resolve@15.2.3(rollup@2.79.1)': dependencies: - '@rollup/pluginutils': 5.1.0 + '@rollup/pluginutils': 5.1.0(rollup@2.79.1) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-builtin-module: 3.2.1 is-module: 1.0.0 resolve: 1.22.8 + optionalDependencies: + rollup: 2.79.1 - '@rollup/pluginutils@5.1.0': + '@rollup/pluginutils@5.1.0(rollup@2.79.1)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 + optionalDependencies: + rollup: 2.79.1 '@simple-dom/document@1.4.0': dependencies: @@ -9759,6 +10162,201 @@ snapshots: mini-svg-data-uri: 1.4.4 tailwindcss: 3.4.1 + '@tiptap/core@2.8.0(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-blockquote@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-bold@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-bullet-list@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/extension-list-item': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + + '@tiptap/extension-code-block@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-code@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-color@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + + '@tiptap/extension-document@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-dropcursor@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-font-family@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + + '@tiptap/extension-gapcursor@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-hard-break@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-heading@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-highlight@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-history@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-horizontal-rule@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-image@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-italic@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-ordered-list@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/extension-list-item': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + + '@tiptap/extension-paragraph@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-placeholder@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-strike@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-subscript@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-superscript@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-table-cell@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-table-header@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-table-row@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-table@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/pm': 2.8.0 + + '@tiptap/extension-text-align@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-text@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-underline@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/extension-youtube@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + + '@tiptap/pm@2.8.0': + dependencies: + prosemirror-changeset: 2.2.1 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.6.0 + prosemirror-dropcursor: 1.8.1 + prosemirror-gapcursor: 1.3.2 + prosemirror-history: 1.4.1 + prosemirror-inputrules: 1.4.0 + prosemirror-keymap: 1.2.2 + prosemirror-markdown: 1.13.1 + prosemirror-menu: 1.2.4 + prosemirror-model: 1.22.3 + prosemirror-schema-basic: 1.2.3 + prosemirror-schema-list: 1.4.1 + prosemirror-state: 1.4.3 + prosemirror-tables: 1.5.0 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.34.3) + prosemirror-transform: 1.10.0 + prosemirror-view: 1.34.3 + + '@tiptap/starter-kit@2.8.0(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + dependencies: + '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/extension-blockquote': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-bold': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-bullet-list': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) + '@tiptap/extension-code': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-code-block': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) + '@tiptap/extension-document': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-dropcursor': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) + '@tiptap/extension-gapcursor': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) + '@tiptap/extension-hard-break': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-heading': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-history': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) + '@tiptap/extension-horizontal-rule': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) + '@tiptap/extension-italic': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-list-item': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-ordered-list': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) + '@tiptap/extension-paragraph': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-strike': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/extension-text': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/pm': 2.8.0 + transitivePeerDependencies: + - '@tiptap/extension-text-style' + '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 @@ -9838,6 +10436,15 @@ snapshots: dependencies: '@types/node': 20.11.19 + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + '@types/mime@1.3.5': {} '@types/mime@3.0.4': {} @@ -10093,7 +10700,7 @@ snapshots: ajv: 6.12.6 ajv-formats@2.1.1(ajv@8.12.0): - dependencies: + optionalDependencies: ajv: 8.12.0 ajv-keywords@3.5.2(ajv@6.12.6): @@ -10375,6 +10982,8 @@ snapshots: babel-import-util@2.0.1: {} + babel-import-util@3.0.0: {} + babel-loader@8.3.0(@babel/core@7.23.2)(webpack@4.47.0): dependencies: '@babel/core': 7.23.2 @@ -10559,6 +11168,10 @@ snapshots: dependencies: safe-buffer: 5.1.2 + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + big.js@5.2.2: {} binary-extensions@1.13.1: @@ -11543,6 +12156,8 @@ snapshots: commander@8.3.0: {} + common-ancestor-path@1.0.1: {} + common-tags@1.8.2: {} commondir@1.0.1: {} @@ -11618,10 +12233,15 @@ snapshots: ora: 3.4.0 through2: 3.0.2 - consolidate@0.16.0(mustache@4.2.0): + consolidate@0.16.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(mustache@4.2.0)(underscore@1.13.6): dependencies: bluebird: 3.7.2 + optionalDependencies: + babel-core: 6.26.3 + handlebars: 4.7.8 + lodash: 4.17.21 mustache: 4.2.0 + underscore: 1.13.6 constants-browserify@1.0.0: {} @@ -11704,6 +12324,8 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 + crelt@1.0.6: {} + cross-spawn@6.0.5: dependencies: nice-try: 1.0.5 @@ -11818,6 +12440,13 @@ snapshots: dependencies: mimic-response: 1.0.1 + decorator-transforms@2.2.2(@babel/core@7.23.2): + dependencies: + '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.23.2) + babel-import-util: 3.0.0 + transitivePeerDependencies: + - '@babel/core' + deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -11945,14 +12574,15 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - ember-animated@1.1.4(@ember/test-helpers@3.2.0)(ember-source@5.4.0): + ember-animated@1.1.4(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: - '@ember/test-helpers': 3.2.0(ember-source@5.4.0)(webpack@5.89.0) '@embroider/addon-shim': 1.8.7 '@embroider/macros': 1.13.5 - '@embroider/util': 1.12.1(ember-source@5.4.0) + '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) assert-never: 1.2.1 - ember-element-helper: 0.8.5(ember-source@5.4.0) + ember-element-helper: 0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + optionalDependencies: + '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) transitivePeerDependencies: - '@glint/environment-ember-loose' - '@glint/template' @@ -12015,45 +12645,7 @@ snapshots: - webpack-cli - webpack-command - ember-auto-import@2.6.3(webpack@5.89.0): - dependencies: - '@babel/core': 7.23.2 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.2) - '@babel/plugin-proposal-decorators': 7.23.2(@babel/core@7.23.2) - '@babel/preset-env': 7.23.9(@babel/core@7.23.2) - '@embroider/macros': 1.13.5 - '@embroider/shared-internals': 2.5.2 - babel-loader: 8.3.0(@babel/core@7.23.2)(webpack@5.89.0) - babel-plugin-ember-modules-api-polyfill: 3.5.0 - babel-plugin-ember-template-compilation: 2.2.1 - babel-plugin-htmlbars-inline-precompile: 5.3.1 - babel-plugin-syntax-dynamic-import: 6.18.0 - broccoli-debug: 0.6.5 - broccoli-funnel: 3.0.8 - broccoli-merge-trees: 4.2.0 - broccoli-plugin: 4.0.7 - broccoli-source: 3.0.1 - css-loader: 5.2.7(webpack@5.89.0) - debug: 4.3.4 - fs-extra: 10.1.0 - fs-tree-diff: 2.0.1 - handlebars: 4.7.8 - js-string-escape: 1.0.1 - lodash: 4.17.21 - mini-css-extract-plugin: 2.8.0(webpack@5.89.0) - parse5: 6.0.1 - resolve: 1.22.8 - resolve-package-path: 4.0.3 - semver: 7.6.0 - style-loader: 2.0.0(webpack@5.89.0) - typescript-memoize: 1.1.1 - walk-sync: 3.0.0 - transitivePeerDependencies: - - '@glint/template' - - supports-color - - webpack - - ember-auto-import@2.7.2(webpack@5.89.0): + ember-auto-import@2.8.1(webpack@5.89.0): dependencies: '@babel/core': 7.23.2 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.2) @@ -12078,11 +12670,13 @@ snapshots: fs-extra: 10.1.0 fs-tree-diff: 2.0.1 handlebars: 4.7.8 + is-subdir: 1.2.0 js-string-escape: 1.0.1 lodash: 4.17.21 mini-css-extract-plugin: 2.8.0(webpack@5.89.0) minimatch: 3.1.2 parse5: 6.0.1 + pkg-entry-points: 1.1.0 resolve: 1.22.8 resolve-package-path: 4.0.3 semver: 7.6.0 @@ -12094,23 +12688,23 @@ snapshots: - supports-color - webpack - ember-basic-dropdown@7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0): + ember-basic-dropdown@7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): dependencies: '@embroider/macros': 1.13.5 - '@embroider/util': 1.12.1(ember-source@5.4.0) + '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@glimmer/component': 1.1.2(@babel/core@7.23.2) '@glimmer/tracking': 1.1.2 - ember-auto-import: 2.7.2(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 ember-cli-typescript: 5.2.1 - ember-element-helper: 0.8.5(ember-source@5.4.0) + ember-element-helper: 0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-get-config: 2.1.1 ember-maybe-in-element: 2.1.0 - ember-modifier: 4.1.0(ember-source@5.4.0) - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) - ember-style-modifier: 3.1.1(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0) - ember-truth-helpers: 4.0.3(ember-source@5.4.0) + ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + ember-style-modifier: 3.1.1(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-truth-helpers: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) transitivePeerDependencies: - '@babel/core' - '@ember/string' @@ -12129,7 +12723,7 @@ snapshots: - '@babel/core' - supports-color - ember-cached-decorator-polyfill@1.0.2(@babel/core@7.23.2)(ember-source@5.4.0): + ember-cached-decorator-polyfill@1.0.2(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/macros': 1.13.5 '@glimmer/tracking': 1.1.2 @@ -12137,12 +12731,24 @@ snapshots: ember-cache-primitive-polyfill: 1.0.1(@babel/core@7.23.2) ember-cli-babel: 7.26.11 ember-cli-babel-plugin-helpers: 1.1.1 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@babel/core' - '@glint/template' - supports-color + ember-can@6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + dependencies: + '@ember/string': 3.1.1 + '@embroider/addon-shim': 1.8.9 + decorator-transforms: 2.2.2(@babel/core@7.23.2) + ember-inflector: 4.0.2 + ember-resolver: 11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + transitivePeerDependencies: + - '@babel/core' + - supports-color + ember-cli-babel-plugin-helpers@1.1.1: {} ember-cli-babel@7.26.11: @@ -12221,10 +12827,10 @@ snapshots: transitivePeerDependencies: - supports-color - ember-cli-dependency-checker@3.3.2(ember-cli@5.4.1): + ember-cli-dependency-checker@3.3.2(ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6)): dependencies: chalk: 2.4.2 - ember-cli: 5.4.1 + ember-cli: 5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6) find-yarn-workspace-root: 1.2.1 is-git-url: 1.0.0 resolve: 1.22.8 @@ -12503,7 +13109,7 @@ snapshots: transitivePeerDependencies: - supports-color - ember-cli@5.4.1: + ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6): dependencies: '@pnpm/find-workspace-dir': 6.0.2 broccoli: 3.5.2 @@ -12581,7 +13187,7 @@ snapshots: sort-package-json: 1.57.0 symlink-or-copy: 1.3.1 temp: 0.9.4 - testem: 3.11.0 + testem: 3.11.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6) tiny-lr: 2.0.0 tree-sync: 2.1.0 walk-sync: 3.0.0 @@ -12657,16 +13263,16 @@ snapshots: - '@babel/core' - supports-color - ember-composability-tools@1.2.0(ember-source@5.4.0)(webpack@5.89.0): + ember-composability-tools@1.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): dependencies: '@babel/core': 7.23.2 - '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0) + '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@glimmer/component': 1.1.2(@babel/core@7.23.2) - ember-auto-import: 2.7.2(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 - ember-element-helper: 0.8.5(ember-source@5.4.0) - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-element-helper: 0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@glint/environment-ember-loose' - '@glint/template' @@ -12682,7 +13288,7 @@ snapshots: transitivePeerDependencies: - supports-color - ember-concurrency-async@1.0.0(ember-concurrency@2.3.7): + ember-concurrency-async@1.0.0(ember-concurrency@2.3.7(@babel/core@7.23.2)): dependencies: '@babel/helper-plugin-utils': 7.22.5 '@babel/types': 7.23.9 @@ -12703,14 +13309,14 @@ snapshots: - '@babel/core' - supports-color - ember-concurrency-test-waiter@0.4.0(ember-concurrency@3.1.1): + ember-concurrency-test-waiter@0.4.0(ember-concurrency@3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))): dependencies: ember-cli-babel: 7.26.11 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0) + ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) transitivePeerDependencies: - supports-color - ember-concurrency-ts@0.3.1(ember-concurrency@2.3.7): + ember-concurrency-ts@0.3.1(ember-concurrency@2.3.7(@babel/core@7.23.2)): dependencies: ember-cli-babel: 7.26.11 ember-cli-htmlbars: 4.5.0 @@ -12732,7 +13338,7 @@ snapshots: - '@babel/core' - supports-color - ember-concurrency@3.1.1(@babel/core@7.23.2)(ember-source@5.4.0): + ember-concurrency@3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@babel/helper-plugin-utils': 7.22.5 '@babel/types': 7.23.9 @@ -12741,7 +13347,7 @@ snapshots: ember-cli-babel-plugin-helpers: 1.1.1 ember-cli-htmlbars: 6.3.0 ember-compatibility-helpers: 1.2.7(@babel/core@7.23.2) - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@babel/core' - supports-color @@ -12758,25 +13364,25 @@ snapshots: transitivePeerDependencies: - supports-color - ember-data@4.12.5(@babel/core@7.23.2)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(webpack@5.89.0): + ember-data@4.12.5(@babel/core@7.23.2)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): dependencies: - '@ember-data/adapter': 4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2) + '@ember-data/adapter': 4.12.5(@ember-data/store@4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(@ember/string@3.1.1)(ember-inflector@4.0.2) '@ember-data/debug': 4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(webpack@5.89.0) '@ember-data/graph': 4.12.5(@ember-data/store@4.12.5) '@ember-data/json-api': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/store@4.12.5) '@ember-data/legacy-compat': 4.12.5(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5) - '@ember-data/model': 4.12.5(@babel/core@7.23.2)(@ember-data/debug@4.12.5)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/store@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-source@5.4.0) + '@ember-data/model': 4.12.5(@babel/core@7.23.2)(@ember-data/debug@4.12.5)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/store@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember-data/private-build-infra': 4.12.5 '@ember-data/request': 4.12.5 - '@ember-data/serializer': 4.12.5(@ember-data/store@4.12.5)(@ember/string@3.1.1)(ember-inflector@4.0.2) - '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0) + '@ember-data/serializer': 4.12.5(@ember-data/store@4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(@ember/string@3.1.1)(ember-inflector@4.0.2) + '@ember-data/store': 4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember-data/tracking': 4.12.5 '@ember/edition-utils': 1.2.0 '@ember/string': 3.1.1 '@embroider/macros': 1.13.5 '@glimmer/env': 0.1.7 broccoli-merge-trees: 4.2.0 - ember-auto-import: 2.6.3(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-inflector: 4.0.2 transitivePeerDependencies: @@ -12804,28 +13410,28 @@ snapshots: - '@babel/core' - supports-color - ember-element-helper@0.6.1(ember-source@5.4.0): + ember-element-helper@0.6.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: - '@embroider/util': 1.12.1(ember-source@5.4.0) + '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@glint/environment-ember-loose' - '@glint/template' - supports-color - ember-element-helper@0.8.5(ember-source@5.4.0): + ember-element-helper@0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/addon-shim': 1.8.3 - '@embroider/util': 1.12.1(ember-source@5.4.0) - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@glint/environment-ember-loose' - '@glint/template' - supports-color - ember-engines@0.9.0(ember-source@5.4.0): + ember-engines@0.9.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/macros': 1.13.5 amd-name-resolver: 1.3.1 @@ -12843,42 +13449,42 @@ snapshots: ember-cli-preprocess-registry: 3.3.0 ember-cli-string-utils: 1.1.0 ember-cli-version-checker: 5.1.2 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) lodash: 4.17.21 transitivePeerDependencies: - '@glint/template' - supports-color - ember-file-upload@8.4.0(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-modifier@4.1.0)(tracked-built-ins@3.3.0)(webpack@5.89.0): + ember-file-upload@8.4.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-modifier@4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(tracked-built-ins@3.3.0)(webpack@5.89.0): dependencies: - '@ember/test-helpers': 3.2.0(ember-source@5.4.0)(webpack@5.89.0) + '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) '@ember/test-waiters': 3.1.0 '@embroider/addon-shim': 1.8.7 '@embroider/macros': 1.13.5 '@glimmer/component': 1.1.2(@babel/core@7.23.2) '@glimmer/tracking': 1.1.2 - ember-auto-import: 2.7.2(webpack@5.89.0) - ember-modifier: 4.1.0(ember-source@5.4.0) + ember-auto-import: 2.8.1(webpack@5.89.0) + ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) tracked-built-ins: 3.3.0 transitivePeerDependencies: - '@glint/template' - supports-color - webpack - ember-focus-trap@1.1.0(ember-source@5.4.0): + ember-focus-trap@1.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/addon-shim': 1.8.7 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) focus-trap: 6.9.4 transitivePeerDependencies: - supports-color - ember-functions-as-helper-polyfill@2.1.2(ember-source@5.4.0): + ember-functions-as-helper-polyfill@2.1.2(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: ember-cli-babel: 7.26.11 ember-cli-typescript: 5.2.1 ember-cli-version-checker: 5.1.2 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -12890,6 +13496,21 @@ snapshots: - '@glint/template' - supports-color + ember-gridstack@4.0.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): + dependencies: + '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-auto-import: 2.8.1(webpack@5.89.0) + ember-cli-babel: 7.26.11 + ember-cli-htmlbars: 6.3.0 + ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + gridstack: 7.3.0 + transitivePeerDependencies: + - '@babel/core' + - '@glint/template' + - supports-color + - webpack + ember-in-element-polyfill@1.0.1: dependencies: debug: 4.3.4 @@ -12917,7 +13538,7 @@ snapshots: broccoli-stew: 3.0.0 calculate-cache-key-for-tree: 2.0.0 cldr-core: 44.1.0 - ember-auto-import: 2.7.2(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-typescript: 5.2.1 eventemitter3: 5.0.1 @@ -12933,7 +13554,7 @@ snapshots: - supports-color - webpack - ember-leaflet@5.1.1(@babel/core@7.23.2)(ember-source@5.4.0)(leaflet@1.9.4)(webpack@5.89.0): + ember-leaflet@5.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(leaflet@1.9.4)(webpack@5.89.0): dependencies: '@glimmer/component': 1.1.2(@babel/core@7.23.2) '@glimmer/tracking': 1.1.2 @@ -12941,10 +13562,32 @@ snapshots: broccoli-merge-trees: 4.2.0 ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 - ember-composability-tools: 1.2.0(ember-source@5.4.0)(webpack@5.89.0) + ember-composability-tools: 1.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) ember-in-element-polyfill: 1.0.1 ember-render-helpers: 0.2.0 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + fastboot-transform: 0.1.3 + leaflet: 1.9.4 + resolve: 1.22.8 + transitivePeerDependencies: + - '@babel/core' + - '@glint/environment-ember-loose' + - '@glint/template' + - supports-color + - webpack + + ember-leaflet@5.1.3(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(leaflet@1.9.4)(webpack@5.89.0): + dependencies: + '@glimmer/component': 1.1.2(@babel/core@7.23.2) + '@glimmer/tracking': 1.1.2 + broccoli-funnel: 3.0.8 + broccoli-merge-trees: 4.2.0 + ember-cli-babel: 7.26.11 + ember-cli-htmlbars: 6.3.0 + ember-composability-tools: 1.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-in-element-polyfill: 1.0.1 + ember-render-helpers: 0.2.0 + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) fastboot-transform: 0.1.3 leaflet: 1.9.4 resolve: 1.22.8 @@ -12969,8 +13612,8 @@ snapshots: ember-cli-htmlbars: 5.7.2 ember-cli-typescript: 4.2.1 ember-concurrency: 2.3.7(@babel/core@7.23.2) - ember-concurrency-async: 1.0.0(ember-concurrency@2.3.7) - ember-concurrency-ts: 0.3.1(ember-concurrency@2.3.7) + ember-concurrency-async: 1.0.0(ember-concurrency@2.3.7(@babel/core@7.23.2)) + ember-concurrency-ts: 0.3.1(ember-concurrency@2.3.7(@babel/core@7.23.2)) transitivePeerDependencies: - '@babel/core' - supports-color @@ -12990,10 +13633,10 @@ snapshots: - '@babel/core' - supports-color - ember-math-helpers@4.0.0(ember-source@5.4.0): + ember-math-helpers@4.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/addon-shim': 1.8.7 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -13025,12 +13668,13 @@ snapshots: - '@babel/core' - supports-color - ember-modifier@4.1.0(ember-source@5.4.0): + ember-modifier@4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/addon-shim': 1.8.7 ember-cli-normalize-entity-name: 1.0.0 ember-cli-string-utils: 1.1.0 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + optionalDependencies: + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -13046,7 +13690,7 @@ snapshots: transitivePeerDependencies: - supports-color - ember-power-calendar@0.18.0(@babel/core@7.23.2)(ember-source@5.4.0): + ember-power-calendar@0.18.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: ember-assign-helper: 0.4.0 ember-cli-babel: 7.26.11 @@ -13054,7 +13698,7 @@ snapshots: ember-cli-htmlbars: 6.3.0 ember-concurrency: 2.3.7(@babel/core@7.23.2) ember-decorators: 6.1.1 - ember-element-helper: 0.6.1(ember-source@5.4.0) + ember-element-helper: 0.6.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-truth-helpers: 3.1.1 transitivePeerDependencies: - '@babel/core' @@ -13063,22 +13707,22 @@ snapshots: - ember-source - supports-color - ember-power-select@7.2.0(@babel/core@7.23.2)(ember-source@5.4.0)(webpack@5.89.0): + ember-power-select@7.2.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): dependencies: - '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0) + '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/string': 3.1.1 - '@embroider/util': 1.12.1(ember-source@5.4.0) + '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@glimmer/component': 1.1.2(@babel/core@7.23.2) '@glimmer/tracking': 1.1.2 ember-assign-helper: 0.4.0 - ember-auto-import: 2.7.2(webpack@5.89.0) - ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) + ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 ember-cli-typescript: 5.2.1 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0) + ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-text-measurer: 0.6.0 - ember-truth-helpers: 4.0.3(ember-source@5.4.0) + ember-truth-helpers: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) transitivePeerDependencies: - '@babel/core' - '@glint/environment-ember-loose' @@ -13087,13 +13731,13 @@ snapshots: - supports-color - webpack - ember-qunit@8.0.1(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(qunit@2.20.0): + ember-qunit@8.0.1(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(qunit@2.20.0): dependencies: - '@ember/test-helpers': 3.2.0(ember-source@5.4.0)(webpack@5.89.0) + '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) '@embroider/addon-shim': 1.8.7 '@embroider/macros': 1.13.5 ember-cli-test-loader: 3.1.0 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) qunit: 2.20.0 transitivePeerDependencies: - '@glint/template' @@ -13127,10 +13771,11 @@ snapshots: transitivePeerDependencies: - supports-color - ember-resolver@11.0.1(ember-source@5.4.0): + ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: ember-cli-babel: 7.26.11 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + optionalDependencies: + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -13150,15 +13795,16 @@ snapshots: transitivePeerDependencies: - supports-color - ember-simple-auth@6.0.0(@ember/test-helpers@3.2.0): + ember-simple-auth@6.0.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)): dependencies: - '@ember/test-helpers': 3.2.0(ember-source@5.4.0)(webpack@5.89.0) '@ember/test-waiters': 3.1.0 '@embroider/addon-shim': 1.8.7 '@embroider/macros': 1.13.5 ember-cli-is-package-missing: 1.0.0 ember-cookies: 1.1.2 silent-error: 1.1.1 + optionalDependencies: + '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) transitivePeerDependencies: - '@glint/template' - supports-color @@ -13169,7 +13815,7 @@ snapshots: transitivePeerDependencies: - encoding - ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0): + ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0): dependencies: '@babel/helper-module-imports': 7.22.15 '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.2) @@ -13201,7 +13847,7 @@ snapshots: broccoli-funnel: 3.0.8 broccoli-merge-trees: 4.2.0 chalk: 4.1.2 - ember-auto-import: 2.6.3(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-cli-get-component-path-option: 1.0.0 ember-cli-is-package-missing: 1.0.0 @@ -13224,12 +13870,12 @@ snapshots: - supports-color - webpack - ember-style-modifier@3.1.1(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0): + ember-style-modifier@3.1.1(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): dependencies: '@ember/string': 3.1.1 - ember-auto-import: 2.7.2(webpack@5.89.0) + ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 - ember-modifier: 4.1.0(ember-source@5.4.0) + ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) transitivePeerDependencies: - '@glint/template' - ember-source @@ -13309,11 +13955,11 @@ snapshots: transitivePeerDependencies: - supports-color - ember-truth-helpers@4.0.3(ember-source@5.4.0): + ember-truth-helpers@4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/addon-shim': 1.8.7 - ember-functions-as-helper-polyfill: 2.1.2(ember-source@5.4.0) - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-functions-as-helper-polyfill: 2.1.2(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -13344,11 +13990,11 @@ snapshots: - encoding - supports-color - ember-window-mock@0.9.0(ember-source@5.4.0): + ember-window-mock@0.9.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -13407,6 +14053,8 @@ snapshots: entities@3.0.1: {} + entities@4.5.0: {} + errlop@2.2.0: {} errno@0.1.8: @@ -13542,13 +14190,15 @@ snapshots: resolve: 1.22.8 semver: 7.6.0 - eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.52.0)(prettier@3.0.3): + eslint-plugin-prettier@5.0.1(@types/eslint@8.56.2)(eslint-config-prettier@9.0.0(eslint@8.52.0))(eslint@8.52.0)(prettier@3.0.3): dependencies: eslint: 8.52.0 - eslint-config-prettier: 9.0.0(eslint@8.52.0) prettier: 3.0.3 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 + optionalDependencies: + '@types/eslint': 8.56.2 + eslint-config-prettier: 9.0.0(eslint@8.52.0) eslint-plugin-qunit@8.0.1(eslint@8.52.0): dependencies: @@ -14424,6 +15074,8 @@ snapshots: graphemer@1.4.0: {} + gridstack@7.3.0: {} + growly@1.3.0: {} handlebars@4.7.8: @@ -14854,6 +15506,10 @@ snapshots: dependencies: has-tostringtag: 1.0.2 + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 @@ -15048,6 +15704,10 @@ snapshots: dependencies: uc.micro: 1.0.6 + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + livereload-js@3.4.1: {} loader-runner@2.4.0: {} @@ -15239,6 +15899,15 @@ snapshots: mdurl: 1.0.1 uc.micro: 1.0.6 + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + matcher-collection@1.1.2: dependencies: minimatch: 3.1.2 @@ -15260,6 +15929,8 @@ snapshots: mdurl@1.0.1: {} + mdurl@2.0.0: {} + media-typer@0.3.0: {} mem@5.1.1: @@ -15704,6 +16375,8 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + orderedmap@2.1.1: {} + os-browserify@0.3.0: {} os-homedir@1.0.2: {} @@ -15892,6 +16565,8 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-entry-points@1.1.0: {} + pkg-up@2.0.0: dependencies: find-up: 2.1.0 @@ -15926,7 +16601,7 @@ snapshots: postcss-color-functional-notation@6.0.4(postcss@8.4.35): dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) @@ -15950,15 +16625,15 @@ snapshots: postcss-custom-media@10.0.2(postcss@8.4.35): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 - '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) postcss: 8.4.35 postcss-custom-properties@13.3.4(postcss@8.4.35): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 postcss: 8.4.35 @@ -15966,7 +16641,7 @@ snapshots: postcss-custom-selectors@7.1.6(postcss@8.4.35): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 postcss: 8.4.35 @@ -16025,7 +16700,7 @@ snapshots: postcss-lab-function@6.0.9(postcss@8.4.35): dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) @@ -16034,8 +16709,9 @@ snapshots: postcss-load-config@4.0.2(postcss@8.4.35): dependencies: lilconfig: 3.1.0 - postcss: 8.4.35 yaml: 2.3.4 + optionalDependencies: + postcss: 8.4.35 postcss-logical@7.0.1(postcss@8.4.35): dependencies: @@ -16234,7 +16910,7 @@ snapshots: process@0.11.10: {} promise-inflight@1.0.1(bluebird@3.7.2): - dependencies: + optionalDependencies: bluebird: 3.7.2 promise-map-series@0.2.3: @@ -16251,6 +16927,109 @@ snapshots: retry: 0.12.0 signal-exit: 3.0.7 + prosemirror-changeset@2.2.1: + dependencies: + prosemirror-transform: 1.10.0 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.3 + + prosemirror-commands@1.6.0: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.0 + + prosemirror-dropcursor@1.8.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.0 + prosemirror-view: 1.34.3 + + prosemirror-gapcursor@1.3.2: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-view: 1.34.3 + + prosemirror-history@1.4.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.0 + prosemirror-view: 1.34.3 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.4.0: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.0 + + prosemirror-keymap@1.2.2: + dependencies: + prosemirror-state: 1.4.3 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.1: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + prosemirror-model: 1.22.3 + + prosemirror-menu@1.2.4: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.6.0 + prosemirror-history: 1.4.1 + prosemirror-state: 1.4.3 + + prosemirror-model@1.22.3: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.3: + dependencies: + prosemirror-model: 1.22.3 + + prosemirror-schema-list@1.4.1: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.0 + + prosemirror-state@1.4.3: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-transform: 1.10.0 + prosemirror-view: 1.34.3 + + prosemirror-tables@1.5.0: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.0 + prosemirror-view: 1.34.3 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.34.3): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-view: 1.34.3 + + prosemirror-transform@1.10.0: + dependencies: + prosemirror-model: 1.22.3 + + prosemirror-view@1.34.3: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.0 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -16283,6 +17062,8 @@ snapshots: inherits: 2.0.4 pump: 2.0.1 + punycode.js@2.3.1: {} + punycode@1.4.1: {} punycode@2.3.1: {} @@ -16591,6 +17372,8 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + rope-sequence@1.3.4: {} + route-recognizer@0.3.4: {} router_js@8.0.3(route-recognizer@0.3.4)(rsvp@4.8.5): @@ -17150,7 +17933,7 @@ snapshots: dependencies: '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 - '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0)(@csstools/css-tokenizer@2.2.3) + '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) '@csstools/selector-specificity': 3.0.1(postcss-selector-parser@6.0.15) balanced-match: 2.0.0 colord: 2.9.3 @@ -17348,7 +18131,7 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - testem@3.11.0: + testem@3.11.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6): dependencies: '@xmldom/xmldom': 0.8.10 backbone: 1.6.0 @@ -17356,7 +18139,7 @@ snapshots: charm: 1.0.2 commander: 2.20.3 compression: 1.7.4 - consolidate: 0.16.0(mustache@4.2.0) + consolidate: 0.16.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(mustache@4.2.0)(underscore@1.13.6) execa: 1.0.0 express: 4.18.2 fireworm: 0.7.2 @@ -17627,6 +18410,8 @@ snapshots: uc.micro@1.0.6: {} + uc.micro@2.1.0: {} + uglify-js@3.17.4: optional: true @@ -17756,6 +18541,8 @@ snapshots: vm-browserify@1.1.2: {} + w3c-keyname@2.2.8: {} + walk-sync@0.2.7: dependencies: ensure-posix-path: 1.1.1 From af8ee78fc9f6278523ca49c83bc8dbe17843f3c6 Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Sat, 22 Nov 2025 19:22:23 -0500 Subject: [PATCH 002/209] feat: Complete backend implementation for Ledger module - Add database migrations for accounts, journals, invoices, invoice_items, and wallets - Implement models with full relationships and traits - Create LedgerService, WalletService, and InvoiceService for business logic - Add controllers for accounts, invoices, wallets, and transactions - Create API resources for all models - Implement events and observers for invoice lifecycle - Configure routes and service provider - Support double-entry bookkeeping with journal entries - Enable system-wide transaction viewing - Implement wallet functionality for driver/entity payments --- ...01_000001_create_ledger_accounts_table.php | 51 ++++ ...01_000002_create_ledger_journals_table.php | 45 +++ ...01_000003_create_ledger_invoices_table.php | 61 ++++ ...0004_create_ledger_invoice_items_table.php | 44 +++ ..._01_000005_create_ledger_wallets_table.php | 48 ++++ server/src/Events/InvoiceCreated.php | 34 +++ server/src/Events/InvoicePaid.php | 34 +++ .../Internal/v1/AccountController.php | 169 +++++++++++ .../Internal/v1/InvoiceController.php | 261 +++++++++++++++++ .../Internal/v1/TransactionController.php | 106 +++++++ .../Internal/v1/WalletController.php | 235 ++++++++++++++++ server/src/Http/Resources/v1/Account.php | 37 +++ server/src/Http/Resources/v1/Invoice.php | 51 ++++ server/src/Http/Resources/v1/Wallet.php | 35 +++ server/src/Models/Account.php | 198 +++++++++++++ server/src/Models/Invoice.php | 245 ++++++++++++++++ server/src/Models/InvoiceItem.php | 86 ++++++ server/src/Models/Journal.php | 94 +++++++ server/src/Models/Wallet.php | 153 ++++++++++ server/src/Observers/InvoiceObserver.php | 37 +++ .../src/Providers/LedgerServiceProvider.php | 9 +- server/src/Services/InvoiceService.php | 183 ++++++++++++ server/src/Services/LedgerService.php | 178 ++++++++++++ server/src/Services/WalletService.php | 265 ++++++++++++++++++ server/src/routes.php | 32 ++- 25 files changed, 2689 insertions(+), 2 deletions(-) create mode 100644 server/migrations/2024_01_01_000001_create_ledger_accounts_table.php create mode 100644 server/migrations/2024_01_01_000002_create_ledger_journals_table.php create mode 100644 server/migrations/2024_01_01_000003_create_ledger_invoices_table.php create mode 100644 server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php create mode 100644 server/migrations/2024_01_01_000005_create_ledger_wallets_table.php create mode 100644 server/src/Events/InvoiceCreated.php create mode 100644 server/src/Events/InvoicePaid.php create mode 100644 server/src/Http/Controllers/Internal/v1/AccountController.php create mode 100644 server/src/Http/Controllers/Internal/v1/InvoiceController.php create mode 100644 server/src/Http/Controllers/Internal/v1/TransactionController.php create mode 100644 server/src/Http/Controllers/Internal/v1/WalletController.php create mode 100644 server/src/Http/Resources/v1/Account.php create mode 100644 server/src/Http/Resources/v1/Invoice.php create mode 100644 server/src/Http/Resources/v1/Wallet.php create mode 100644 server/src/Models/Account.php create mode 100644 server/src/Models/Invoice.php create mode 100644 server/src/Models/InvoiceItem.php create mode 100644 server/src/Models/Journal.php create mode 100644 server/src/Models/Wallet.php create mode 100644 server/src/Observers/InvoiceObserver.php create mode 100644 server/src/Services/InvoiceService.php create mode 100644 server/src/Services/LedgerService.php create mode 100644 server/src/Services/WalletService.php diff --git a/server/migrations/2024_01_01_000001_create_ledger_accounts_table.php b/server/migrations/2024_01_01_000001_create_ledger_accounts_table.php new file mode 100644 index 0000000..7ad10d5 --- /dev/null +++ b/server/migrations/2024_01_01_000001_create_ledger_accounts_table.php @@ -0,0 +1,51 @@ +increments('id'); + $table->string('_key')->nullable(); + $table->string('uuid', 191)->nullable()->unique(); + $table->string('public_id', 191)->nullable()->unique(); + $table->uuid('company_uuid')->nullable()->index(); + $table->char('created_by_uuid', 36)->nullable()->index(); + $table->char('updated_by_uuid', 36)->nullable()->index(); + $table->string('name', 191); + $table->string('code', 191)->nullable()->index(); + $table->string('type', 191)->index(); // asset, liability, equity, revenue, expense + $table->text('description')->nullable(); + $table->boolean('is_system_account')->default(false); + $table->integer('balance')->default(0); // stored in cents + $table->string('currency', 3)->default('USD'); + $table->string('status', 191)->default('active')->index(); + $table->json('meta')->nullable(); + $table->softDeletes(); + $table->timestamp('created_at')->nullable()->index(); + $table->timestamp('updated_at')->nullable(); + + $table->unique(['uuid']); + $table->unique(['company_uuid', 'code']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ledger_accounts'); + } +}; diff --git a/server/migrations/2024_01_01_000002_create_ledger_journals_table.php b/server/migrations/2024_01_01_000002_create_ledger_journals_table.php new file mode 100644 index 0000000..0b31db9 --- /dev/null +++ b/server/migrations/2024_01_01_000002_create_ledger_journals_table.php @@ -0,0 +1,45 @@ +increments('id'); + $table->string('_key')->nullable(); + $table->string('uuid', 191)->nullable()->unique(); + $table->uuid('company_uuid')->nullable()->index(); + $table->char('transaction_uuid', 36)->nullable()->index(); + $table->char('debit_account_uuid', 36)->nullable()->index(); + $table->char('credit_account_uuid', 36)->nullable()->index(); + $table->integer('amount'); // stored in cents + $table->string('currency', 3)->default('USD'); + $table->text('description')->nullable(); + $table->date('date')->index(); + $table->json('meta')->nullable(); + $table->timestamp('created_at')->nullable()->index(); + $table->timestamp('updated_at')->nullable(); + + $table->unique(['uuid']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ledger_journals'); + } +}; diff --git a/server/migrations/2024_01_01_000003_create_ledger_invoices_table.php b/server/migrations/2024_01_01_000003_create_ledger_invoices_table.php new file mode 100644 index 0000000..9830463 --- /dev/null +++ b/server/migrations/2024_01_01_000003_create_ledger_invoices_table.php @@ -0,0 +1,61 @@ +increments('id'); + $table->string('_key')->nullable(); + $table->string('uuid', 191)->nullable()->unique(); + $table->string('public_id', 191)->nullable()->unique(); + $table->uuid('company_uuid')->nullable()->index(); + $table->char('created_by_uuid', 36)->nullable()->index(); + $table->char('updated_by_uuid', 36)->nullable()->index(); + $table->uuid('customer_uuid')->nullable()->index(); + $table->string('customer_type')->nullable(); + $table->uuid('order_uuid')->nullable()->index(); + $table->uuid('transaction_uuid')->nullable()->index(); + $table->string('number', 191)->unique(); + $table->date('date')->index(); + $table->date('due_date')->nullable()->index(); + $table->integer('subtotal')->default(0); // stored in cents + $table->integer('tax')->default(0); // stored in cents + $table->integer('total_amount')->default(0); // stored in cents + $table->integer('amount_paid')->default(0); // stored in cents + $table->integer('balance')->default(0); // stored in cents + $table->string('currency', 3)->default('USD'); + $table->string('status', 191)->default('draft')->index(); // draft, sent, viewed, paid, partial, overdue, void, cancelled + $table->text('notes')->nullable(); + $table->text('terms')->nullable(); + $table->json('meta')->nullable(); + $table->softDeletes(); + $table->timestamp('created_at')->nullable()->index(); + $table->timestamp('updated_at')->nullable(); + $table->timestamp('sent_at')->nullable(); + $table->timestamp('viewed_at')->nullable(); + $table->timestamp('paid_at')->nullable(); + + $table->unique(['uuid']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ledger_invoices'); + } +}; diff --git a/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php b/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php new file mode 100644 index 0000000..4a1c1e3 --- /dev/null +++ b/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php @@ -0,0 +1,44 @@ +increments('id'); + $table->string('_key')->nullable(); + $table->string('uuid', 191)->nullable()->unique(); + $table->uuid('invoice_uuid')->nullable()->index(); + $table->string('description', 191); + $table->integer('quantity')->default(1); + $table->integer('unit_price')->default(0); // stored in cents + $table->integer('amount')->default(0); // stored in cents + $table->decimal('tax_rate', 5, 2)->default(0.00); // percentage + $table->integer('tax_amount')->default(0); // stored in cents + $table->json('meta')->nullable(); + $table->timestamp('created_at')->nullable()->index(); + $table->timestamp('updated_at')->nullable(); + + $table->unique(['uuid']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ledger_invoice_items'); + } +}; diff --git a/server/migrations/2024_01_01_000005_create_ledger_wallets_table.php b/server/migrations/2024_01_01_000005_create_ledger_wallets_table.php new file mode 100644 index 0000000..27b378b --- /dev/null +++ b/server/migrations/2024_01_01_000005_create_ledger_wallets_table.php @@ -0,0 +1,48 @@ +increments('id'); + $table->string('_key')->nullable(); + $table->string('uuid', 191)->nullable()->unique(); + $table->string('public_id', 191)->nullable()->unique(); + $table->uuid('company_uuid')->nullable()->index(); + $table->char('created_by_uuid', 36)->nullable()->index(); + $table->char('updated_by_uuid', 36)->nullable()->index(); + $table->uuid('subject_uuid')->nullable()->index(); + $table->string('subject_type')->nullable(); + $table->integer('balance')->default(0); // stored in cents + $table->string('currency', 3)->default('USD'); + $table->string('status', 191)->default('active')->index(); // active, frozen, closed + $table->json('meta')->nullable(); + $table->softDeletes(); + $table->timestamp('created_at')->nullable()->index(); + $table->timestamp('updated_at')->nullable(); + + $table->unique(['uuid']); + $table->unique(['subject_uuid', 'subject_type']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('ledger_wallets'); + } +}; diff --git a/server/src/Events/InvoiceCreated.php b/server/src/Events/InvoiceCreated.php new file mode 100644 index 0000000..aa3d00f --- /dev/null +++ b/server/src/Events/InvoiceCreated.php @@ -0,0 +1,34 @@ +invoice = $invoice; + } +} diff --git a/server/src/Events/InvoicePaid.php b/server/src/Events/InvoicePaid.php new file mode 100644 index 0000000..fe5b229 --- /dev/null +++ b/server/src/Events/InvoicePaid.php @@ -0,0 +1,34 @@ +invoice = $invoice; + } +} diff --git a/server/src/Http/Controllers/Internal/v1/AccountController.php b/server/src/Http/Controllers/Internal/v1/AccountController.php new file mode 100644 index 0000000..5369dc5 --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/AccountController.php @@ -0,0 +1,169 @@ +when($request->filled('type'), function ($query) use ($request) { + $query->where('type', $request->input('type')); + }) + ->when($request->filled('status'), function ($query) use ($request) { + $query->where('status', $request->input('status')); + }) + ->when($request->filled('search'), function ($query) use ($request) { + $search = $request->input('search'); + $query->where(function ($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('code', 'like', "%{$search}%") + ->orWhere('description', 'like', "%{$search}%"); + }); + }) + ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) + ->paginate($request->input('limit', 15)); + + return AccountResource::collection($results); + } + + /** + * Find a single account. + * + * @return \Illuminate\Http\Response + */ + public function find($id, Request $request) + { + $account = Account::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + return new AccountResource($account); + } + + /** + * Create a new account. + * + * @return \Illuminate\Http\Response + */ + public function create(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:191', + 'code' => 'nullable|string|max:191', + 'type' => 'required|in:asset,liability,equity,revenue,expense', + 'description' => 'nullable|string', + 'currency' => 'nullable|string|size:3', + ]); + + $account = Account::create([ + 'company_uuid' => session('company'), + 'name' => $request->input('name'), + 'code' => $request->input('code'), + 'type' => $request->input('type'), + 'description' => $request->input('description'), + 'currency' => $request->input('currency', 'USD'), + 'status' => 'active', + ]); + + return new AccountResource($account); + } + + /** + * Update an account. + * + * @return \Illuminate\Http\Response + */ + public function update($id, Request $request) + { + $account = Account::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $request->validate([ + 'name' => 'sometimes|required|string|max:191', + 'code' => 'sometimes|nullable|string|max:191', + 'type' => 'sometimes|required|in:asset,liability,equity,revenue,expense', + 'description' => 'nullable|string', + 'status' => 'sometimes|in:active,inactive', + ]); + + $account->update($request->only([ + 'name', + 'code', + 'type', + 'description', + 'status', + ])); + + return new AccountResource($account); + } + + /** + * Delete an account. + * + * @return \Illuminate\Http\Response + */ + public function delete($id, Request $request) + { + $account = Account::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + if ($account->is_system_account) { + return response()->json(['error' => 'Cannot delete system account'], 400); + } + + $account->delete(); + + return response()->json(['status' => 'ok']); + } + + /** + * Recalculate and update the balance for an account. + * + * @return \Illuminate\Http\Response + */ + public function recalculateBalance($id, Request $request) + { + $account = Account::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $account->updateBalance(); + + return new AccountResource($account); + } +} diff --git a/server/src/Http/Controllers/Internal/v1/InvoiceController.php b/server/src/Http/Controllers/Internal/v1/InvoiceController.php new file mode 100644 index 0000000..4a2e3c6 --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/InvoiceController.php @@ -0,0 +1,261 @@ +with(['customer', 'items']) + ->when($request->filled('status'), function ($query) use ($request) { + $query->where('status', $request->input('status')); + }) + ->when($request->filled('customer'), function ($query) use ($request) { + $query->where('customer_uuid', $request->input('customer')); + }) + ->when($request->filled('search'), function ($query) use ($request) { + $search = $request->input('search'); + $query->where(function ($q) use ($search) { + $q->where('number', 'like', "%{$search}%") + ->orWhere('public_id', 'like', "%{$search}%"); + }); + }) + ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) + ->paginate($request->input('limit', 15)); + + return InvoiceResource::collection($results); + } + + /** + * Find a single invoice. + * + * @return \Illuminate\Http\Response + */ + public function find($id, Request $request) + { + $invoice = Invoice::where('company_uuid', session('company')) + ->with(['customer', 'items', 'order']) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id)->orWhere('number', $id); + }) + ->firstOrFail(); + + return new InvoiceResource($invoice); + } + + /** + * Create a new invoice. + * + * @return \Illuminate\Http\Response + */ + public function create(Request $request) + { + $request->validate([ + 'customer_uuid' => 'required|string', + 'customer_type' => 'required|string', + 'date' => 'required|date', + 'due_date' => 'nullable|date', + 'items' => 'required|array|min:1', + 'items.*.description' => 'required|string', + 'items.*.quantity' => 'required|integer|min:1', + 'items.*.unit_price' => 'required|integer|min:0', + ]); + + return DB::transaction(function () use ($request) { + $invoice = Invoice::create([ + 'company_uuid' => session('company'), + 'customer_uuid' => $request->input('customer_uuid'), + 'customer_type' => $request->input('customer_type'), + 'order_uuid' => $request->input('order_uuid'), + 'number' => Invoice::generateNumber(), + 'date' => $request->input('date'), + 'due_date' => $request->input('due_date'), + 'currency' => $request->input('currency', 'USD'), + 'status' => 'draft', + 'notes' => $request->input('notes'), + 'terms' => $request->input('terms'), + ]); + + // Create invoice items + foreach ($request->input('items', []) as $itemData) { + $item = new InvoiceItem([ + 'description' => $itemData['description'], + 'quantity' => $itemData['quantity'], + 'unit_price' => $itemData['unit_price'], + 'tax_rate' => $itemData['tax_rate'] ?? 0, + ]); + $item->calculateAmount(); + $invoice->items()->save($item); + } + + // Calculate totals + $invoice->calculateTotals(); + $invoice->save(); + + return new InvoiceResource($invoice->load(['customer', 'items'])); + }); + } + + /** + * Update an invoice. + * + * @return \Illuminate\Http\Response + */ + public function update($id, Request $request) + { + $invoice = Invoice::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + return DB::transaction(function () use ($invoice, $request) { + $invoice->update($request->only([ + 'customer_uuid', + 'customer_type', + 'date', + 'due_date', + 'notes', + 'terms', + 'status', + ])); + + // Update items if provided + if ($request->has('items')) { + // Delete existing items + $invoice->items()->delete(); + + // Create new items + foreach ($request->input('items', []) as $itemData) { + $item = new InvoiceItem([ + 'description' => $itemData['description'], + 'quantity' => $itemData['quantity'], + 'unit_price' => $itemData['unit_price'], + 'tax_rate' => $itemData['tax_rate'] ?? 0, + ]); + $item->calculateAmount(); + $invoice->items()->save($item); + } + + // Recalculate totals + $invoice->calculateTotals(); + $invoice->save(); + } + + return new InvoiceResource($invoice->load(['customer', 'items'])); + }); + } + + /** + * Delete an invoice. + * + * @return \Illuminate\Http\Response + */ + public function delete($id, Request $request) + { + $invoice = Invoice::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + if ($invoice->status === 'paid') { + return response()->json(['error' => 'Cannot delete paid invoice'], 400); + } + + $invoice->delete(); + + return response()->json(['status' => 'ok']); + } + + /** + * Create an invoice from an order. + * + * @return \Illuminate\Http\Response + */ + public function createFromOrder(Request $request) + { + $request->validate([ + 'order_uuid' => 'required|string|exists:orders,uuid', + ]); + + $order = Order::where('company_uuid', session('company')) + ->where('uuid', $request->input('order_uuid')) + ->firstOrFail(); + + $invoiceService = app(InvoiceService::class); + $invoice = $invoiceService->createFromOrder($order); + + return new InvoiceResource($invoice->load(['customer', 'items'])); + } + + /** + * Record a payment for an invoice. + * + * @return \Illuminate\Http\Response + */ + public function recordPayment($id, Request $request) + { + $request->validate([ + 'amount' => 'required|integer|min:1', + ]); + + $invoice = Invoice::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $invoiceService = app(InvoiceService::class); + $invoice = $invoiceService->recordPayment($invoice, $request->input('amount')); + + return new InvoiceResource($invoice->load(['customer', 'items'])); + } + + /** + * Mark an invoice as sent. + * + * @return \Illuminate\Http\Response + */ + public function markAsSent($id, Request $request) + { + $invoice = Invoice::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $invoice->markAsSent(); + + return new InvoiceResource($invoice); + } +} diff --git a/server/src/Http/Controllers/Internal/v1/TransactionController.php b/server/src/Http/Controllers/Internal/v1/TransactionController.php new file mode 100644 index 0000000..83a1c63 --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/TransactionController.php @@ -0,0 +1,106 @@ +with(['customer', 'items']) + ->when($request->filled('type'), function ($query) use ($request) { + $query->where('type', $request->input('type')); + }) + ->when($request->filled('status'), function ($query) use ($request) { + $query->where('status', $request->input('status')); + }) + ->when($request->filled('gateway'), function ($query) use ($request) { + $query->where('gateway', $request->input('gateway')); + }) + ->when($request->filled('customer'), function ($query) use ($request) { + $query->where('customer_uuid', $request->input('customer')); + }) + ->when($request->filled('search'), function ($query) use ($request) { + $search = $request->input('search'); + $query->where(function ($q) use ($search) { + $q->where('gateway_transaction_id', 'like', "%{$search}%") + ->orWhere('public_id', 'like', "%{$search}%") + ->orWhere('description', 'like', "%{$search}%"); + }); + }) + ->when($request->filled('start_date'), function ($query) use ($request) { + $query->where('created_at', '>=', $request->input('start_date')); + }) + ->when($request->filled('end_date'), function ($query) use ($request) { + $query->where('created_at', '<=', $request->input('end_date')); + }) + ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) + ->paginate($request->input('limit', 15)); + + return TransactionResource::collection($results); + } + + /** + * Find a single transaction. + * + * @return \Illuminate\Http\Response + */ + public function find($id, Request $request) + { + $transaction = Transaction::where('company_uuid', session('company')) + ->with(['customer', 'items']) + ->where(function ($query) use ($id) { + $query->where('uuid', $id) + ->orWhere('public_id', $id) + ->orWhere('gateway_transaction_id', $id); + }) + ->firstOrFail(); + + // Load the journal entry if it exists + $journal = Journal::where('transaction_uuid', $transaction->uuid)->first(); + + $response = new TransactionResource($transaction); + $data = $response->toArray(request()); + + if ($journal) { + $data['journal'] = [ + 'uuid' => $journal->uuid, + 'debit_account_uuid' => $journal->debit_account_uuid, + 'credit_account_uuid' => $journal->credit_account_uuid, + 'amount' => $journal->amount, + 'currency' => $journal->currency, + 'description' => $journal->description, + 'date' => $journal->date, + 'debit_account' => $journal->debitAccount, + 'credit_account' => $journal->creditAccount, + ]; + } + + return response()->json($data); + } +} diff --git a/server/src/Http/Controllers/Internal/v1/WalletController.php b/server/src/Http/Controllers/Internal/v1/WalletController.php new file mode 100644 index 0000000..b45b1dd --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/WalletController.php @@ -0,0 +1,235 @@ +with(['subject']) + ->when($request->filled('status'), function ($query) use ($request) { + $query->where('status', $request->input('status')); + }) + ->when($request->filled('subject_type'), function ($query) use ($request) { + $query->where('subject_type', $request->input('subject_type')); + }) + ->when($request->filled('search'), function ($query) use ($request) { + $search = $request->input('search'); + $query->where('public_id', 'like', "%{$search}%"); + }) + ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) + ->paginate($request->input('limit', 15)); + + return WalletResource::collection($results); + } + + /** + * Find a single wallet. + * + * @return \Illuminate\Http\Response + */ + public function find($id, Request $request) + { + $wallet = Wallet::where('company_uuid', session('company')) + ->with(['subject']) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + return new WalletResource($wallet); + } + + /** + * Create a new wallet. + * + * @return \Illuminate\Http\Response + */ + public function create(Request $request) + { + $request->validate([ + 'subject_uuid' => 'required|string', + 'subject_type' => 'required|string', + 'currency' => 'nullable|string|size:3', + ]); + + $wallet = Wallet::create([ + 'company_uuid' => session('company'), + 'subject_uuid' => $request->input('subject_uuid'), + 'subject_type' => $request->input('subject_type'), + 'currency' => $request->input('currency', 'USD'), + 'balance' => 0, + 'status' => 'active', + ]); + + return new WalletResource($wallet->load('subject')); + } + + /** + * Update a wallet. + * + * @return \Illuminate\Http\Response + */ + public function update($id, Request $request) + { + $wallet = Wallet::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $request->validate([ + 'status' => 'sometimes|in:active,frozen,closed', + ]); + + $wallet->update($request->only(['status'])); + + return new WalletResource($wallet); + } + + /** + * Delete a wallet. + * + * @return \Illuminate\Http\Response + */ + public function delete($id, Request $request) + { + $wallet = Wallet::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + if ($wallet->balance != 0) { + return response()->json(['error' => 'Cannot delete wallet with non-zero balance'], 400); + } + + $wallet->delete(); + + return response()->json(['status' => 'ok']); + } + + /** + * Deposit funds into a wallet. + * + * @return \Illuminate\Http\Response + */ + public function deposit($id, Request $request) + { + $request->validate([ + 'amount' => 'required|integer|min:1', + 'description' => 'nullable|string', + ]); + + $wallet = Wallet::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $walletService = app(WalletService::class); + $wallet = $walletService->deposit( + $wallet, + $request->input('amount'), + $request->input('description', '') + ); + + return new WalletResource($wallet); + } + + /** + * Withdraw funds from a wallet. + * + * @return \Illuminate\Http\Response + */ + public function withdraw($id, Request $request) + { + $request->validate([ + 'amount' => 'required|integer|min:1', + 'description' => 'nullable|string', + ]); + + $wallet = Wallet::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $walletService = app(WalletService::class); + $wallet = $walletService->withdraw( + $wallet, + $request->input('amount'), + $request->input('description', '') + ); + + return new WalletResource($wallet); + } + + /** + * Transfer funds between wallets. + * + * @return \Illuminate\Http\Response + */ + public function transfer(Request $request) + { + $request->validate([ + 'from_wallet' => 'required|string', + 'to_wallet' => 'required|string', + 'amount' => 'required|integer|min:1', + 'description' => 'nullable|string', + ]); + + $fromWallet = Wallet::where('company_uuid', session('company')) + ->where(function ($query) use ($request) { + $id = $request->input('from_wallet'); + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $toWallet = Wallet::where('company_uuid', session('company')) + ->where(function ($query) use ($request) { + $id = $request->input('to_wallet'); + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $walletService = app(WalletService::class); + $result = $walletService->transfer( + $fromWallet, + $toWallet, + $request->input('amount'), + $request->input('description', '') + ); + + return response()->json([ + 'from_wallet' => new WalletResource($result['from_wallet']), + 'to_wallet' => new WalletResource($result['to_wallet']), + ]); + } +} diff --git a/server/src/Http/Resources/v1/Account.php b/server/src/Http/Resources/v1/Account.php new file mode 100644 index 0000000..1538cc9 --- /dev/null +++ b/server/src/Http/Resources/v1/Account.php @@ -0,0 +1,37 @@ + $this->when(Http::isInternalRequest(), $this->id, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id), + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), + 'name' => $this->name, + 'code' => $this->code, + 'type' => $this->type, + 'description' => $this->description, + 'is_system_account' => $this->is_system_account, + 'balance' => $this->balance, + 'currency' => $this->currency, + 'status' => $this->status, + 'meta' => $this->meta, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/Http/Resources/v1/Invoice.php b/server/src/Http/Resources/v1/Invoice.php new file mode 100644 index 0000000..2df726b --- /dev/null +++ b/server/src/Http/Resources/v1/Invoice.php @@ -0,0 +1,51 @@ + $this->when(Http::isInternalRequest(), $this->id, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id), + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), + 'customer_uuid' => $this->customer_uuid, + 'customer_type' => $this->customer_type, + 'customer' => $this->whenLoaded('customer'), + 'order_uuid' => $this->order_uuid, + 'order' => $this->whenLoaded('order'), + 'transaction_uuid' => $this->transaction_uuid, + 'number' => $this->number, + 'date' => $this->date, + 'due_date' => $this->due_date, + 'subtotal' => $this->subtotal, + 'tax' => $this->tax, + 'total_amount' => $this->total_amount, + 'amount_paid' => $this->amount_paid, + 'balance' => $this->balance, + 'currency' => $this->currency, + 'status' => $this->status, + 'notes' => $this->notes, + 'terms' => $this->terms, + 'items' => $this->whenLoaded('items'), + 'meta' => $this->meta, + 'sent_at' => $this->sent_at, + 'viewed_at' => $this->viewed_at, + 'paid_at' => $this->paid_at, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/Http/Resources/v1/Wallet.php b/server/src/Http/Resources/v1/Wallet.php new file mode 100644 index 0000000..3cc6845 --- /dev/null +++ b/server/src/Http/Resources/v1/Wallet.php @@ -0,0 +1,35 @@ + $this->when(Http::isInternalRequest(), $this->id, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id), + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), + 'subject_uuid' => $this->subject_uuid, + 'subject_type' => $this->subject_type, + 'subject' => $this->whenLoaded('subject'), + 'balance' => $this->balance, + 'currency' => $this->currency, + 'status' => $this->status, + 'meta' => $this->meta, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/Models/Account.php b/server/src/Models/Account.php new file mode 100644 index 0000000..103e947 --- /dev/null +++ b/server/src/Models/Account.php @@ -0,0 +1,198 @@ + 'boolean', + 'balance' => 'integer', + 'meta' => Json::class, + ]; + + /** + * Dynamic attributes that are appended to object. + * + * @var array + */ + protected $appends = []; + + /** + * The attributes excluded from the model's JSON form. + * + * @var array + */ + protected $hidden = []; + + /** + * Journal entries where this account is debited. + */ + public function debitJournals(): HasMany + { + return $this->hasMany(Journal::class, 'debit_account_uuid'); + } + + /** + * Journal entries where this account is credited. + */ + public function creditJournals(): HasMany + { + return $this->hasMany(Journal::class, 'credit_account_uuid'); + } + + /** + * All journal entries for this account. + */ + public function journals() + { + return Journal::where('debit_account_uuid', $this->uuid) + ->orWhere('credit_account_uuid', $this->uuid); + } + + /** + * Calculate the current balance of the account. + * + * @return int + */ + public function calculateBalance(): int + { + $debits = $this->debitJournals()->sum('amount'); + $credits = $this->creditJournals()->sum('amount'); + + // For asset and expense accounts, debits increase balance + // For liability, equity, and revenue accounts, credits increase balance + if (in_array($this->type, ['asset', 'expense'])) { + return $debits - $credits; + } + + return $credits - $debits; + } + + /** + * Update the cached balance. + * + * @return void + */ + public function updateBalance(): void + { + $this->balance = $this->calculateBalance(); + $this->save(); + } + + /** + * Check if the account is an asset. + * + * @return bool + */ + public function isAsset(): bool + { + return $this->type === 'asset'; + } + + /** + * Check if the account is a liability. + * + * @return bool + */ + public function isLiability(): bool + { + return $this->type === 'liability'; + } + + /** + * Check if the account is equity. + * + * @return bool + */ + public function isEquity(): bool + { + return $this->type === 'equity'; + } + + /** + * Check if the account is revenue. + * + * @return bool + */ + public function isRevenue(): bool + { + return $this->type === 'revenue'; + } + + /** + * Check if the account is an expense. + * + * @return bool + */ + public function isExpense(): bool + { + return $this->type === 'expense'; + } +} diff --git a/server/src/Models/Invoice.php b/server/src/Models/Invoice.php new file mode 100644 index 0000000..2691fed --- /dev/null +++ b/server/src/Models/Invoice.php @@ -0,0 +1,245 @@ + 'date', + 'due_date' => 'date', + 'subtotal' => 'integer', + 'tax' => 'integer', + 'total_amount' => 'integer', + 'amount_paid' => 'integer', + 'balance' => 'integer', + 'customer_type' => PolymorphicType::class, + 'meta' => Json::class, + 'sent_at' => 'datetime', + 'viewed_at' => 'datetime', + 'paid_at' => 'datetime', + ]; + + /** + * Dynamic attributes that are appended to object. + * + * @var array + */ + protected $appends = []; + + /** + * The attributes excluded from the model's JSON form. + * + * @var array + */ + protected $hidden = []; + + /** + * The customer for this invoice. + */ + public function customer(): MorphTo + { + return $this->morphTo(__FUNCTION__, 'customer_type', 'customer_uuid')->withoutGlobalScopes(); + } + + /** + * The order this invoice is for. + */ + public function order(): BelongsTo + { + return $this->belongsTo(Order::class, 'order_uuid'); + } + + /** + * The transaction associated with this invoice. + */ + public function transaction(): BelongsTo + { + return $this->belongsTo(Transaction::class, 'transaction_uuid'); + } + + /** + * The line items for this invoice. + */ + public function items(): HasMany + { + return $this->hasMany(InvoiceItem::class, 'invoice_uuid'); + } + + /** + * Generate a unique invoice number. + * + * @param string $prefix + * @param int $length + * + * @return string + */ + public static function generateNumber(string $prefix = 'INV', int $length = 6): string + { + $number = $prefix . '-' . str_pad(mt_rand(1, pow(10, $length) - 1), $length, '0', STR_PAD_LEFT); + $exists = self::where('number', $number)->withTrashed()->exists(); + + while ($exists) { + $number = $prefix . '-' . str_pad(mt_rand(1, pow(10, $length) - 1), $length, '0', STR_PAD_LEFT); + $exists = self::where('number', $number)->withTrashed()->exists(); + } + + return $number; + } + + /** + * Calculate totals from line items. + * + * @return void + */ + public function calculateTotals(): void + { + $this->subtotal = $this->items()->sum('amount'); + $this->tax = $this->items()->sum('tax_amount'); + $this->total_amount = $this->subtotal + $this->tax; + $this->balance = $this->total_amount - $this->amount_paid; + } + + /** + * Mark the invoice as sent. + * + * @return void + */ + public function markAsSent(): void + { + $this->status = 'sent'; + $this->sent_at = now(); + $this->save(); + } + + /** + * Mark the invoice as viewed. + * + * @return void + */ + public function markAsViewed(): void + { + if (!$this->viewed_at) { + $this->viewed_at = now(); + $this->save(); + } + } + + /** + * Mark the invoice as paid. + * + * @return void + */ + public function markAsPaid(): void + { + $this->status = 'paid'; + $this->amount_paid = $this->total_amount; + $this->balance = 0; + $this->paid_at = now(); + $this->save(); + } + + /** + * Check if the invoice is overdue. + * + * @return bool + */ + public function isOverdue(): bool + { + return $this->due_date && $this->due_date->isPast() && $this->status !== 'paid'; + } + + /** + * Check if the invoice is paid. + * + * @return bool + */ + public function isPaid(): bool + { + return $this->status === 'paid'; + } +} diff --git a/server/src/Models/InvoiceItem.php b/server/src/Models/InvoiceItem.php new file mode 100644 index 0000000..f7a919e --- /dev/null +++ b/server/src/Models/InvoiceItem.php @@ -0,0 +1,86 @@ + 'integer', + 'unit_price' => 'integer', + 'amount' => 'integer', + 'tax_rate' => 'decimal:2', + 'tax_amount' => 'integer', + 'meta' => Json::class, + ]; + + /** + * Dynamic attributes that are appended to object. + * + * @var array + */ + protected $appends = []; + + /** + * The attributes excluded from the model's JSON form. + * + * @var array + */ + protected $hidden = []; + + /** + * The invoice this item belongs to. + */ + public function invoice(): BelongsTo + { + return $this->belongsTo(Invoice::class, 'invoice_uuid'); + } + + /** + * Calculate the line item amount. + * + * @return void + */ + public function calculateAmount(): void + { + $this->amount = $this->quantity * $this->unit_price; + $this->tax_amount = (int) round($this->amount * ($this->tax_rate / 100)); + } +} diff --git a/server/src/Models/Journal.php b/server/src/Models/Journal.php new file mode 100644 index 0000000..a13a3cc --- /dev/null +++ b/server/src/Models/Journal.php @@ -0,0 +1,94 @@ + 'integer', + 'date' => 'date', + 'meta' => Json::class, + ]; + + /** + * Dynamic attributes that are appended to object. + * + * @var array + */ + protected $appends = []; + + /** + * The attributes excluded from the model's JSON form. + * + * @var array + */ + protected $hidden = []; + + /** + * The transaction this journal entry belongs to. + */ + public function transaction(): BelongsTo + { + return $this->belongsTo(Transaction::class, 'transaction_uuid'); + } + + /** + * The account being debited. + */ + public function debitAccount(): BelongsTo + { + return $this->belongsTo(Account::class, 'debit_account_uuid'); + } + + /** + * The account being credited. + */ + public function creditAccount(): BelongsTo + { + return $this->belongsTo(Account::class, 'credit_account_uuid'); + } +} diff --git a/server/src/Models/Wallet.php b/server/src/Models/Wallet.php new file mode 100644 index 0000000..f47e6e3 --- /dev/null +++ b/server/src/Models/Wallet.php @@ -0,0 +1,153 @@ + 'integer', + 'subject_type' => PolymorphicType::class, + 'meta' => Json::class, + ]; + + /** + * Dynamic attributes that are appended to object. + * + * @var array + */ + protected $appends = []; + + /** + * The attributes excluded from the model's JSON form. + * + * @var array + */ + protected $hidden = []; + + /** + * The subject (owner) of this wallet. + */ + public function subject(): MorphTo + { + return $this->morphTo(__FUNCTION__, 'subject_type', 'subject_uuid')->withoutGlobalScopes(); + } + + /** + * Check if the wallet is active. + * + * @return bool + */ + public function isActive(): bool + { + return $this->status === 'active'; + } + + /** + * Check if the wallet is frozen. + * + * @return bool + */ + public function isFrozen(): bool + { + return $this->status === 'frozen'; + } + + /** + * Check if the wallet has sufficient balance. + * + * @param int $amount + * + * @return bool + */ + public function hasSufficientBalance(int $amount): bool + { + return $this->balance >= $amount; + } + + /** + * Freeze the wallet. + * + * @return void + */ + public function freeze(): void + { + $this->status = 'frozen'; + $this->save(); + } + + /** + * Activate the wallet. + * + * @return void + */ + public function activate(): void + { + $this->status = 'active'; + $this->save(); + } +} diff --git a/server/src/Observers/InvoiceObserver.php b/server/src/Observers/InvoiceObserver.php new file mode 100644 index 0000000..98d220d --- /dev/null +++ b/server/src/Observers/InvoiceObserver.php @@ -0,0 +1,37 @@ +isDirty('status') && $invoice->status === 'paid') { + event(new InvoicePaid($invoice)); + } + } +} diff --git a/server/src/Providers/LedgerServiceProvider.php b/server/src/Providers/LedgerServiceProvider.php index 106e7c7..5680213 100644 --- a/server/src/Providers/LedgerServiceProvider.php +++ b/server/src/Providers/LedgerServiceProvider.php @@ -18,7 +18,9 @@ class LedgerServiceProvider extends CoreServiceProvider * * @var array */ - public $observers = []; + public $observers = [ + \Fleetbase\Ledger\Models\Invoice::class => \Fleetbase\Ledger\Observers\InvoiceObserver::class, + ]; /** * Register any application services. @@ -36,6 +38,11 @@ class LedgerServiceProvider extends CoreServiceProvider public function register() { $this->app->register(CoreServiceProvider::class); + + // Register services + $this->app->singleton(\Fleetbase\Ledger\Services\LedgerService::class); + $this->app->singleton(\Fleetbase\Ledger\Services\WalletService::class); + $this->app->singleton(\Fleetbase\Ledger\Services\InvoiceService::class); } /** diff --git a/server/src/Services/InvoiceService.php b/server/src/Services/InvoiceService.php new file mode 100644 index 0000000..de9ac36 --- /dev/null +++ b/server/src/Services/InvoiceService.php @@ -0,0 +1,183 @@ +ledgerService = $ledgerService; + } + + /** + * Create an invoice from an order. + * + * @param Order $order + * @param array $options + * + * @return Invoice + */ + public function createFromOrder(Order $order, array $options = []): Invoice + { + return DB::transaction(function () use ($order, $options) { + // Create the invoice + $invoice = Invoice::create([ + 'company_uuid' => $order->company_uuid, + 'customer_uuid' => $order->customer_uuid, + 'customer_type' => $order->customer_type, + 'order_uuid' => $order->uuid, + 'number' => $options['number'] ?? Invoice::generateNumber(), + 'date' => $options['date'] ?? now(), + 'due_date' => $options['due_date'] ?? now()->addDays(30), + 'currency' => $options['currency'] ?? 'USD', + 'status' => 'draft', + 'notes' => $options['notes'] ?? null, + 'terms' => $options['terms'] ?? null, + ]); + + // Create invoice items from order + $this->createItemsFromOrder($invoice, $order); + + // Calculate totals + $invoice->calculateTotals(); + $invoice->save(); + + return $invoice; + }); + } + + /** + * Create invoice items from an order. + * + * @param Invoice $invoice + * @param Order $order + * + * @return void + */ + protected function createItemsFromOrder(Invoice $invoice, Order $order): void + { + // Create a line item for the order + InvoiceItem::create([ + 'invoice_uuid' => $invoice->uuid, + 'description' => "Order: {$order->public_id}", + 'quantity' => 1, + 'unit_price' => $order->getMeta('total', 0), + 'amount' => $order->getMeta('total', 0), + 'tax_rate' => 0, + 'tax_amount' => 0, + ]); + } + + /** + * Record a payment for an invoice. + * + * @param Invoice $invoice + * @param int $amount + * @param array $options + * + * @return Invoice + */ + public function recordPayment(Invoice $invoice, int $amount, array $options = []): Invoice + { + return DB::transaction(function () use ($invoice, $amount, $options) { + // Get accounts + $cashAccount = $this->getCashAccount($invoice->company_uuid); + $arAccount = $this->getAccountsReceivableAccount($invoice->company_uuid); + + // Create journal entry: Debit Cash, Credit Accounts Receivable + $journal = $this->ledgerService->createJournalEntry( + $cashAccount, + $arAccount, + $amount, + "Payment for invoice {$invoice->number}", + array_merge($options, [ + 'company_uuid' => $invoice->company_uuid, + 'type' => 'invoice_payment', + ]) + ); + + // Update invoice + $invoice->amount_paid += $amount; + $invoice->balance = $invoice->total_amount - $invoice->amount_paid; + + if ($invoice->balance <= 0) { + $invoice->markAsPaid(); + } elseif ($invoice->amount_paid > 0) { + $invoice->status = 'partial'; + } + + // Link the transaction to the invoice + if (!$invoice->transaction_uuid) { + $invoice->transaction_uuid = $journal->transaction_uuid; + } + + $invoice->save(); + + return $invoice; + }); + } + + /** + * Get or create the cash account. + * + * @param string $companyUuid + * + * @return Account + */ + protected function getCashAccount(string $companyUuid): Account + { + return Account::firstOrCreate( + [ + 'company_uuid' => $companyUuid, + 'code' => 'CASH-DEFAULT', + ], + [ + 'name' => 'Cash', + 'type' => 'asset', + 'description' => 'Default cash account', + 'is_system_account' => true, + ] + ); + } + + /** + * Get or create the accounts receivable account. + * + * @param string $companyUuid + * + * @return Account + */ + protected function getAccountsReceivableAccount(string $companyUuid): Account + { + return Account::firstOrCreate( + [ + 'company_uuid' => $companyUuid, + 'code' => 'AR-DEFAULT', + ], + [ + 'name' => 'Accounts Receivable', + 'type' => 'asset', + 'description' => 'Default accounts receivable account', + 'is_system_account' => true, + ] + ); + } +} diff --git a/server/src/Services/LedgerService.php b/server/src/Services/LedgerService.php new file mode 100644 index 0000000..31d5da9 --- /dev/null +++ b/server/src/Services/LedgerService.php @@ -0,0 +1,178 @@ + $options['company_uuid'] ?? session('company'), + 'gateway_transaction_id' => $options['transaction_id'] ?? Transaction::generateNumber(), + 'amount' => $amount, + 'currency' => $options['currency'] ?? 'USD', + 'description' => $description, + 'type' => $options['type'] ?? 'ledger', + 'status' => $options['status'] ?? 'completed', + 'meta' => $options['meta'] ?? [], + ]); + + // Create the journal entry + $journal = Journal::create([ + 'company_uuid' => $transaction->company_uuid, + 'transaction_uuid' => $transaction->uuid, + 'debit_account_uuid' => $debitAccount->uuid, + 'credit_account_uuid' => $creditAccount->uuid, + 'amount' => $amount, + 'currency' => $transaction->currency, + 'description' => $description, + 'date' => $options['date'] ?? now(), + 'meta' => $options['meta'] ?? [], + ]); + + // Update account balances + $debitAccount->updateBalance(); + $creditAccount->updateBalance(); + + return $journal; + }); + } + + /** + * Transfer funds between two accounts. + * + * @param Account $fromAccount + * @param Account $toAccount + * @param int $amount + * @param string $description + * @param array $options + * + * @return Journal + */ + public function transfer( + Account $fromAccount, + Account $toAccount, + int $amount, + string $description = '', + array $options = [] + ): Journal { + return $this->createJournalEntry($fromAccount, $toAccount, $amount, $description, $options); + } + + /** + * Record revenue. + * + * @param Account $assetAccount + * @param Account $revenueAccount + * @param int $amount + * @param string $description + * @param array $options + * + * @return Journal + */ + public function recordRevenue( + Account $assetAccount, + Account $revenueAccount, + int $amount, + string $description = '', + array $options = [] + ): Journal { + return $this->createJournalEntry($assetAccount, $revenueAccount, $amount, $description, $options); + } + + /** + * Record an expense. + * + * @param Account $expenseAccount + * @param Account $assetAccount + * @param int $amount + * @param string $description + * @param array $options + * + * @return Journal + */ + public function recordExpense( + Account $expenseAccount, + Account $assetAccount, + int $amount, + string $description = '', + array $options = [] + ): Journal { + return $this->createJournalEntry($expenseAccount, $assetAccount, $amount, $description, $options); + } + + /** + * Get the general ledger for a specific account. + * + * @param Account $account + * @param string|null $startDate + * @param string|null $endDate + * + * @return \Illuminate\Support\Collection + */ + public function getGeneralLedger(Account $account, ?string $startDate = null, ?string $endDate = null) + { + $query = Journal::where(function ($q) use ($account) { + $q->where('debit_account_uuid', $account->uuid) + ->orWhere('credit_account_uuid', $account->uuid); + }); + + if ($startDate) { + $query->where('date', '>=', $startDate); + } + + if ($endDate) { + $query->where('date', '<=', $endDate); + } + + return $query->orderBy('date', 'asc')->get(); + } + + /** + * Calculate the balance for an account at a specific date. + * + * @param Account $account + * @param string $date + * + * @return int + */ + public function getBalanceAtDate(Account $account, string $date): int + { + $debits = Journal::where('debit_account_uuid', $account->uuid) + ->where('date', '<=', $date) + ->sum('amount'); + + $credits = Journal::where('credit_account_uuid', $account->uuid) + ->where('date', '<=', $date) + ->sum('amount'); + + if (in_array($account->type, ['asset', 'expense'])) { + return $debits - $credits; + } + + return $credits - $debits; + } +} diff --git a/server/src/Services/WalletService.php b/server/src/Services/WalletService.php new file mode 100644 index 0000000..7a02867 --- /dev/null +++ b/server/src/Services/WalletService.php @@ -0,0 +1,265 @@ +ledgerService = $ledgerService; + } + + /** + * Get or create a wallet for a subject. + * + * @param Model $subject + * @param string $currency + * + * @return Wallet + */ + public function getOrCreateWallet(Model $subject, string $currency = 'USD'): Wallet + { + return Wallet::firstOrCreate( + [ + 'subject_uuid' => $subject->uuid, + 'subject_type' => get_class($subject), + ], + [ + 'company_uuid' => $subject->company_uuid ?? session('company'), + 'currency' => $currency, + 'balance' => 0, + 'status' => 'active', + ] + ); + } + + /** + * Deposit funds into a wallet. + * + * @param Wallet $wallet + * @param int $amount + * @param string $description + * @param array $options + * + * @return Wallet + */ + public function deposit(Wallet $wallet, int $amount, string $description = '', array $options = []): Wallet + { + if (!$wallet->isActive()) { + throw new \Exception('Wallet is not active'); + } + + return DB::transaction(function () use ($wallet, $amount, $description, $options) { + // Get or create the wallet liability account + $walletAccount = $this->getWalletAccount($wallet); + + // Get the source account (e.g., cash or bank account) + $sourceAccount = $options['source_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); + + // Create journal entry: Debit Wallet Liability, Credit Source Account + $this->ledgerService->createJournalEntry( + $walletAccount, + $sourceAccount, + $amount, + $description ?: "Deposit to wallet {$wallet->public_id}", + array_merge($options, [ + 'company_uuid' => $wallet->company_uuid, + 'type' => 'wallet_deposit', + ]) + ); + + // Update wallet balance + $wallet->balance += $amount; + $wallet->save(); + + return $wallet; + }); + } + + /** + * Withdraw funds from a wallet. + * + * @param Wallet $wallet + * @param int $amount + * @param string $description + * @param array $options + * + * @return Wallet + */ + public function withdraw(Wallet $wallet, int $amount, string $description = '', array $options = []): Wallet + { + if (!$wallet->isActive()) { + throw new \Exception('Wallet is not active'); + } + + if (!$wallet->hasSufficientBalance($amount)) { + throw new \Exception('Insufficient wallet balance'); + } + + return DB::transaction(function () use ($wallet, $amount, $description, $options) { + // Get or create the wallet liability account + $walletAccount = $this->getWalletAccount($wallet); + + // Get the destination account (e.g., expense or cash account) + $destinationAccount = $options['destination_account'] ?? $this->getDefaultExpenseAccount($wallet->company_uuid); + + // Create journal entry: Debit Destination Account, Credit Wallet Liability + $this->ledgerService->createJournalEntry( + $destinationAccount, + $walletAccount, + $amount, + $description ?: "Withdrawal from wallet {$wallet->public_id}", + array_merge($options, [ + 'company_uuid' => $wallet->company_uuid, + 'type' => 'wallet_withdrawal', + ]) + ); + + // Update wallet balance + $wallet->balance -= $amount; + $wallet->save(); + + return $wallet; + }); + } + + /** + * Transfer funds between two wallets. + * + * @param Wallet $fromWallet + * @param Wallet $toWallet + * @param int $amount + * @param string $description + * @param array $options + * + * @return array + */ + public function transfer(Wallet $fromWallet, Wallet $toWallet, int $amount, string $description = '', array $options = []): array + { + if (!$fromWallet->isActive() || !$toWallet->isActive()) { + throw new \Exception('One or both wallets are not active'); + } + + if (!$fromWallet->hasSufficientBalance($amount)) { + throw new \Exception('Insufficient balance in source wallet'); + } + + return DB::transaction(function () use ($fromWallet, $toWallet, $amount, $description, $options) { + // Get wallet accounts + $fromAccount = $this->getWalletAccount($fromWallet); + $toAccount = $this->getWalletAccount($toWallet); + + // Create journal entry: Debit To Wallet, Credit From Wallet + $journal = $this->ledgerService->createJournalEntry( + $toAccount, + $fromAccount, + $amount, + $description ?: "Transfer from {$fromWallet->public_id} to {$toWallet->public_id}", + array_merge($options, [ + 'company_uuid' => $fromWallet->company_uuid, + 'type' => 'wallet_transfer', + ]) + ); + + // Update wallet balances + $fromWallet->balance -= $amount; + $fromWallet->save(); + + $toWallet->balance += $amount; + $toWallet->save(); + + return [ + 'from_wallet' => $fromWallet, + 'to_wallet' => $toWallet, + 'journal' => $journal, + ]; + }); + } + + /** + * Get or create the ledger account for a wallet. + * + * @param Wallet $wallet + * + * @return Account + */ + protected function getWalletAccount(Wallet $wallet): Account + { + return Account::firstOrCreate( + [ + 'company_uuid' => $wallet->company_uuid, + 'code' => "WALLET-{$wallet->uuid}", + ], + [ + 'name' => "Wallet: {$wallet->public_id}", + 'type' => 'liability', + 'description' => "Liability account for wallet {$wallet->public_id}", + 'is_system_account' => true, + 'currency' => $wallet->currency, + ] + ); + } + + /** + * Get the default cash account. + * + * @param string $companyUuid + * + * @return Account + */ + protected function getDefaultCashAccount(string $companyUuid): Account + { + return Account::firstOrCreate( + [ + 'company_uuid' => $companyUuid, + 'code' => 'CASH-DEFAULT', + ], + [ + 'name' => 'Cash', + 'type' => 'asset', + 'description' => 'Default cash account', + 'is_system_account' => true, + ] + ); + } + + /** + * Get the default expense account. + * + * @param string $companyUuid + * + * @return Account + */ + protected function getDefaultExpenseAccount(string $companyUuid): Account + { + return Account::firstOrCreate( + [ + 'company_uuid' => $companyUuid, + 'code' => 'EXPENSE-WALLET', + ], + [ + 'name' => 'Wallet Expenses', + 'type' => 'expense', + 'description' => 'Expenses from wallet withdrawals', + 'is_system_account' => true, + ] + ); + } +} diff --git a/server/src/routes.php b/server/src/routes.php index 83c3165..79999a9 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -27,7 +27,37 @@ function ($router) { $router->group( ['prefix' => 'v1', 'middleware' => ['fleetbase.protected']], function ($router) { - // $router->fleetbaseRoutes('resourcex'); + // Accounts + $router->get('accounts', 'Internal\v1\AccountController@query'); + $router->get('accounts/{id}', 'Internal\v1\AccountController@find'); + $router->post('accounts', 'Internal\v1\AccountController@create'); + $router->put('accounts/{id}', 'Internal\v1\AccountController@update'); + $router->delete('accounts/{id}', 'Internal\v1\AccountController@delete'); + $router->post('accounts/{id}/recalculate-balance', 'Internal\v1\AccountController@recalculateBalance'); + + // Invoices + $router->get('invoices', 'Internal\v1\InvoiceController@query'); + $router->get('invoices/{id}', 'Internal\v1\InvoiceController@find'); + $router->post('invoices', 'Internal\v1\InvoiceController@create'); + $router->put('invoices/{id}', 'Internal\v1\InvoiceController@update'); + $router->delete('invoices/{id}', 'Internal\v1\InvoiceController@delete'); + $router->post('invoices/from-order', 'Internal\v1\InvoiceController@createFromOrder'); + $router->post('invoices/{id}/record-payment', 'Internal\v1\InvoiceController@recordPayment'); + $router->post('invoices/{id}/mark-as-sent', 'Internal\v1\InvoiceController@markAsSent'); + + // Wallets + $router->get('wallets', 'Internal\v1\WalletController@query'); + $router->get('wallets/{id}', 'Internal\v1\WalletController@find'); + $router->post('wallets', 'Internal\v1\WalletController@create'); + $router->put('wallets/{id}', 'Internal\v1\WalletController@update'); + $router->delete('wallets/{id}', 'Internal\v1\WalletController@delete'); + $router->post('wallets/{id}/deposit', 'Internal\v1\WalletController@deposit'); + $router->post('wallets/{id}/withdraw', 'Internal\v1\WalletController@withdraw'); + $router->post('wallets/transfer', 'Internal\v1\WalletController@transfer'); + + // Transactions (System-wide viewer) + $router->get('transactions', 'Internal\v1\TransactionController@query'); + $router->get('transactions/{id}', 'Internal\v1\TransactionController@find'); } ); } From abac1b11086723b5068a9c2fda0a6c6c238663d5 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Sat, 28 Feb 2026 10:42:19 +0800 Subject: [PATCH 003/209] New extension structure --- addon/extension.js | 9 + composer.json | 10 +- index.js | 11 - package.json | 8 +- pnpm-lock.yaml | 6416 +++++++++++++++++++++++++++++++++++--------- 5 files changed, 5167 insertions(+), 1287 deletions(-) create mode 100644 addon/extension.js diff --git a/addon/extension.js b/addon/extension.js new file mode 100644 index 0000000..3a3a373 --- /dev/null +++ b/addon/extension.js @@ -0,0 +1,9 @@ +import { Widget, ExtensionComponent, Hook } from '@fleetbase/ember-core/contracts'; + +export default { + setupExtension(app, universe) { + // const menuService = universe.getService('universe/menu-service'); + // const hookService = universe.getService('universe/hook-service'); + // const widgetService = universe.getService('universe/widget-service'); + } +}; diff --git a/composer.json b/composer.json index 357f106..a854615 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,8 @@ ], "require": { "php": "^8.0", - "fleetbase/core-api": "^1.4.30", - "fleetbase/fleetops-api": "^0.5.4", + "fleetbase/core-api": "*", + "fleetbase/fleetops-api": "*", "php-http/guzzle7-adapter": "^1.0", "psr/http-factory-implementation": "*" }, @@ -37,12 +37,6 @@ "phpstan/phpstan": "^1.10.38", "symfony/var-dumper": "^5.4.29" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/fleetbase/laravel-model-caching" - } - ], "autoload": { "psr-4": { "Fleetbase\\Ledger\\": "server/src/", diff --git a/index.js b/index.js index f7ceeee..7a5e298 100644 --- a/index.js +++ b/index.js @@ -1,21 +1,10 @@ 'use strict'; const { buildEngine } = require('ember-engines/lib/engine-addon'); const { name } = require('./package'); -const Funnel = require('broccoli-funnel'); module.exports = buildEngine({ name, - postprocessTree(type, tree) { - if (type === 'css') { - tree = new Funnel(tree, { - exclude: ['**/@fleetbase/ember-ui/**/*.css'], - }); - } - - return tree; - }, - lazyLoading: { enabled: true, }, diff --git a/package.json b/package.json index bdf7822..b8be78f 100644 --- a/package.json +++ b/package.json @@ -43,14 +43,14 @@ "publish:github": "npm config set '@fleetbase:registry' https://npm.pkg.github.com/ && npm publish" }, "dependencies": { - "@fleetbase/ember-core": "^0.2.19", - "@fleetbase/ember-ui": "^0.2.32", - "@fleetbase/fleetops-data": "^0.1.18", + "@babel/core": "^7.23.2", + "@fleetbase/ember-core": "^0.3.12", + "@fleetbase/ember-ui": "^0.3.21", + "@fleetbase/fleetops-data": "latest", "@fortawesome/ember-fontawesome": "^2.0.0", "@fortawesome/fontawesome-svg-core": "6.4.0", "@fortawesome/free-brands-svg-icons": "6.4.0", "@fortawesome/free-solid-svg-icons": "6.4.0", - "@babel/core": "^7.23.2", "broccoli-funnel": "^3.0.8", "ember-auto-import": "^2.7.4", "ember-cli-babel": "^8.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f5a725..4b881a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,17 +12,17 @@ importers: specifier: ^7.23.2 version: 7.23.2 '@fleetbase/ember-core': - specifier: ^0.2.19 - version: 0.2.19(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + specifier: ^0.3.12 + version: 0.3.12(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(eslint@8.52.0)(webpack@5.89.0) '@fleetbase/ember-ui': - specifier: ^0.2.32 - version: 0.2.32(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(postcss@8.4.35)(rollup@2.79.1)(tracked-built-ins@3.3.0)(webpack@5.89.0) + specifier: ^0.3.21 + version: 0.3.21(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(postcss@8.4.35)(rollup@2.79.1)(tracked-built-ins@3.3.0)(webpack@5.89.0) '@fleetbase/fleetops-data': - specifier: ^0.1.18 - version: 0.1.18(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + specifier: latest + version: 0.1.25(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(eslint@8.52.0)(webpack@5.89.0) '@fortawesome/ember-fontawesome': specifier: ^2.0.0 - version: 2.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0) + version: 2.0.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0) '@fortawesome/fontawesome-svg-core': specifier: 6.4.0 version: 6.4.0 @@ -89,13 +89,13 @@ importers: version: 8.2.2 ember-cli: specifier: ~5.4.1 - version: 5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6) + version: 5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(underscore@1.13.6) ember-cli-clean-css: specifier: ^3.0.0 version: 3.0.0 ember-cli-dependency-checker: specifier: ^3.3.2 - version: 3.3.2(ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6)) + version: 3.3.2(ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(underscore@1.13.6)) ember-cli-inject-live-reload: specifier: ^2.1.0 version: 2.1.0 @@ -208,14 +208,26 @@ packages: resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.23.5': resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + '@babel/core@7.23.2': resolution: {integrity: sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==} engines: {node: '>=6.9.0'} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + '@babel/eslint-parser@7.22.15': resolution: {integrity: sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} @@ -223,14 +235,29 @@ packages: '@babel/core': ^7.11.0 eslint: ^7.5.0 || ^8.0.0 + '@babel/eslint-parser@7.28.6': + resolution: {integrity: sha512-QGmsKi2PBO/MHSQk+AAgA9R6OHQr+VqnniFE0eMWZcVcfBZoA2dKn2hUsl3Csg/Plt9opRUWdY7//VXsrIlEiA==} + engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 + '@babel/generator@7.23.6': resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.22.5': resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} engines: {node: '>=6.9.0'} @@ -239,23 +266,44 @@ packages: resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + '@babel/helper-create-class-features-plugin@7.23.10': resolution: {integrity: sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-create-regexp-features-plugin@7.22.15': resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-define-polyfill-provider@0.5.0': resolution: {integrity: sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/helper-define-polyfill-provider@0.6.6': + resolution: {integrity: sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/helper-environment-visitor@7.22.20': resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} @@ -264,6 +312,10 @@ packages: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + '@babel/helper-hoist-variables@7.22.5': resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} @@ -272,36 +324,70 @@ packages: resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.22.15': resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.23.3': resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-optimise-call-expression@7.22.5': resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.22.5': resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + '@babel/helper-remap-async-to-generator@7.22.20': resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-remap-async-to-generator@7.27.1': + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-replace-supers@7.22.20': resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-simple-access@7.22.5': resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} @@ -310,6 +396,10 @@ packages: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.22.6': resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} @@ -318,22 +408,42 @@ packages: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.22.20': resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.23.5': resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + '@babel/helper-wrap-function@7.22.20': resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} engines: {node: '>=6.9.0'} + '@babel/helper-wrap-function@7.28.6': + resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} + engines: {node: '>=6.9.0'} + '@babel/helpers@7.23.9': resolution: {integrity: sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + '@babel/highlight@7.23.4': resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} engines: {node: '>=6.9.0'} @@ -343,24 +453,59 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3': resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3': resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7': resolution: {integrity: sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': + resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-proposal-class-properties@7.18.6': resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} @@ -430,6 +575,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-decorators@7.28.6': + resolution: {integrity: sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-dynamic-import@7.8.3': resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: @@ -446,12 +597,24 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-assertions@7.28.6': + resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-attributes@7.23.3': resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-meta@7.10.4': resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: @@ -510,6 +673,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} @@ -522,230 +691,482 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-generator-functions@7.23.9': resolution: {integrity: sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-generator-functions@7.29.0': + resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-to-generator@7.23.3': resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-async-to-generator@7.28.6': + resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoped-functions@7.23.3': resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoped-functions@7.27.1': + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoping@7.23.4': resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-block-scoping@7.28.6': + resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-properties@7.23.3': resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-properties@7.28.6': + resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-static-block@7.23.4': resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + '@babel/plugin-transform-classes@7.23.8': resolution: {integrity: sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-classes@7.28.6': + resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-computed-properties@7.23.3': resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-computed-properties@7.28.6': + resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-destructuring@7.23.3': resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-dotall-regex@7.23.3': resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-dotall-regex@7.28.6': + resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-duplicate-keys@7.23.3': resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-duplicate-keys@7.27.1': + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-transform-dynamic-import@7.23.4': resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-dynamic-import@7.27.1': + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-explicit-resource-management@7.28.6': + resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-exponentiation-operator@7.23.3': resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-exponentiation-operator@7.28.6': + resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-export-namespace-from@7.23.4': resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-export-namespace-from@7.27.1': + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-for-of@7.23.6': resolution: {integrity: sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-for-of@7.27.1': + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-function-name@7.23.3': resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-function-name@7.27.1': + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-json-strings@7.23.4': resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-json-strings@7.28.6': + resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-literals@7.23.3': resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-literals@7.27.1': + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-logical-assignment-operators@7.23.4': resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-logical-assignment-operators@7.28.6': + resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-member-expression-literals@7.23.3': resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-member-expression-literals@7.27.1': + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-amd@7.23.3': resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-amd@7.27.1': + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-commonjs@7.23.3': resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-systemjs@7.23.9': resolution: {integrity: sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-systemjs@7.29.0': + resolution: {integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-umd@7.23.3': resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-umd@7.27.1': + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5': resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/plugin-transform-new-target@7.23.3': resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-new-target@7.27.1': + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4': resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': + resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-numeric-separator@7.23.4': resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-numeric-separator@7.28.6': + resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-rest-spread@7.23.4': resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-rest-spread@7.28.6': + resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-super@7.23.3': resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-object-super@7.27.1': + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-catch-binding@7.23.4': resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-catch-binding@7.28.6': + resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-chaining@7.23.4': resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-optional-chaining@7.28.6': + resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-parameters@7.23.3': resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-parameters@7.27.7': + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-methods@7.23.3': resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-methods@7.28.6': + resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-private-property-in-object@7.23.4': resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.23.3': - resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} + '@babel/plugin-transform-private-property-in-object@7.28.6': + resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.23.3': - resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} + '@babel/plugin-transform-property-literals@7.23.3': + resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-reserved-words@7.23.3': - resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} + '@babel/plugin-transform-property-literals@7.27.1': + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.23.3': + resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.29.0': + resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.28.6': + resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.23.3': + resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-reserved-words@7.27.1': + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -756,42 +1177,84 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-runtime@7.29.0': + resolution: {integrity: sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-shorthand-properties@7.23.3': resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-shorthand-properties@7.27.1': + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-spread@7.23.3': resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-spread@7.28.6': + resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-sticky-regex@7.23.3': resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-sticky-regex@7.27.1': + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-template-literals@7.23.3': resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-template-literals@7.27.1': + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typeof-symbol@7.23.3': resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typeof-symbol@7.27.1': + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.23.6': resolution: {integrity: sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.4.5': resolution: {integrity: sha512-RPB/YeGr4ZrFKNwfuQRlMf2lxoCUaU01MTw39/OFE/RiL8HDjtn68BwEPft1P7JN4akyEmjGWAMNldOV7o9V2g==} peerDependencies: @@ -813,24 +1276,48 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-escapes@7.27.1': + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-property-regex@7.23.3': resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-property-regex@7.28.6': + resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-regex@7.23.3': resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-regex@7.27.1': + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-sets-regex@7.23.3': resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/plugin-transform-unicode-sets-regex@7.28.6': + resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/polyfill@7.12.1': resolution: {integrity: sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==} deprecated: 🚨 This package has been deprecated in favor of separate inclusion of a polyfill and regenerator-runtime (when needed). See the @babel/polyfill docs (https://babeljs.io/docs/en/babel-polyfill) for more information. @@ -841,6 +1328,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/preset-env@7.29.0': + resolution: {integrity: sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/preset-modules@0.1.6-no-external-plugins': resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: @@ -856,18 +1349,34 @@ packages: resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.23.9': resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.23.9': resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + '@babel/types@7.23.9': resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@cnakazawa/watch@1.0.4': resolution: {integrity: sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==} engines: {node: '>=0.1.95'} @@ -877,30 +1386,30 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@csstools/cascade-layer-name-parser@1.0.7': - resolution: {integrity: sha512-9J4aMRJ7A2WRjaRLvsMeWrL69FmEuijtiW1XlK/sG+V0UJiHVYUyvj9mY4WAXfU/hGIiGOgL8e0jJcRyaZTjDQ==} + '@csstools/cascade-layer-name-parser@1.0.13': + resolution: {integrity: sha512-MX0yLTwtZzr82sQ0zOjqimpZbzjMaK/h2pmlrLK7DCzlmiZLYFpoO94WmN1akRVo6ll/TdpHb53vihHLUMyvng==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-parser-algorithms': ^2.5.0 - '@csstools/css-tokenizer': ^2.2.3 + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 - '@csstools/color-helpers@4.0.0': - resolution: {integrity: sha512-wjyXB22/h2OvxAr3jldPB7R7kjTUEzopvjitS8jWtyd8fN6xJ8vy1HnHu0ZNfEkqpBJgQ76Q+sBDshWcMvTa/w==} + '@csstools/color-helpers@4.2.1': + resolution: {integrity: sha512-CEypeeykO9AN7JWkr1OEOQb0HRzZlPWGwV0Ya6DuVgFdDi6g3ma/cPZ5ZPZM4AWQikDpq/0llnGGlIL+j8afzw==} engines: {node: ^14 || ^16 || >=18} - '@csstools/css-calc@1.1.6': - resolution: {integrity: sha512-YHPAuFg5iA4qZGzMzvrQwzkvJpesXXyIUyaONflQrjtHB+BcFFbgltJkIkb31dMGO4SE9iZFA4HYpdk7+hnYew==} + '@csstools/css-calc@1.2.4': + resolution: {integrity: sha512-tfOuvUQeo7Hz+FcuOd3LfXVp+342pnWUJ7D2y8NUpu1Ww6xnTbHLpz018/y6rtbHifJ3iIEf9ttxXd8KG7nL0Q==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-parser-algorithms': ^2.5.0 - '@csstools/css-tokenizer': ^2.2.3 + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 - '@csstools/css-color-parser@1.5.1': - resolution: {integrity: sha512-x+SajGB2paGrTjPOUorGi8iCztF008YMKXTn+XzGVDBEIVJ/W1121pPerpneJYGOe1m6zWLPLnzOPaznmQxKFw==} + '@csstools/css-color-parser@2.0.5': + resolution: {integrity: sha512-lRZSmtl+DSjok3u9hTWpmkxFZnz7stkbZxzKc08aDUsdrWwhSgWo8yq9rq9DaFUtbAyAq2xnH92fj01S+pwIww==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-parser-algorithms': ^2.5.0 - '@csstools/css-tokenizer': ^2.2.3 + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 '@csstools/css-parser-algorithms@2.5.0': resolution: {integrity: sha512-abypo6m9re3clXA00eu5syw+oaPHbJTPapu9C4pzNsJ4hdZDzushT50Zhu+iIYXgEe1CxnRMn7ngsbV+MLrlpQ==} @@ -908,10 +1417,27 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^2.2.3 + '@csstools/css-parser-algorithms@2.7.1': + resolution: {integrity: sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-tokenizer': ^2.4.1 + '@csstools/css-tokenizer@2.2.3': resolution: {integrity: sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg==} engines: {node: ^14 || ^16 || >=18} + '@csstools/css-tokenizer@2.4.1': + resolution: {integrity: sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==} + engines: {node: ^14 || ^16 || >=18} + + '@csstools/media-query-list-parser@2.1.13': + resolution: {integrity: sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 + '@csstools/media-query-list-parser@2.1.7': resolution: {integrity: sha512-lHPKJDkPUECsyAvD60joYfDmp8UERYxHGkFfyLJFTVK/ERJe0sVlIFLXU5XFxdjNDTerp5L4KeaKG+Z5S94qxQ==} engines: {node: ^14 || ^16 || >=18} @@ -919,56 +1445,62 @@ packages: '@csstools/css-parser-algorithms': ^2.5.0 '@csstools/css-tokenizer': ^2.2.3 - '@csstools/postcss-cascade-layers@4.0.2': - resolution: {integrity: sha512-PqM+jvg5T2tB4FHX+akrMGNWAygLupD4FNUjcv4PSvtVuWZ6ISxuo37m4jFGU7Jg3rCfloGzKd0+xfr5Ec3vZQ==} + '@csstools/postcss-cascade-layers@4.0.6': + resolution: {integrity: sha512-Xt00qGAQyqAODFiFEJNkTpSUz5VfYqnDLECdlA/Vv17nl/OIV5QfTRHGAXrBGG5YcJyHpJ+GF9gF/RZvOQz4oA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-color-function@3.0.19': + resolution: {integrity: sha512-d1OHEXyYGe21G3q88LezWWx31ImEDdmINNDy0LyLNN9ChgN2bPxoubUPiHf9KmwypBMaHmNcMuA/WZOKdZk/Lg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-color-function@3.0.9': - resolution: {integrity: sha512-6Hbkw/4k73UH121l4LG+LNLKSvrfHqk3GHHH0A6/iFlD0xGmsWAr80Jd0VqXjfYbUTOGmJTOMMoxv3jvNxt1uw==} + '@csstools/postcss-color-mix-function@2.0.19': + resolution: {integrity: sha512-mLvQlMX+keRYr16AuvuV8WYKUwF+D0DiCqlBdvhQ0KYEtcQl9/is9Ssg7RcIys8x0jIn2h1zstS4izckdZj9wg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-color-mix-function@2.0.9': - resolution: {integrity: sha512-fs1SOWJ/44DQSsDeJP+rxAkP2MYkCg6K4ZB8qJwFku2EjurgCAPiPZJvC6w94T1hBBinJwuMfT9qvvvniXyVgw==} + '@csstools/postcss-content-alt-text@1.0.0': + resolution: {integrity: sha512-SkHdj7EMM/57GVvSxSELpUg7zb5eAndBeuvGwFzYtU06/QXJ/h9fuK7wO5suteJzGhm3GDF/EWPCdWV2h1IGHQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-exponential-functions@1.0.3': - resolution: {integrity: sha512-IfGtEg3eC4b8Nd/kPgO3SxgKb33YwhHVsL0eJ3UYihx6fzzAiZwNbWmVW9MZTQjZ5GacgKxa4iAHikGvpwuIjw==} + '@csstools/postcss-exponential-functions@1.0.9': + resolution: {integrity: sha512-x1Avr15mMeuX7Z5RJUl7DmjhUtg+Amn5DZRD0fQ2TlTFTcJS8U1oxXQ9e5mA62S2RJgUU6db20CRoJyDvae2EQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-font-format-keywords@3.0.1': - resolution: {integrity: sha512-D1lcG2sfotTq6yBEOMV3myFxJLT10F3DLYZJMbiny5YToqzHWodZen8WId3UTimm0mEHitXqAUNL5jdd6RzVdA==} + '@csstools/postcss-font-format-keywords@3.0.2': + resolution: {integrity: sha512-E0xz2sjm4AMCkXLCFvI/lyl4XO6aN1NCSMMVEOngFDJ+k2rDwfr6NDjWljk1li42jiLNChVX+YFnmfGCigZKXw==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-gamut-mapping@1.0.2': - resolution: {integrity: sha512-zf9KHGM2PTuJEm4ZYg4DTmzCir38EbZBzlMPMbA4jbhLDqXHkqwnQ+Z5+UNrU8y6seVu5B4vzZmZarTFQwe+Ig==} + '@csstools/postcss-gamut-mapping@1.0.11': + resolution: {integrity: sha512-KrHGsUPXRYxboXmJ9wiU/RzDM7y/5uIefLWKFSc36Pok7fxiPyvkSHO51kh+RLZS1W5hbqw9qaa6+tKpTSxa5g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-gradients-interpolation-method@4.0.9': - resolution: {integrity: sha512-PSqR6QH7h3ggOl8TsoH73kbwYTKVQjAJauGg6nDKwaGfi5IL5StV//ehrv1C7HuPsHixMTc9YoAuuv1ocT20EQ==} + '@csstools/postcss-gradients-interpolation-method@4.0.20': + resolution: {integrity: sha512-ZFl2JBHano6R20KB5ZrB8KdPM2pVK0u+/3cGQ2T8VubJq982I2LSOvQ4/VtxkAXjkPkk1rXt4AD1ni7UjTZ1Og==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-hwb-function@3.0.8': - resolution: {integrity: sha512-CRQEG372Hivmt17rm/Ho22hBQI9K/a6grzGQ21Zwc7dyspmyG0ibmPIW8hn15vJmXqWGeNq7S+L2b8/OrU7O5A==} + '@csstools/postcss-hwb-function@3.0.18': + resolution: {integrity: sha512-3ifnLltR5C7zrJ+g18caxkvSRnu9jBBXCYgnBznRjxm6gQJGnnCO9H6toHfywNdNr/qkiVf2dymERPQLDnjLRQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-ic-unit@3.0.3': - resolution: {integrity: sha512-MpcmIL0/uMm/cFWh5V/9nbKKJ7jRr2qTYW5Q6zoE6HZ6uzOBJr2KRERv5/x8xzEBQ1MthDT7iP1EBp9luSQy7g==} + '@csstools/postcss-ic-unit@3.0.7': + resolution: {integrity: sha512-YoaNHH2wNZD+c+rHV02l4xQuDpfR8MaL7hD45iJyr+USwvr0LOheeytJ6rq8FN6hXBmEeoJBeXXgGmM8fkhH4g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -979,8 +1511,14 @@ packages: peerDependencies: postcss: ^8.4 - '@csstools/postcss-is-pseudo-class@4.0.4': - resolution: {integrity: sha512-vTVO/uZixpTVAOQt3qZRUFJ/K1L03OfNkeJ8sFNDVNdVy/zW0h1L5WT7HIPMDUkvSrxQkFaCCybTZkUP7UESlQ==} + '@csstools/postcss-is-pseudo-class@4.0.8': + resolution: {integrity: sha512-0aj591yGlq5Qac+plaWCbn5cpjs5Sh0daovYUKJUOMjIp70prGH/XPLp7QjxtbFXz3CTvb0H9a35dpEuIuUi3Q==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-light-dark-function@1.0.8': + resolution: {integrity: sha512-x0UtpCyVnERsplUeoaY6nEtp1HxTf4lJjoK/ULEm40DraqFfUdUSt76yoOyX5rGY6eeOUOkurHyYlFHVKv/pew==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -1009,26 +1547,26 @@ packages: peerDependencies: postcss: ^8.4 - '@csstools/postcss-logical-viewport-units@2.0.5': - resolution: {integrity: sha512-2fjSamKN635DSW6fEoyNd2Bkpv3FVblUpgk5cpghIgPW1aDHZE2SYfZK5xQALvjMYZVjfqsD5EbXA7uDVBQVQA==} + '@csstools/postcss-logical-viewport-units@2.0.11': + resolution: {integrity: sha512-ElITMOGcjQtvouxjd90WmJRIw1J7KMP+M+O87HaVtlgOOlDt1uEPeTeii8qKGe2AiedEp0XOGIo9lidbiU2Ogg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-media-minmax@1.1.2': - resolution: {integrity: sha512-7qTRTJxW96u2yiEaTep1+8nto1O/rEDacewKqH+Riq5E6EsHTOmGHxkB4Se5Ic5xgDC4I05lLZxzzxnlnSypxA==} + '@csstools/postcss-media-minmax@1.1.8': + resolution: {integrity: sha512-KYQCal2i7XPNtHAUxCECdrC7tuxIWQCW+s8eMYs5r5PaAiVTeKwlrkRS096PFgojdNCmHeG0Cb7njtuNswNf+w==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.5': - resolution: {integrity: sha512-XHMPasWYPWa9XaUHXU6Iq0RLfoAI+nvGTPj51hOizNsHaAyFiq2SL4JvF1DU8lM6B70+HVzKM09Isbyrr755Bw==} + '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.11': + resolution: {integrity: sha512-YD6jrib20GRGQcnOu49VJjoAnQ/4249liuz7vTpy/JfgqQ1Dlc5eD4HPUMNLOw9CWey9E6Etxwf/xc/ZF8fECA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-nested-calc@3.0.1': - resolution: {integrity: sha512-bwwababZpWRm0ByHaWBxTsDGTMhZKmtUNl3Wt0Eom8AY7ORgXx5qF9SSk1vEFrCi+HOfJT6M6W5KPgzXuQNRwQ==} + '@csstools/postcss-nested-calc@3.0.2': + resolution: {integrity: sha512-ySUmPyawiHSmBW/VI44+IObcKH0v88LqFe0d09Sb3w4B1qjkaROc6d5IA3ll9kjD46IIX/dbO5bwFN/swyoyZA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -1039,20 +1577,20 @@ packages: peerDependencies: postcss: ^8.4 - '@csstools/postcss-oklab-function@3.0.9': - resolution: {integrity: sha512-l639gpcBfL3ogJe+og1M5FixQn8iGX8+29V7VtTSCUB37VzpzOC05URfde7INIdiJT65DkHzgdJ64/QeYggU8A==} + '@csstools/postcss-oklab-function@3.0.19': + resolution: {integrity: sha512-e3JxXmxjU3jpU7TzZrsNqSX4OHByRC3XjItV3Ieo/JEQmLg5rdOL4lkv/1vp27gXemzfNt44F42k/pn0FpE21Q==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-progressive-custom-properties@3.0.3': - resolution: {integrity: sha512-WipTVh6JTMQfeIrzDV4wEPsV9NTzMK2jwXxyH6CGBktuWdivHnkioP/smp1x/0QDPQyx7NTS14RB+GV3zZZYEw==} + '@csstools/postcss-progressive-custom-properties@3.3.0': + resolution: {integrity: sha512-W2oV01phnILaRGYPmGFlL2MT/OgYjQDrL9sFlbdikMFi6oQkFki9B86XqEWR7HCsTZFVq7dbzr/o71B75TKkGg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-relative-color-syntax@2.0.9': - resolution: {integrity: sha512-2UoaRd2iIuzUGtYgteN5fJ0s+OfCiV7PvCnw8MCh3om8+SeVinfG8D5sqBOvImxFVfrp6k60XF5RFlH6oc//fg==} + '@csstools/postcss-relative-color-syntax@2.0.19': + resolution: {integrity: sha512-MxUMSNvio1WwuS6WRLlQuv6nNPXwIWUFzBBAvL/tBdWfiKjiJnAa6eSSN5gtaacSqUkQ/Ce5Z1OzLRfeaWhADA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -1063,20 +1601,20 @@ packages: peerDependencies: postcss: ^8.4 - '@csstools/postcss-stepped-value-functions@3.0.4': - resolution: {integrity: sha512-gyNQ2YaOVXPqLR737XtReRPVu7DGKBr9JBDLoiH1T+N1ggV3r4HotRCOC1l6rxVC0zOuU1KiOzUn9Z5W838/rg==} + '@csstools/postcss-stepped-value-functions@3.0.10': + resolution: {integrity: sha512-MZwo0D0TYrQhT5FQzMqfy/nGZ28D1iFtpN7Su1ck5BPHS95+/Y5O9S4kEvo76f2YOsqwYcT8ZGehSI1TnzuX2g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-text-decoration-shorthand@3.0.4': - resolution: {integrity: sha512-yUZmbnUemgQmja7SpOZeU45+P49wNEgQguRdyTktFkZsHf7Gof+ZIYfvF6Cm+LsU1PwSupy4yUeEKKjX5+k6cQ==} + '@csstools/postcss-text-decoration-shorthand@3.0.7': + resolution: {integrity: sha512-+cptcsM5r45jntU6VjotnkC9GteFR7BQBfZ5oW7inLCxj7AfLGAzMbZ60hKTP13AULVZBdxky0P8um0IBfLHVA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - '@csstools/postcss-trigonometric-functions@3.0.4': - resolution: {integrity: sha512-qj4Cxth6c38iNYzfJJWAxt8jsLrZaMVmbfGDDLOlI2YJeZoC3A5Su6/Kr7oXaPFRuspUu+4EQHngOktqVHWfVg==} + '@csstools/postcss-trigonometric-functions@3.0.10': + resolution: {integrity: sha512-G9G8moTc2wiad61nY5HfvxLiM/myX0aYK4s1x8MQlPH29WDPxHQM7ghGgvv2qf2xH+rrXhztOmjGHJj4jsEqXw==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -1087,12 +1625,30 @@ packages: peerDependencies: postcss: ^8.4 + '@csstools/selector-resolve-nested@1.1.0': + resolution: {integrity: sha512-uWvSaeRcHyeNenKg8tp17EVDRkpflmdyvbE0DHo6D/GdBb6PDnCYYU6gRpXhtICMGMcahQmj2zGxwFM/WC8hCg==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss-selector-parser: ^6.0.13 + '@csstools/selector-specificity@3.0.1': resolution: {integrity: sha512-NPljRHkq4a14YzZ3YD406uaxh7s0g6eAq3L9aLOWywoqe8PkYamAvtsh7KNX6c++ihDrJ0RiU+/z7rGnhlZ5ww==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss-selector-parser: ^6.0.13 + '@csstools/selector-specificity@3.1.1': + resolution: {integrity: sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss-selector-parser: ^6.0.13 + + '@csstools/utilities@1.0.0': + resolution: {integrity: sha512-tAgvZQe/t2mlvpNosA4+CkMiZ2azISW5WPAcdSalZlEjQvUfghHxfQcrCiK/7/CrfAWVxyM88kGFYO82heIGDg==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.4 + '@ember-data/adapter@4.12.5': resolution: {integrity: sha512-YWCjBga9h59q3iBqLONxi68AjNZtKmxQ/uB7e8uSv7czOXGQKpzONlTb68jyMJ687qpg0RWebxLBlBU5yPxq1Q==} engines: {node: 16.* || >= 18.*} @@ -1240,6 +1796,10 @@ packages: resolution: {integrity: sha512-bb9h95ktG2wKY9+ja1sdsFBdOms2lB19VWs8wmNpzgHv1NCetonBoV5jHBV4DHt0uS1tg9z66cZqhUVlYs96KQ==} engines: {node: 10.* || 12.* || >= 14.*} + '@embroider/addon-shim@1.10.2': + resolution: {integrity: sha512-EfI9cJ5/3QSUJtwm7x1MXrx3TEa2p7RNgSHefy7fvGm8/DP1xUFL25nST1NaHbHcqR1UhMlrTtv5iUIDoVzeQQ==} + engines: {node: 12.* || 14.* || >= 16} + '@embroider/addon-shim@1.8.3': resolution: {integrity: sha512-7pyHwzT6ESXc3nZsB8rfnirLkUhQWdvj6CkYH+0MUPN74mX4rslf7pnBqZE/KZkW3uBIaBYvU8fxi0hcKC/Paw==} engines: {node: 12.* || 14.* || >= 16} @@ -1248,10 +1808,6 @@ packages: resolution: {integrity: sha512-JGOQNRj3UR0NdWEg8MsM2eqPLncEwSB1IX+rwntIj22TEKj8biqx7GDgSbeH+ZedijmCh354Hf2c5rthrdzUAw==} engines: {node: 12.* || 14.* || >= 16} - '@embroider/addon-shim@1.8.9': - resolution: {integrity: sha512-qyN64T1jMHZ99ihlk7VFHCWHYZHLE1DOdHi0J7lmn5waV1DoW7gD8JLi1i7FregzXtKhbDc7shyEmTmWPTs8MQ==} - engines: {node: 12.* || 14.* || >= 16} - '@embroider/addon@0.30.0': resolution: {integrity: sha512-hBgskhX38RMIyHcnUpRt+KbddLMPLVOFdLp4qhv7Vs881SPDwsbo7pir4KpILmnoqcvBMh1MCVY970tYaAyMcQ==} engines: {node: 10.* || >= 12} @@ -1265,6 +1821,19 @@ packages: '@glint/template': optional: true + '@embroider/macros@1.20.0': + resolution: {integrity: sha512-hEFKhkDJanvL8+E2UBw5uHAcYwhGXRMtOKAHfq6kMvXB5ziPWRYvyBsynF05a19TioZ4a9UQ29uqXGHrobPu+Q==} + engines: {node: 12.* || 14.* || >= 16} + peerDependencies: + '@glint/template': ^1.0.0 + peerDependenciesMeta: + '@glint/template': + optional: true + + '@embroider/reverse-exports@0.2.0': + resolution: {integrity: sha512-WFsw8nQpHZiWGEDYpa/A79KEFfTisqteXbY+jg9eZiww1r1G+LZvsmdszDp86TkotUSCqrMbK/ewn0jR1CJmqg==} + engines: {node: 12.* || 14.* || >= 16} + '@embroider/shared-internals@1.8.3': resolution: {integrity: sha512-N5Gho6Qk8z5u+mxLCcMYAoQMbN4MmH+z2jXwQHVs859bxuZTxwF6kKtsybDAASCtd2YGxEmzcc1Ja/wM28824w==} engines: {node: 12.* || 14.* || >= 16} @@ -1273,8 +1842,12 @@ packages: resolution: {integrity: sha512-jNDJ9YlV6Qp9Na9v17qirUewVuq6T0t32nn+bbnFlCRTvmllKluZdYPSC5RuRnEZKTloVYRSF0+f1rgkTIEvxQ==} engines: {node: 12.* || 14.* || >= 16} - '@embroider/shared-internals@2.7.0': - resolution: {integrity: sha512-ISaVmGvTI+y7QRwo+Qku9mDm1p35DV4Gi7luSoizL88PlC2UZHuK6nOEEF2hjsqUnHwmEv0jd3/tpOCohwgk6w==} + '@embroider/shared-internals@2.9.2': + resolution: {integrity: sha512-d96ub/WkS1Gx6dRDxZ0mCRPwFAHIMlMr2iti6uTYxTFzC85Wgt6j7bYr6ppkEuwEwKQVyzKRT0kTsJz6P74caQ==} + engines: {node: 12.* || 14.* || >= 16} + + '@embroider/shared-internals@3.0.2': + resolution: {integrity: sha512-/SusdG+zgosc3t+9sPFVKSFOYyiSgLfXOT6lYNWoG1YtnhWDxlK4S8leZ0jhcVjemdaHln5rTyxCnq8oFLxqpQ==} engines: {node: 12.* || 14.* || >= 16} '@embroider/test-setup@3.0.2': @@ -1305,6 +1878,19 @@ packages: '@glint/template': optional: true + '@embroider/util@1.13.5': + resolution: {integrity: sha512-rHhGUzAQ5iOr5Swvk7yaarVe5SJtcjK2t/C8ts9agWfhTq4DVfy8+axF0KOf1jALRiJao3l9ALRGd6letKw2ZQ==} + engines: {node: 12.* || 14.* || >= 16} + peerDependencies: + '@glint/environment-ember-loose': ^1.0.0 + '@glint/template': ^1.0.0 + ember-source: '*' + peerDependenciesMeta: + '@glint/environment-ember-loose': + optional: true + '@glint/template': + optional: true + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1329,26 +1915,26 @@ packages: peerDependencies: ember-source: '>= 4.0.0' - '@fleetbase/ember-core@0.2.19': - resolution: {integrity: sha512-xXRBp+dqZ975bPyAxvxlw1K+kcVxu1XZ9/Db+eySNPS2ua+wswg8+KyegnU6hkJflDgFjo7xTqBL30WVrjRUiQ==} + '@fleetbase/ember-core@0.3.12': + resolution: {integrity: sha512-XvX8ND36FOKvNPuXvo5usDlSrH1PkfpWrRGtlU4/bDkYZBcNUH3jJAu4Wfl8vfv1Tg232bMpHjgCYUgDlu1YUg==} engines: {node: '>= 18'} - '@fleetbase/ember-ui@0.2.32': - resolution: {integrity: sha512-+6lPyziomGKA405ILe6DSY9tBfehMTO1pSpe/8ZUQrez06wda6Ci4C2DCNd5vWmOlOtiC91cRKLUcN6Myx9dwQ==} + '@fleetbase/ember-ui@0.3.21': + resolution: {integrity: sha512-HodjXkqg29/omCxmf4jwPlZcLhbjaLqDIVTprB9+c65Ekzsca2ag51dmpjjUIJisaZQ+OtHHNpOU0pVAYgaqKA==} engines: {node: '>= 18'} - '@fleetbase/fleetops-data@0.1.18': - resolution: {integrity: sha512-SBiL992igloYgEGMbUX65uW95nv8k32u2QSoqVm7HrWfhCwMEeHubEOA916otDkBalkHNSE6QgWigaJDMNnW4A==} + '@fleetbase/fleetops-data@0.1.25': + resolution: {integrity: sha512-uCX/qB4ANDGNN+EM1vdsVc4inprGEwj1dT0G5OTYKsFaHL3CWOeXsOg8qSa5EDClqxIodadx6stB+dSwrhYowg==} engines: {node: '>= 18'} - '@floating-ui/core@1.6.0': - resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} + '@floating-ui/core@1.7.4': + resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} - '@floating-ui/dom@1.6.3': - resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} + '@floating-ui/dom@1.7.5': + resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} - '@floating-ui/utils@0.2.1': - resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} '@formatjs/ecma402-abstract@1.18.2': resolution: {integrity: sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==} @@ -1401,18 +1987,18 @@ packages: resolution: {integrity: sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==} engines: {node: '>=6'} - '@fullcalendar/core@6.1.10': - resolution: {integrity: sha512-oTXGJSAGpCf1oY+CKp5qYjMHkJCPBkJ3SHitl63n8Q6xKeiwQ4EF6Au451euUovREwJpLmD1AyZrCnWmtB9AVg==} + '@fullcalendar/core@6.1.20': + resolution: {integrity: sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==} - '@fullcalendar/daygrid@6.1.10': - resolution: {integrity: sha512-Z4GRm1IyHKgxXFTWGcEI0nTsvYOIkpE0aMt3/o3ER2SZkF+hfwcDFhtj0c9+WhMjXFIWYeoTnA9rUOY7Zl/nxA==} + '@fullcalendar/daygrid@6.1.20': + resolution: {integrity: sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ==} peerDependencies: - '@fullcalendar/core': ~6.1.10 + '@fullcalendar/core': ~6.1.20 - '@fullcalendar/interaction@6.1.10': - resolution: {integrity: sha512-aZRlwCpmDasq2RNeWV0ub20Uevare9Cb6iMlxCacx0fhOC14H28G9d1FsduJIecInL84SPGwt5ItqAYMsWv7zw==} + '@fullcalendar/interaction@6.1.20': + resolution: {integrity: sha512-p6txmc5txL0bMiPaJxe2ip6o0T384TyoD2KGdsU6UjZ5yoBlaY+dg7kxfnYKpYMzEJLG58n+URrHr2PgNL2fyA==} peerDependencies: - '@fullcalendar/core': ~6.1.10 + '@fullcalendar/core': ~6.1.20 '@glimmer/compiler@0.84.3': resolution: {integrity: sha512-cj9sGlnvExP9httxY6ZMivJRGulyaZ31DddCYB5h6LxupR4Nk2d1nAJCWPLsvuQJ8qR+eYw0y9aiY/VeT0krpQ==} @@ -1439,6 +2025,9 @@ packages: '@glimmer/interfaces@0.84.3': resolution: {integrity: sha512-dk32ykoNojt0mvEaIW6Vli5MGTbQo58uy3Epj7ahCgTHmWOKuw/0G83f2UmFprRwFx689YTXG38I/vbpltEjzg==} + '@glimmer/interfaces@0.94.6': + resolution: {integrity: sha512-sp/1WePvB/8O+jrcUHwjboNPTKrdGicuHKA9T/lh0vkYK2qM5Xz4i25lQMQ38tEMiw7KixrjHiTUiaXRld+IwA==} + '@glimmer/low-level@0.78.2': resolution: {integrity: sha512-0S6TWOOd0fzLLysw1pWZN0TgasaHmYs1Sjz9Til1mTByIXU1S+1rhdyr2veSQPO/aRjPuEQyKXZQHvx23Zax6w==} @@ -1466,6 +2055,9 @@ packages: '@glimmer/syntax@0.84.3': resolution: {integrity: sha512-ioVbTic6ZisLxqTgRBL2PCjYZTFIwobifCustrozRU2xGDiYvVIL0vt25h2c1ioDsX59UgVlDkIK4YTAQQSd2A==} + '@glimmer/syntax@0.95.0': + resolution: {integrity: sha512-W/PHdODnpONsXjbbdY9nedgIHpglMfOzncf/moLVrKIcCfeQhw2vG07Rs/YW8KeJCgJRCLkQsi+Ix7XvrurGAg==} + '@glimmer/tracking@1.1.2': resolution: {integrity: sha512-cyV32zsHh+CnftuRX84ALZpd2rpbDrhLhJnTXn9W//QpqdRZ5rdMsxSY9fOsj0CKEc706tmEU299oNnDc0d7tA==} @@ -1475,6 +2067,9 @@ packages: '@glimmer/util@0.84.3': resolution: {integrity: sha512-qFkh6s16ZSRuu2rfz3T4Wp0fylFj3HBsONGXQcrAdZjdUaIS6v3pNj6mecJ71qRgcym9Hbaq/7/fefIwECUiKw==} + '@glimmer/util@0.94.8': + resolution: {integrity: sha512-HfCKeZ74clF9BsPDBOqK/yRNa/ke6niXFPM6zRn9OVYw+ZAidLs7V8He/xljUHlLRL322kaZZY8XxRW7ALEwyg==} + '@glimmer/validator@0.44.0': resolution: {integrity: sha512-i01plR0EgFVz69GDrEuFgq1NheIjZcyTy3c7q+w7d096ddPVeVcRzU3LKaqCfovvLJ+6lJx40j45ecycASUUyw==} @@ -1490,9 +2085,16 @@ packages: '@glimmer/wire-format@0.84.3': resolution: {integrity: sha512-aZVfQhqv4k7tTo2vwjy+b4mAxKt7cHH75JR3zAeCilimApa+yYTYUyY73NDNSUVbelgAlQ5s6vTiMSQ55WwVow==} + '@glimmer/wire-format@0.94.8': + resolution: {integrity: sha512-A+Cp5m6vZMAEu0Kg/YwU2dJZXyYxVJs2zI57d3CP6NctmX7FsT8WjViiRUmt5abVmMmRH5b8BUovqY6GSMAdrw==} + '@handlebars/parser@2.0.0': resolution: {integrity: sha512-EP9uEDZv/L5Qh9IWuMUGJRfwhXJ4h1dqKTT4/3+tY0eu7sPis7xh23j61SYUnNF4vqCQvvUXpDo9Bh/+q1zASA==} + '@handlebars/parser@2.2.2': + resolution: {integrity: sha512-n/SZW+12rwikx/f8YcSv9JCi5p9vn1Bnts9ZtVvfErG4h0gbjHI1H1ZMhVUnaOC7yzFc6PtsCKIK8XeTnL90Gw==} + engines: {node: ^18 || ^20 || ^22 || >=24} + '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -1508,10 +2110,16 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.3': resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1526,11 +2134,17 @@ packages: '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.22': resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} - '@kurkle/color@0.3.2': - resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@kurkle/color@0.3.4': + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} '@lint-todo/utils@13.1.1': resolution: {integrity: sha512-F5z53uvRIF4dYfFfJP3a2Cqg+4P1dgJchJsFnsZE0eZp0LK8X7g2J0CsJHRgns+skpXOlM7n5vFGwkWCWj8qJg==} @@ -1625,199 +2239,195 @@ packages: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} engines: {node: '>=6'} - '@tailwindcss/forms@0.5.7': - resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==} + '@tailwindcss/forms@0.5.11': + resolution: {integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==} peerDependencies: - tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' - '@tiptap/core@2.8.0': - resolution: {integrity: sha512-xsqDI4BNzYRWRtBq7+/38ThhqEr7uG9Njip1x+9/wgR3vWPBFnBkYJTz6jSxS35NRE6BSnERm4/B/vrLuY1Hdw==} + '@tiptap/core@2.27.2': + resolution: {integrity: sha512-ABL1N6eoxzDzC1bYvkMbvyexHacszsKdVPYqhl5GwHLOvpZcv9VE9QaKwDILTyz5voCA0lGcAAXZp+qnXOk5lQ==} peerDependencies: '@tiptap/pm': ^2.7.0 - '@tiptap/extension-blockquote@2.8.0': - resolution: {integrity: sha512-m3CKrOIvV7fY1Ak2gYf5LkKiz6AHxHpg6wxfVaJvdBqXgLyVtHo552N+A4oSHOSRbB4AG9EBQ2NeBM8cdEQ4MA==} + '@tiptap/extension-blockquote@2.27.2': + resolution: {integrity: sha512-oIGZgiAeA4tG3YxbTDfrmENL4/CIwGuP3THtHsNhwRqwsl9SfMk58Ucopi2GXTQSdYXpRJ0ahE6nPqB5D6j/Zw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bold@2.8.0': - resolution: {integrity: sha512-U1YkZBxDkSLNvPNiqxB5g42IeJHr27C7zDb/yGQN2xL4UBeg4O9xVhCFfe32f6tLwivSL0dar4ScElpaCJuqow==} + '@tiptap/extension-bold@2.27.2': + resolution: {integrity: sha512-bR7J5IwjCGQ0s3CIxyMvOCnMFMzIvsc5OVZKscTN5UkXzFsaY6muUAIqtKxayBUucjtUskm5qZowJITCeCb1/A==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bullet-list@2.8.0': - resolution: {integrity: sha512-H4O2X0ozbc/ce9/XF1H98sqWVUdtt7jzy7hMBunwmY8ZxI4dHtcRkeg81CZbpKTqOqRrMCLWjE3M2tgiDXrDkA==} + '@tiptap/extension-bullet-list@2.27.2': + resolution: {integrity: sha512-gmFuKi97u5f8uFc/GQs+zmezjiulZmFiDYTh3trVoLRoc2SAHOjGEB7qxdx7dsqmMN7gwiAWAEVurLKIi1lnnw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-list-item': ^2.7.0 - '@tiptap/extension-text-style': ^2.7.0 - '@tiptap/extension-code-block@2.8.0': - resolution: {integrity: sha512-POuA5Igx+Dto0DTazoBFAQTj/M/FCdkqRVD9Uhsxhv49swPyANTJRr05vgbgtHB+NDDsZfCawVh7pI0IAD/O0w==} + '@tiptap/extension-code-block@2.27.2': + resolution: {integrity: sha512-KgvdQHS4jXr79aU3wZOGBIZYYl9vCB7uDEuRFV4so2rYrfmiYMw3T8bTnlNEEGe4RUeAms1i4fdwwvQp9nR1Dw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-code@2.8.0': - resolution: {integrity: sha512-VSFn3sFF6qPpOGkXFhik8oYRH5iByVJpFEFd/duIEftmS0MdPzkbSItOpN3mc9xsJ5dCX80LYaResSj5hr5zkA==} + '@tiptap/extension-code@2.27.2': + resolution: {integrity: sha512-7X9AgwqiIGXoZX7uvdHQsGsjILnN/JaEVtqfXZnPECzKGaWHeK/Ao4sYvIIIffsyZJA8k5DC7ny2/0sAgr2TuA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-color@2.8.0': - resolution: {integrity: sha512-b0ZIDaZKTDVdTb0PMgtOiPzgCkYhvDldjzdWyPLsjWup5x9/zPasH5X/2SfMuwtjt+cKj6YBPveJjF7w5ApK7w==} + '@tiptap/extension-color@2.27.2': + resolution: {integrity: sha512-sOKCP8/2V3sRM3FdWgMe1lFE5ewsWNCRafiVoujS1+TTHGCj4jw6W+LiumBUk7cRI8kXW/rqGWVC4RVdknYUCA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/extension-text-style': ^2.7.0 - '@tiptap/extension-document@2.8.0': - resolution: {integrity: sha512-mp7Isx1sVc/ifeW4uW/PexGQ9exN3NRUOebSpnLfqXeWYk4y1RS1PA/3+IHkOPVetbnapgPjFx/DswlCP3XLjA==} + '@tiptap/extension-document@2.27.2': + resolution: {integrity: sha512-CFhAYsPnyYnosDC4639sCJnBUnYH4Cat9qH5NZWHVvdgtDwu8GZgZn2eSzaKSYXWH1vJ9DSlCK+7UyC3SNXIBA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-dropcursor@2.8.0': - resolution: {integrity: sha512-rAFvx44YuT6dtS1c+ALw0ROAGI16l5L1HxquL4hR1gtxDcTieST5xhw5bkshXlmrlfotZXPrhokzqA7qjhZtJw==} + '@tiptap/extension-dropcursor@2.27.2': + resolution: {integrity: sha512-oEu/OrktNoQXq1x29NnH/GOIzQZm8ieTQl3FK27nxfBPA89cNoH4mFEUmBL5/OFIENIjiYG3qWpg6voIqzswNw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-font-family@2.8.0': - resolution: {integrity: sha512-v35PeyC6+iIRXnXDDg8xJVCEEtRcGqcUvm5lO9kKqBcoMg20BXF1+mhY3pSigQ1VMtZfh9XO+BHlfTDC02S9QQ==} + '@tiptap/extension-font-family@2.27.2': + resolution: {integrity: sha512-Lc3fAF/t3QXuG5AiOjGiCoyxJH7QyAOj5P+X4O6NfFtHST2wxoqIKqnlXkROv+g49Th/ypVGQ/z47wb6EG4iQg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/extension-text-style': ^2.7.0 - '@tiptap/extension-gapcursor@2.8.0': - resolution: {integrity: sha512-Be1LWCmvteQInOnNVN+HTqc1XWsj1bCl+Q7et8qqNjtGtTaCbdCp8ppcH1SKJxNTM/RLUtPyJ8FDgOTj51ixCA==} + '@tiptap/extension-gapcursor@2.27.2': + resolution: {integrity: sha512-/c9VF1HBxj+AP54XGVgCmD9bEGYc5w5OofYCFQgM7l7PB1J00A4vOke0oPkHJnqnOOyPlFaxO/7N6l3XwFcnKA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-hard-break@2.8.0': - resolution: {integrity: sha512-vqiIfviNiCmy/pJTHuDSCAGL2O4QDEdDmAvGJu8oRmElUrnlg8DbJUfKvn6DWQHNSQwRb+LDrwWlzAYj1K9u6A==} + '@tiptap/extension-hard-break@2.27.2': + resolution: {integrity: sha512-kSRVGKlCYK6AGR0h8xRkk0WOFGXHIIndod3GKgWU49APuIGDiXd8sziXsSlniUsWmqgDmDXcNnSzPcV7AQ8YNg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-heading@2.8.0': - resolution: {integrity: sha512-4inWgrTPiqlivPmEHFOM5ck2UsmOsbKKPtqga6bALvWPmCv24S6/EBwFp8Jz4YABabXDnkviihmGu0LpP9D69w==} + '@tiptap/extension-heading@2.27.2': + resolution: {integrity: sha512-iM3yeRWuuQR/IRQ1djwNooJGfn9Jts9zF43qZIUf+U2NY8IlvdNsk2wTOdBgh6E0CamrStPxYGuln3ZS4fuglw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-highlight@2.8.0': - resolution: {integrity: sha512-vyqX7D449nuARhI0AyRqtIZReFg3sfc/U/q1p3JOjtUoW6z2jmDTzshiKRrSg+Jf7Hhzj1pqwU+6+CpelPPDpA==} + '@tiptap/extension-highlight@2.27.2': + resolution: {integrity: sha512-ZjlktDdMjruMJFAVz0TbQf0v92Jqkc7Ri1iZJqBXuLid+r+GxUzl2CVAV7qq5yagkGQgvAG+WGsMk880HgR3MA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-history@2.8.0': - resolution: {integrity: sha512-u5YS0J5Egsxt8TUWMMAC3QhPZaak+IzQeyHch4gtqxftx96tprItY7AD/A3pGDF2uCSnN+SZrk6yVexm6EncDw==} + '@tiptap/extension-history@2.27.2': + resolution: {integrity: sha512-+hSyqERoFNTWPiZx4/FCyZ/0eFqB9fuMdTB4AC/q9iwu3RNWAQtlsJg5230bf/qmyO6bZxRUc0k8p4hrV6ybAw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-horizontal-rule@2.8.0': - resolution: {integrity: sha512-Sn/MI8WVFBoIYSIHA9NJryJIyCEzZdRysau8pC5TFnfifre0QV1ksPz2bgF+DyCD69ozQiRdBBHDEwKe47ZbfQ==} + '@tiptap/extension-horizontal-rule@2.27.2': + resolution: {integrity: sha512-WGWUSgX+jCsbtf9Y9OCUUgRZYuwjVoieW5n6mAUohJ9/6gc6sGIOrUpBShf+HHo6WD+gtQjRd+PssmX3NPWMpg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-image@2.8.0': - resolution: {integrity: sha512-5CReomgHGTUgxaX8P3i6qiC9VRWcWQgVoYtds4ZM52LVx/oGwMxQ4ECyzdVYKaRW+6PrNnAe6ew3Qpd5Wk0cIg==} + '@tiptap/extension-image@2.27.2': + resolution: {integrity: sha512-5zL/BY41FIt72azVrCrv3n+2YJ/JyO8wxCcA4Dk1eXIobcgVyIdo4rG39gCqIOiqziAsqnqoj12QHTBtHsJ6mQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-italic@2.8.0': - resolution: {integrity: sha512-PwwSE2LTYiHI47NJnsfhBmPiLE8IXZYqaSoNPU6flPrk1KxEzqvRI1joKZBmD9wuqzmHJ93VFIeZcC+kfwi8ZA==} + '@tiptap/extension-italic@2.27.2': + resolution: {integrity: sha512-1OFsw2SZqfaqx5Fa5v90iNlPRcqyt+lVSjBwTDzuPxTPFY4Q0mL89mKgkq2gVHYNCiaRkXvFLDxaSvBWbmthgg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-list-item@2.8.0': - resolution: {integrity: sha512-o7OGymGxB0B9x3x2prp3KBDYFuBYGc5sW69O672jk8G52DqhzzndgPnkk0qUn8nXAUKuDGbJmpmHVA2kagqnRg==} + '@tiptap/extension-list-item@2.27.2': + resolution: {integrity: sha512-eJNee7IEGXMnmygM5SdMGDC8m/lMWmwNGf9fPCK6xk0NxuQRgmZHL6uApKcdH6gyNcRPHCqvTTkhEP7pbny/fg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-ordered-list@2.8.0': - resolution: {integrity: sha512-sCvNbcTS1+5QTTXwUPFa10vf5I1pr8sGcOTIh0G+a5ZkS5+6FxT12k7VLzPt39QyNbOi+77U2o4Xr4XyaEkfSg==} + '@tiptap/extension-ordered-list@2.27.2': + resolution: {integrity: sha512-M7A4tLGJcLPYdLC4CI2Gwl8LOrENQW59u3cMVa+KkwG1hzSJyPsbDpa1DI6oXPC2WtYiTf22zrbq3gVvH+KA2w==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-list-item': ^2.7.0 - '@tiptap/extension-text-style': ^2.7.0 - '@tiptap/extension-paragraph@2.8.0': - resolution: {integrity: sha512-XgxxNNbuBF48rAGwv7/s6as92/xjm/lTZIGTq9aG13ClUKFtgdel7C33SpUCcxg3cO2WkEyllXVyKUiauFZw/A==} + '@tiptap/extension-paragraph@2.27.2': + resolution: {integrity: sha512-elYVn2wHJJ+zB9LESENWOAfI4TNT0jqEN34sMA/hCtA4im1ZG2DdLHwkHIshj/c4H0dzQhmsS/YmNC5Vbqab/A==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-placeholder@2.8.0': - resolution: {integrity: sha512-BMqv/C9Tcjd7L1/OphUAJTZhWfpWs0rTQJ0bs3RRGsC8L+K20Fg+li45vw7M0teojpfrw57zwJogJd/m23Zr1Q==} + '@tiptap/extension-placeholder@2.27.2': + resolution: {integrity: sha512-IjsgSVYJRjpAKmIoapU0E2R4E2FPY3kpvU7/1i7PUYisylqejSJxmtJPGYw0FOMQY9oxnEEvfZHMBA610tqKpg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-strike@2.8.0': - resolution: {integrity: sha512-ezkDiXxQ3ME/dDMMM7tAMkKRi6UWw7tIu+Mx7Os0z8HCGpVBk1gFhLlhEd8I5rJaPZr4tK1wtSehMA9bscFGQw==} + '@tiptap/extension-strike@2.27.2': + resolution: {integrity: sha512-HHIjhafLhS2lHgfAsCwC1okqMsQzR4/mkGDm4M583Yftyjri1TNA7lzhzXWRFWiiMfJxKtdjHjUAQaHuteRTZw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-subscript@2.8.0': - resolution: {integrity: sha512-m14K5M7E+SqqrBul+B9t5sjN4zqTddV+Q+vd+RIm+OHG6AQhwewNoFyghZz5dGZ2Xj7HqiEyusBN+iHwfgJpmg==} + '@tiptap/extension-subscript@2.27.2': + resolution: {integrity: sha512-x2Oz7hrI4KvzzB9pWChFRm6JnKdYAUQDyrlSROngtzXT7VpNQNoD5s8OlICzDeNsaRKzhR8omIz2z17S1VB48g==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-superscript@2.8.0': - resolution: {integrity: sha512-3rAVyRvzhoM51vaeIAEXmr2PkucIwv7ptgyxg6zx6STxcyzMchafGee0LJL7Kcn9uE/n7Yt7ek6bDqo8jU8CtA==} + '@tiptap/extension-superscript@2.27.2': + resolution: {integrity: sha512-VTGJDuNqdesibSVW94Q71VaGVGr/bwBppdaNLn7k6beOegALfIH7ncArlkD/eihOlJ2qaWiT7FoWNLTb/Fdv1w==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-cell@2.8.0': - resolution: {integrity: sha512-IZpxONWyOd474L8+k4bHrFNRhbsl9eRwbNs5O877JkVFItc2WUz1DIhbJzjmBRsqExtWQJuOsiqWFab1kpiwGQ==} + '@tiptap/extension-table-cell@2.27.2': + resolution: {integrity: sha512-9Lk46MjZMFzVZfOj9Kd7VgC6Odt6vmEhlCYVumErShUY7EkFqCw3b2IYoUtQkntfOEx/Afnhff/okNQwPsJeUA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-header@2.8.0': - resolution: {integrity: sha512-B67A96yMQlG96IFzZBc7D5dnn7O29hcjuDLtjyZkKvU5D/RlFKPMmC9nVphCV3CnbkvEOZUdK9pNaOpen64naw==} + '@tiptap/extension-table-header@2.27.2': + resolution: {integrity: sha512-ZEb6lbG0NbbodWLV0b4BS/QrDIPlUbCcuOsUxzqVvlMUY1Vg6Fj6fKwLaBcsIUDHi8sxZDBEgYEDw3BR/zcO6A==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-row@2.8.0': - resolution: {integrity: sha512-Iezej6l7X+WqKzGLmCgAwmpL+QsfjFv1g8yVH5d0/3Pkcj3G9nDn+GSm4bZnbfYFyqInHG94PZ5PMReiALrJtA==} + '@tiptap/extension-table-row@2.27.2': + resolution: {integrity: sha512-Nw9+tA56Y5HtLVP01NGCZSUuTQhJPtfK9OfmDgGgcxynn2cRVdEtj+9FNZqRhQ1iRVaAI+Rd4xRvX9qYePMOxw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table@2.8.0': - resolution: {integrity: sha512-dm9CitjacXyJuE5SZfV2lUc3uOiP2sxo6fygIzMz7iuxHqQueyONWG+TBkK7HjqzXOiMPsvOf/25NazzIG8HMg==} + '@tiptap/extension-table@2.27.2': + resolution: {integrity: sha512-pDbhOpT5phZkcsyPjGBQlXv0+0hmdrvqHJ+dJjkGcCtlfy2pHiEIhmIItOFagc7wXy8G9iUFZ9Jie4zvDf+brg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-text-align@2.8.0': - resolution: {integrity: sha512-Y6s/DF+P4lxpAnvSrnmt4xGwQT/AJJJm0aA1wu5GuPKpAQ+K4C7K6rE6uGNAXtR39GlewC7KdmcvA+CYhL8xlw==} + '@tiptap/extension-text-align@2.27.2': + resolution: {integrity: sha512-0Pyks6Hu+Q/+9+5/osoSv0SP6jIerdWMYbi13aaZLsJoj3lBj5WNaE11JtAwSFN5sx0IbqhDSlp1zkvRnzgZ8g==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text-style@2.8.0': - resolution: {integrity: sha512-jJp0vcZ2Ty7RvIL0VU6dm1y+fTfXq1lN2GwtYzYM0ueFuESa+Qo8ticYOImyWZ3wGJGVrjn7OV9r0ReW0/NYkQ==} + '@tiptap/extension-text-style@2.27.2': + resolution: {integrity: sha512-Omk+uxjJLyEY69KStpCw5fA9asvV+MGcAX2HOxyISDFoLaL49TMrNjhGAuz09P1L1b0KGXo4ml7Q3v/Lfy4WPA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text@2.8.0': - resolution: {integrity: sha512-EDAdFFzWOvQfVy7j3qkKhBpOeE5thkJaBemSWfXI93/gMVc0ZCdLi24mDvNNgUHlT+RjlIoQq908jZaaxLKN2A==} + '@tiptap/extension-text@2.27.2': + resolution: {integrity: sha512-Xk7nYcigljAY0GO9hAQpZ65ZCxqOqaAlTPDFcKerXmlkQZP/8ndx95OgUb1Xf63kmPOh3xypurGS2is3v0MXSA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-underline@2.8.0': - resolution: {integrity: sha512-1ouuHwZJphT8OosAmp6x8e+Wly3cUd1pNWBiOutJX+6QRGBXJnIKFCzn8YOTlWhg1YQigisG7dNF3YdlyuRNHw==} + '@tiptap/extension-underline@2.27.2': + resolution: {integrity: sha512-gPOsbAcw1S07ezpAISwoO8f0RxpjcSH7VsHEFDVuXm4ODE32nhvSinvHQjv2icRLOXev+bnA7oIBu7Oy859gWQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-youtube@2.8.0': - resolution: {integrity: sha512-mE80+XOkvbUvWYOZnDTtftIUfZhpBJdNKRY73Fyg20GApspdpLejo1x/lhJbAFk09jyRMvnBw292Spy2JRcF0g==} + '@tiptap/extension-youtube@2.27.2': + resolution: {integrity: sha512-3l/tfJ8wO8/tALo1tpAfN7TTJQQ00V52XaYamjQPVzPGelm/ECCfSCGQ4oRv8gbyzjUbZkNpkSV1Bj2V7QcGDg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/pm@2.8.0': - resolution: {integrity: sha512-eMGpRooUMvKz/vOpnKKppApMSoNM325HxTdAJvTlVAmuHp5bOY5kyY1kfUlePRiVx1t1UlFcXs3kecFwkkBD3Q==} + '@tiptap/pm@2.27.2': + resolution: {integrity: sha512-kaEg7BfiJPDQMKbjVIzEPO3wlcA+pZb2tlcK9gPrdDnEFaec2QTF1sXz2ak2IIb2curvnIrQ4yrfHgLlVA72wA==} - '@tiptap/starter-kit@2.8.0': - resolution: {integrity: sha512-r7UwaTrECkQoheWVZKFDqtL5tBx07x7IFT+prfgnsVlYFutGWskVVqzCDvD3BDmrg5PzeCWYZrQGlPaLib7tjg==} + '@tiptap/starter-kit@2.27.2': + resolution: {integrity: sha512-bb0gJvPoDuyRUQ/iuN52j1//EtWWttw+RXAv1uJxfR0uKf8X7uAqzaOOgwjknoCIDC97+1YHwpGdnRjpDkOBxw==} '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -2075,14 +2685,19 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + ag-channel@5.0.0: resolution: {integrity: sha512-bArHkdqQxynim981t8FLZM5TfA0v7p081OlFdOxs6clB79GSGcGlOQMDa31DT9F5VMjzqNiJmhfGwinvfU/3Zg==} - ag-request@1.0.1: - resolution: {integrity: sha512-3F4pDpLy9mxOXop7LoWE78J5g2jmiEJ0gJfzcECOsf/NaCfyeNmOdNLDVM5dS4Hvbi9T+HENL4DmXq5XSotPaA==} + ag-request@1.1.0: + resolution: {integrity: sha512-d4K7QC1KnIpzcnUNNOeh1ddxmYMLiIdhdc1M8osxiHbZP/uoia4IINhhf2+1CrlnNJEPUoUH0Y58Sx0qeqoIvg==} - air-datepicker@3.4.0: - resolution: {integrity: sha512-MFr+2QYdHgrbd6Ah32hxoSCsmNJdrhYSkhr6hhefLpJBtsvX7zdYSvizsCJg15B2000NrEXep8UCYOsWy39iiw==} + air-datepicker@3.6.0: + resolution: {integrity: sha512-+txUkqa949rXBJDmkQAIb/GehZECJYF4rm9XJxVYtEX22C9WvBpE/XwCUQZBopKIkpg4ycAySJ9lH3JOg9qQTw==} ajv-errors@1.0.1: resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} @@ -2110,9 +2725,15 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + amd-name-resolver@0.0.6: resolution: {integrity: sha512-W2trar3LgeKV/yB6ZRD3Iw7MlhrKjLMVSNAatWNNYsn4w+iSfbmA66VB+jQjVIfvzHPZicnHObAvflMkoVtjAQ==} @@ -2257,12 +2878,15 @@ packages: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} - asn1.js@5.4.1: - resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} assert-never@1.2.1: resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==} + assert-never@1.4.0: + resolution: {integrity: sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==} + assert@1.5.1: resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} @@ -2309,11 +2933,11 @@ packages: engines: {node: '>= 4.5.0'} hasBin: true - autonumeric@4.10.5: - resolution: {integrity: sha512-t7h1poYH37eVi/pDTdO0UBb8qk8A9gUHzABP/wUoqSw4w5aDFJr2gxfZPl+agta4ifb5OfBm4Bylv1G/dCC2zQ==} + autonumeric@4.10.9: + resolution: {integrity: sha512-7aStLD5zn0x8mUDvYsl7YY11xzI6NgOK8u40UB6SvdoqItfzfOz6sfVZv4CyADy2nlbM0zHJ992SXGVVJEzCGA==} - autoprefixer@10.4.17: - resolution: {integrity: sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==} + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: @@ -2323,6 +2947,10 @@ packages: resolution: {integrity: sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==} engines: {node: '>= 0.4'} + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + babel-code-frame@6.26.0: resolution: {integrity: sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==} @@ -2347,8 +2975,12 @@ packages: resolution: {integrity: sha512-N1ZfNprtf/37x0R05J0QCW/9pCAcuI+bjZIK9tlu0JEkwEST7ssdD++gxHRbD58AiG5QE5OuNYhRoEFsc1wESw==} engines: {node: '>= 12.*'} - babel-import-util@3.0.0: - resolution: {integrity: sha512-4YNPkuVsxAW5lnSTa6cn4Wk49RX6GAB6vX+M6LqEtN0YePqoFczv1/x0EyLK/o+4E1j9jEuYj5Su7IEPab5JHQ==} + babel-import-util@2.1.1: + resolution: {integrity: sha512-3qBQWRjzP9NreSH/YrOEU1Lj5F60+pWSLP0kIdCWxjFHH7pX2YPHIxQ67el4gnMNfYoDxSDGcT0zpVlZ+gVtQA==} + engines: {node: '>= 12.*'} + + babel-import-util@3.0.1: + resolution: {integrity: sha512-2copPaWQFUrzooJVIVZA/Oppx/S/KOoZ4Uhr+XWEQDMZ8Rvq/0SNQpbdIyMBJ8IELWt10dewuJw+tX4XjOo7Rg==} engines: {node: '>= 12.*'} babel-loader@8.3.0: @@ -2358,6 +2990,13 @@ packages: '@babel/core': ^7.0.0 webpack: '>=2' + babel-loader@8.4.1: + resolution: {integrity: sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==} + engines: {node: '>= 8.9'} + peerDependencies: + '@babel/core': ^7.0.0 + webpack: '>=2' + babel-messages@6.23.0: resolution: {integrity: sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==} @@ -2388,6 +3027,10 @@ packages: resolution: {integrity: sha512-alinprIQcLficqkuIyeKKfD4HQOpMOiHK6pt6Skj/yjoPoQYBuwAJ2BoPAlRe9k/URPeVkpMefbN3m6jEp7RsA==} engines: {node: '>= 12.*'} + babel-plugin-ember-template-compilation@2.4.1: + resolution: {integrity: sha512-n+ktQ3JeyWrpRutSyPn2PsHeH+A94SVm+iUoogzf9VUqpP47FfWem24gpQXhn+p6+x5/BpuFJXMLXWt7ZoYAKA==} + engines: {node: '>= 12.*'} + babel-plugin-filter-imports@4.0.0: resolution: {integrity: sha512-jDLlxI8QnfKd7PtieH6pl4tZJzymzfCDCPGdTq/grgbiYAikwDPp/oL0IlFJn0HQjLpcLkyYhPKkUVneRESw5w==} engines: {node: '>=8'} @@ -2408,11 +3051,29 @@ packages: resolution: {integrity: sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==} engines: {node: '>= 16'} + babel-plugin-module-resolver@5.0.2: + resolution: {integrity: sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==} + + babel-plugin-polyfill-corejs2@0.4.15: + resolution: {integrity: sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-corejs2@0.4.8: resolution: {integrity: sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-corejs3@0.13.0: + resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.14.0: + resolution: {integrity: sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-corejs3@0.9.0: resolution: {integrity: sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==} peerDependencies: @@ -2423,6 +3084,11 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-regenerator@0.6.6: + resolution: {integrity: sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-syntax-dynamic-import@6.18.0: resolution: {integrity: sha512-MioUE+LfjCEz65Wf7Z/Rm4XCP5k2c+TbMd2Z2JKc7U9uwjBhAfNPE48KC4GTGKhppMeYVepwDBNO/nGY6NYHBA==} @@ -2471,6 +3137,11 @@ packages: resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} engines: {node: '>=0.10.0'} + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} + hasBin: true + basic-auth@2.0.1: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} engines: {node: '>= 0.8'} @@ -2486,8 +3157,8 @@ packages: resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} engines: {node: '>=0.10.0'} - binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} binaryextensions@2.3.0: @@ -2512,11 +3183,11 @@ packages: bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} - bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + bn.js@5.2.3: + resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} body-parser@1.20.1: resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} @@ -2528,6 +3199,9 @@ packages: brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -2539,6 +3213,10 @@ packages: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + broccoli-asset-rev@3.0.0: resolution: {integrity: sha512-gAHQZnwvtl74tGevUqGuWoyOdJUdMMv0TjGSMzbdyGImr9fZcnM6xmggDA8bUawrMto9NFi00ZtNUgA4dQiUBw==} @@ -2555,6 +3233,12 @@ packages: peerDependencies: '@babel/core': ^7.17.9 + broccoli-babel-transpiler@8.0.2: + resolution: {integrity: sha512-XIGsUyJgehSRNVVrOnRuW+tijYBqkoGEONc/UHkiOBW+C0trPv9c/Icc/Cf+2l1McQlHW/Mc6SksHg6qFlEClg==} + engines: {node: 16.* || >= 18} + peerDependencies: + '@babel/core': ^7.17.9 + broccoli-builder@0.18.14: resolution: {integrity: sha512-YoUHeKnPi4xIGZ2XDVN9oHNA9k3xF5f5vlA+1wvrxIIDXqQU97gp2FxVAF503Zxdtt0C5CRB5n+47k2hlkaBzA==} engines: {node: '>= 0.10.0'} @@ -2565,6 +3249,9 @@ packages: broccoli-caching-writer@3.0.3: resolution: {integrity: sha512-g644Kb5uBPsy+6e2DvO3sOc+/cXZQQNgQt64QQzjA9TSdP0dl5qvetpoNIx4sy/XIjrPYG1smEidq9Z9r61INw==} + broccoli-caching-writer@3.1.0: + resolution: {integrity: sha512-3TWi92ogzUhLmCF5V4DjhN7v4t6OjXYO21p9GkuOZQ1SiVmM1sYio364y64dREHUzjFEcH8mdVCiRDdrwUGVTw==} + broccoli-clean-css@1.1.0: resolution: {integrity: sha512-S7/RWWX+lL42aGc5+fXVLnwDdMtS0QEWUFalDp03gJ9Na7zj1rWa351N2HZ687E2crM9g+eDWXKzD17cbcTepg==} @@ -2736,12 +3423,13 @@ packages: browserify-des@1.0.2: resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - browserify-rsa@4.1.0: - resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + browserify-rsa@4.1.1: + resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} + engines: {node: '>= 0.10'} - browserify-sign@4.2.2: - resolution: {integrity: sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==} - engines: {node: '>= 4'} + browserify-sign@4.2.5: + resolution: {integrity: sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==} + engines: {node: '>= 0.10'} browserify-zlib@0.2.0: resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} @@ -2751,6 +3439,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -2802,10 +3495,22 @@ packages: resolution: {integrity: sha512-Quw8a6y8CPmRd6eU+mwypktYCwUcf8yVFIRbNZ6tPQEckX9yd+EBVEPC/GSZZrMWH9e7Vz4pT7XhpmyApRByLQ==} engines: {node: 6.* || 8.* || >= 10.*} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + call-me-maybe@1.0.2: resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} @@ -2838,6 +3543,9 @@ packages: caniuse-lite@1.0.30001588: resolution: {integrity: sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==} + caniuse-lite@1.0.30001774: + resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==} + capture-exit@2.0.0: resolution: {integrity: sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2868,9 +3576,9 @@ packages: charm@1.0.2: resolution: {integrity: sha512-wqW3VdPnlSWT4eRiYX+hcs+C6ViBPUWk1qTCd+37qw9kEm/a5n2qcyQDMBWvSYKN/ctqZzeXNQaeBjOetJJUkw==} - chart.js@4.4.1: - resolution: {integrity: sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==} - engines: {pnpm: '>=7'} + chart.js@4.5.1: + resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} + engines: {pnpm: '>=8'} chartjs-adapter-date-fns@3.0.0: resolution: {integrity: sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==} @@ -2892,12 +3600,17 @@ packages: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} engines: {node: '>=6.0'} + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + cipher-base@1.0.7: + resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} + engines: {node: '>= 0.10'} class-utils@0.3.6: resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} @@ -3045,8 +3758,8 @@ packages: component-emitter@1.3.1: resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} - compress-json@3.1.0: - resolution: {integrity: sha512-Zcq4jRC5ZpfaOY3mbBWOANtGuMHJ/hsTENcwN1/lEkrogcoAF7HBma1RLe/CICZO6IquK1U0EaPzmnlDIFRNjA==} + compress-json@3.4.0: + resolution: {integrity: sha512-SxT8uFOacRbP3gfi4aVAulr4KzE933eZWBguVBwuVWv3GTGQAToqpq8rFtdbIVgeCOH7RpPuXKQrPPd087b8uA==} compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} @@ -3262,6 +3975,9 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-tag@4.1.0: + resolution: {integrity: sha512-On6gUuvI1l5MScHO+Xbwjeq1Pk9H6HOipDWkzqGGUGmKpq6K5TRmQuCl1LGSHbdIo2l+lSsgLKrLgCl5kKYA+A==} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -3300,6 +4016,9 @@ packages: core-js-compat@3.36.0: resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==} + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} + core-js@2.6.12: resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. @@ -3344,15 +4063,16 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - crypto-browserify@3.12.0: - resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + crypto-browserify@3.12.1: + resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} + engines: {node: '>= 0.10'} crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} - css-blank-pseudo@6.0.1: - resolution: {integrity: sha512-goSnEITByxTzU4Oh5oJZrEWudxTqk7L6IXj1UW69pO6Hv0UdX+Vsrt02FFu5DweRh2bLu6WpX/+zsQCu5O1gKw==} + css-blank-pseudo@6.0.2: + resolution: {integrity: sha512-J/6m+lsqpKPqWHOifAFtKFeGLOzw3jR92rxQcwRUfA/eTuZzKfKlxOmYDx2+tqOPQAueNvBiY8WhAeHu5qNmTg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -3364,8 +4084,8 @@ packages: resolution: {integrity: sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==} engines: {node: '>=12 || >=16'} - css-has-pseudo@6.0.1: - resolution: {integrity: sha512-WwoVKqNxApfEI7dWFyaHoeFCcUPD+lPyjL6lNpRUNX7IyIUuVpawOTwwA5D0ZR6V2xQZonNPVj8kEcxzEaAQfQ==} + css-has-pseudo@6.0.5: + resolution: {integrity: sha512-ZTv6RlvJJZKp32jPYnAJVhowDCrRrHUTAxsYSuUPBEDJjzws6neMnzkRblxtgmv1RgcV5dhH2gn7E3wA9Wt6lw==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -3389,14 +4109,17 @@ packages: css-unit-converter@1.1.2: resolution: {integrity: sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==} - cssdb@7.11.0: - resolution: {integrity: sha512-YUVAJhjDcTZzVD5XE49l3PQtGE29vvhzaL1bM3BtkvSmIRJeYENdfn1dn5jauBI7BBF+IyyiBS+oSVx3Hz/Gaw==} + cssdb@8.8.0: + resolution: {integrity: sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q==} cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cyclist@1.0.2: resolution: {integrity: sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==} @@ -3432,6 +4155,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -3452,8 +4184,11 @@ packages: resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} engines: {node: '>=4'} - decorator-transforms@2.2.2: - resolution: {integrity: sha512-NHCSJXOUQ29YFli1QzstXWo72EyASpoVx+s0YdkMwswpovf/iAJP580nD1tB0Ph9exvtbfWdVrSAloXrWVo1Xg==} + decorator-transforms@1.2.1: + resolution: {integrity: sha512-UUtmyfdlHvYoX3VSG1w5rbvBQ2r5TX1JsE4hmKU9snleFymadA3VACjl6SRfi9YgBCSjBbfQvR1bs9PRW9yBKw==} + + decorator-transforms@2.3.1: + resolution: {integrity: sha512-PDOk74Zqqy0946Lx4ckXxbgG6uhPScOICtrxL/pXmfznxchqNee0TaJISClGJQe6FeT8ohGqsOgdjfahm4FwEw==} deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} @@ -3562,6 +4297,10 @@ packages: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + duplexer3@0.1.5: resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} @@ -3585,12 +4324,15 @@ packages: electron-to-chromium@1.4.673: resolution: {integrity: sha512-zjqzx4N7xGdl5468G+vcgzDhaHkaYgVcf9MqgexcTqsl2UHSCmOj/Bi3HAprg4BZCpC7HyD8a6nZl6QAZf72gw==} + electron-to-chromium@1.5.302: + resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} + element-closest@3.0.2: resolution: {integrity: sha512-JxKQiJKX0Zr5Q2/bCaTx8P+UbfyMET1OQd61qu5xQFeWr1km3fGaxelSJtnfT27XQ5Uoztn2yIyeamAc/VX13g==} engines: {node: '>=0.12.0'} - elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} ember-animated@1.1.4: resolution: {integrity: sha512-30omG5vB8naagE7cFW7AfTH4i2r+JyvEPpN/pRoz6Z/I5pYcjhSTrONZs5BAdX8B+B0/hEfZqO7ge/Ui8riBHA==} @@ -3608,6 +4350,9 @@ packages: resolution: {integrity: sha512-GKHhT4HD2fhtDnuBk6eCdCA8XGew9hY7TVs8zjrykegiI7weC0CGtpJscmIG3O0gEEb0d07UTkF2pjfNGLx4Nw==} engines: {node: '>= 12'} + ember-assign-helper@0.5.1: + resolution: {integrity: sha512-dXHbwlBTJWVjG7k4dhVrT3Gh4nQt6rC2LjyltuPztIhQ+YcPYHMqAPJRJYLGZu16aPSJbaGF8K+u51i7CLzqlQ==} + ember-ast-helpers@0.4.0: resolution: {integrity: sha512-3gBsatspW3AT2hwzD27aQbgyWA29RXeMxCnMYgFBYtmS/T1M6TxuatEgfpofKqai4OC/JijftmN4s6dydeXGzQ==} engines: {node: '>= 6'} @@ -3616,14 +4361,20 @@ packages: resolution: {integrity: sha512-gLqML2k77AuUiXxWNon1FSzuG1DV7PEPpCLCU5aJvf6fdL6rmFfElsZRh+8ELEB/qP9dT+LHjNEunVzd2dYc8A==} engines: {node: '>= 10.*'} + ember-auto-import@2.12.1: + resolution: {integrity: sha512-wyvl+aJJKOKbRSLqq6CyMsNrvurmX4SIWHHqZdC5giZ7P8ECGmcn9W9HFoVLpwXkFJoXhNV4L7mqqcU6881t0w==} + engines: {node: 12.* || 14.* || >= 16} + ember-auto-import@2.8.1: resolution: {integrity: sha512-R5RpJmhycU6YKryzsIL/wP42r0e2PPfLRsFECoGvb1st2eEnU1Q7XyLVC1txd/XvURfu7x3Z7hKtZtYUxy61oQ==} engines: {node: 12.* || 14.* || >= 16} - ember-basic-dropdown@7.3.0: - resolution: {integrity: sha512-XzLd1noCrHjG7O35HpZ+ljj7VwPPqon7svbvNJ2U7421e00eXBUVcCioGJFo1NnnPkjc14FTDc5UwktbGSbJdQ==} - engines: {node: 16.* || >= 18} + ember-basic-dropdown@8.4.0: + resolution: {integrity: sha512-vaK0ypA6J8hduvIrctquMpIoAsgp1Uz/W2RGQJ1KsvvgAttowuDBBuGFEmubzhnnKJM2LGBX7+miRXnn36kBTA==} peerDependencies: + '@ember/test-helpers': ^2.9.4 || ^3.2.1 || ^4.0.2 + '@glimmer/component': ^1.1.2 || ^2.0.0 + '@glimmer/tracking': ^1.1.2 ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0 ember-cache-primitive-polyfill@1.0.1: @@ -3658,6 +4409,12 @@ packages: peerDependencies: '@babel/core': ^7.12.0 + ember-cli-babel@8.3.1: + resolution: {integrity: sha512-Pxm5JP0jQ6fCBlXuh1BFmhrg2/5YXjhf16JI/n8ReOR6Nl+fEbudMpdO69LlqZRsMmTgdjCRmfSxMh26Wsw/rw==} + engines: {node: 16.* || 18.* || >= 20} + peerDependencies: + '@babel/core': ^7.12.0 + ember-cli-clean-css@3.0.0: resolution: {integrity: sha512-BbveJCyRvzzkaTH1llLW+MpHe/yzA5zpHOpMIg2vp/3JD9mban9zUm7lphaB0TSpPuMuby9rAhTI8pgXq0ifIA==} engines: {node: 16.* || >= 18} @@ -3701,8 +4458,10 @@ packages: ember-cli-normalize-entity-name@1.0.0: resolution: {integrity: sha512-rF4P1rW2P1gVX1ynZYPmuIf7TnAFDiJmIUFI1Xz16VYykUAyiOCme0Y22LeZq8rTzwBMiwBwoE3RO4GYWehXZA==} - ember-cli-notifications@9.0.0: - resolution: {integrity: sha512-ytGHRLmIsr/WkKDGtPHwqtV27T4PAuikW2NP8IdreaOsnvoEY6v2vZJEJEU79z2kQ1XgrNRXWVg4R4KrdR3m8Q==} + ember-cli-notifications@9.1.0: + resolution: {integrity: sha512-Vr3/3y6dIbfFZB7OJuKrQCwMzL48Ym1tnJUGiElvg3G75gr/FUZ88O8gTo5HqCSASmqp2HFw4bQpvtmq2GHqjg==} + peerDependencies: + ember-source: '>= 3.8.0' ember-cli-path-utils@1.0.0: resolution: {integrity: sha512-Qq0vvquzf4cFHoDZavzkOy3Izc893r/5spspWgyzLCPTaG78fM3HsrjZm7UWEltbXUqwHHYrqZd/R0jS08NqSA==} @@ -3763,6 +4522,10 @@ packages: resolution: {integrity: sha512-qqp5TAIuPHxHiGXJKL+78Euyhy0zSKQMovPh8sJpN/ZBYx0H90pONufHR3anaMcp1snVfx4B+mb9+7ijOik8ZA==} engines: {node: '>= 12.*'} + ember-cli-typescript@5.3.0: + resolution: {integrity: sha512-gFA+ZwmsvvFwo2Jz/B9GMduEn+fPoGb69qWGP0Tp3+Tu5xypDtIKVSZ5086I3Cr19cLXD4HkrOR3YQvdUKzAkQ==} + engines: {node: '>= 12.*'} + ember-cli-version-checker@2.2.0: resolution: {integrity: sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg==} engines: {node: '>= 4'} @@ -3794,6 +4557,12 @@ packages: peerDependencies: ember-source: ^3.8 || ^4.0.0 || >= 5.0.0 + ember-composability-tools@1.3.0: + resolution: {integrity: sha512-KRIybkRlPWrymQFfW2UiDrbI6GDpXiqJLK+fxKZyaqf2Pb/vJmHShm55Bch90U2tcbG20UB4Tf+w+IpZA8Gi3w==} + engines: {node: 16.* || >= 18} + peerDependencies: + ember-source: ^3.8 || ^4.0.0 || >= 5.0.0 + ember-composable-helpers@5.0.0: resolution: {integrity: sha512-gyUrjiSju4QwNrsCLbBpP0FL6VDFZaELNW7Kbcp60xXhjvNjncYgzm4zzYXhT+i1lLA6WEgRZ3lOGgyBORYD0w==} engines: {node: 12.* || 14.* || >= 16} @@ -3808,12 +4577,6 @@ packages: resolution: {integrity: sha512-r6O34YKI/slyYapVsuOPnmaKC4AsmBSwvgcadbdy+jHNj+mnryXPkm+3hhhRnFdlsKUKdEuXvl43lhjhYRLhhA==} engines: {node: 10.* || >= 12} - ember-concurrency-test-waiter@0.4.0: - resolution: {integrity: sha512-Yx3rDu9C1oDzWOFk9C4G9VQvnALZXsNvTGgRhM4J4Uzk1/tlRfZ0eLEJHWJqO3P3nyHdGlNAWYLq6Ozi0iFhQA==} - engines: {node: 10.* || >= 12} - peerDependencies: - ember-concurrency: '>=0.7.19' - ember-concurrency-ts@0.3.1: resolution: {integrity: sha512-lE9uqPgK1Y9PN/0BJ5zE2a+h95izRCn6FCyt7qVV3012TlblTynsBaoUuAbN1T3KfzFsrJaXwsxzRbDjEde2Sw==} engines: {node: 10.* || >= 12} @@ -3830,9 +4593,20 @@ packages: peerDependencies: ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0 - ember-cookies@1.1.2: - resolution: {integrity: sha512-6GaN0eEDZT9SEUSZBxWzZMlvxjcGKXFTJNjv30LVXTTOxozE5IBmIxiDAEq0udi0UpWUGHLYQBgnANn4jdll7w==} + ember-concurrency@4.0.6: + resolution: {integrity: sha512-Ikwl2YwXVe8aBwrT1deWTcUVxVu6KxS1qeU1ks3EML1Q/nxwKgxCkGqTJavxczawO8H/SIW45dV4r7z5Yqd2Xg==} + engines: {node: 16.* || >= 18} + peerDependencies: + '@glint/template': '>= 1.0.0' + peerDependenciesMeta: + '@glint/template': + optional: true + + ember-cookies@1.3.0: + resolution: {integrity: sha512-nhVDm9lql4EVLpbjxyosyEITFvuNAmHr7cod8K2FmIyw2KcAFWSS0v88quIWc+GvcawBTz3KSMRXOJq/0InVpg==} engines: {node: '>= 16.*'} + peerDependencies: + ember-source: '>=4.0' ember-copy@2.0.1: resolution: {integrity: sha512-N/XFvZszrzyyX4IcNoeK4mJvIItNuONumhPLqi64T8NDjJkxBj4Pq61rvMkJx/9eZ8alzE4I8vYKOLxT0FvRuQ==} @@ -3852,6 +4626,12 @@ packages: resolution: {integrity: sha512-TovtNqCumzyAiW0/OisSkkVK93xnVF4NRU6+FN0ubpfwEOpRrmM2RqDwXI6YAChCgSHON1cz0DfQStpA1Gjuuw==} engines: {node: 10.* || >= 12} + ember-drag-sort@4.2.0: + resolution: {integrity: sha512-MB+4P6/O77YVpUPdKV3PKCyB3SFAy5nzFhatEPUILBbONv+YNIw9QKJgrqK3ytwNfJi8zBUPXGk3KMZvyzcfAQ==} + engines: {node: '>= 20'} + peerDependencies: + ember-source: '>= 4.0.0' + ember-element-helper@0.6.1: resolution: {integrity: sha512-YiOdAMlzYul4ulkIoNp8z7iHDfbT1fbut/9xGFRfxDwU/FmF8HtAUB2f1veu/w50HTeZNopa1OV2PCloZ76XlQ==} engines: {node: 12.* || 14.* || >= 16} @@ -3864,6 +4644,10 @@ packages: peerDependencies: ember-source: ^3.8 || ^4.0.0 || >= 5.0.0 + ember-element-helper@0.8.8: + resolution: {integrity: sha512-3slTltQV5ke53t3YVP2GYoswsQ6y+lhuVzKmt09tbEx91DapG8I/xa8W5OA0StvcQlavL3/vHrz/vCQEFs8bBA==} + engines: {node: 14.* || 16.* || >= 18} + ember-engines@0.9.0: resolution: {integrity: sha512-LVb1GrLGU2DXLXL2ynYXPHg0JJ6P3LRciOdDfjP0aRPLZ1evOr0h7IPIDq4SsT2nG0yhX5qBMJNB4NCyFZvcyA==} engines: {node: 14.* || 16.* || >= 18} @@ -3891,14 +4675,11 @@ packages: miragejs: optional: true - ember-focus-trap@1.1.0: - resolution: {integrity: sha512-KxbCKpAJaBVZm+bW4tHPoBJAZThmxa6pI+WQusL+bj0RtAnGUNkWsVy6UBMZ5QqTQzf4EvGHkCVACVp5lbAWMQ==} - engines: {node: 12.* || >= 14} - peerDependencies: - ember-source: ^4.0.0 || ^5.0.0 + ember-focus-trap@1.2.0: + resolution: {integrity: sha512-+/AkXjWF9Qtv6a3tSZQvzFTF+vSoSNuWVemN8kbp4d3MmHWnbXzv5brd9wmAFFlp4yYRr2be7bVhNVxzJMLEhw==} - ember-functions-as-helper-polyfill@2.1.2: - resolution: {integrity: sha512-yvW6xykvZEIYzzwlrC/g9yu6LtLkkj5F+ho6U+BDxN1uREMgoMOZnji7sSILn5ITVpaJ055DPcO+utEFD7IZOA==} + ember-functions-as-helper-polyfill@2.1.3: + resolution: {integrity: sha512-Hte8jfOmSNzrz/vOchf68CGaBWXN2/5qKgFaylqr9omW2i4Wt9JmaBWRkeR0AJ53N57q3DX2TOb166Taq6QjiA==} engines: {node: '>= 14.0.0'} peerDependencies: ember-source: ^3.25.0 || >=4.0.0 @@ -3921,6 +4702,12 @@ packages: resolution: {integrity: sha512-+oRstEa52mm0jAFzhr51/xtEWpCEykB3SEBr7vUg8YnXUZJ5hKNBppP938q8Zzr9XfJEbzrtDSGjhKwJCJv6FQ==} engines: {node: 10.* || 12.* || >= 14} + ember-inflector@4.0.3: + resolution: {integrity: sha512-E+NnmzybMRWn1JyEfDxY7arjOTJLIcGjcXnUxizgjD4TlvO1s3O65blZt+Xq2C2AFSPeqHLC6PXd6XHYM8BxdQ==} + engines: {node: 14.* || 16.* || >= 18} + peerDependencies: + ember-source: ^3.16.0 || ^4.0.0 || ^5.0.0 + ember-intl@6.3.2: resolution: {integrity: sha512-UJ91JjlY3z6fjajoHhhJtKUbgqEr/l6Ie4Viqn0B3Lrbavxg5IgAIvyZZ9fOVtq05MDtCuc610zV6vLOc71G0w==} engines: {node: 16.* || >= 18} @@ -3944,6 +4731,15 @@ packages: ember-source: ^4.0.0 || ^5.0.0 leaflet: '>=0.7' + ember-lifeline@7.0.0: + resolution: {integrity: sha512-2l51NzgH5vjN972zgbs+32rnXnnEFKB7qsSpJF+lBI4V5TG6DMy4SfowC72ZEuAtS58OVfwITbOO+RnM21EdpA==} + engines: {node: 16.* || >= 18} + peerDependencies: + '@ember/test-helpers': '>= 1.0.0' + peerDependenciesMeta: + '@ember/test-helpers': + optional: true + ember-load-initializers@2.1.2: resolution: {integrity: sha512-CYR+U/wRxLbrfYN3dh+0Tb6mFaxJKfdyz+wNql6cqTrA0BBi9k6J3AaKXj273TqvEpyyXegQFFkZEiuZdYtgJw==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3962,10 +4758,6 @@ packages: peerDependencies: ember-source: ^4.0.0 || ^5.0.0 - ember-maybe-in-element@2.1.0: - resolution: {integrity: sha512-6WAzPbf4BNQIQzkur2+zRJJJ/PKQoujIYgFjrpj3fOPy8iRlxVUm0/B41qbFyg1LE6bVbg0cWbuESWEvJ9Rswg==} - engines: {node: 10.* || >= 12} - ember-modifier-manager-polyfill@1.2.0: resolution: {integrity: sha512-bnaKF1LLKMkBNeDoetvIJ4vhwRPKIIumWr6dbVuW6W6p4QV8ZiO+GdF8J7mxDNlog9CeL9Z/7wam4YS86G8BYA==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3974,13 +4766,8 @@ packages: resolution: {integrity: sha512-ezcPQhH8jUfcJQbbHji4/ZG/h0yyj1jRDknfYue/ypQS8fM8LrGcCMo0rjDZLzL1Vd11InjNs3BD7BdxFlzGoA==} engines: {node: 12.* || >= 14} - ember-modifier@4.1.0: - resolution: {integrity: sha512-YFCNpEYj6jdyy3EjslRb2ehNiDvaOrXTilR9+ngq+iUqSHYto2zKV0rleiA1XJQ27ELM1q8RihT29U6Lq5EyqQ==} - peerDependencies: - ember-source: '*' - peerDependenciesMeta: - ember-source: - optional: true + ember-modifier@4.3.0: + resolution: {integrity: sha512-O0rirSLQbGg0VJ/NqoQ4uN1bh2iAekZC/Ykma+FkjCM2ofrO38u+d8n3+AK6uVWeMJmogGX2KL+Is5fofoInJg==} ember-on-helper@0.1.0: resolution: {integrity: sha512-jjafBnWfoA4VSSje476ft5G+urlvvuSDddwAJjKDCjKY9mbe3hAEsJiMBAaPObJRMm1FOglCuKjQZfwDDls6MQ==} @@ -3994,9 +4781,15 @@ packages: resolution: {integrity: sha512-bkW5eL8MxS3rmn6XnR7B4QivJZ+Y4SF2kHSZPlUwaVjsw4FqZ7a3I1N1dbC3khcgcFvh1M8aa4/Ek/BwP+sorQ==} engines: {node: 10.* || >= 12} - ember-power-select@7.2.0: - resolution: {integrity: sha512-h02M6y4yV5EAYdFXixWQw7qDjb3tuVwB0L/8ZYDezQjqZPdtem86fV7AddsXaejZ3bZsHEhIqzhXD5+TsPxEjg==} - engines: {node: 16.* || >= 18} + ember-power-select@8.6.2: + resolution: {integrity: sha512-EUDMxcO+I0iK6QBM4rOuqn7OMZOxrznslulgI51OStAfbT+Qf5MAvSeOMOEdPbDI7n/racXKr55kCn3HviQSgQ==} + peerDependencies: + '@ember/test-helpers': ^2.9.4 || ^3.2.1 || ^4.0.2 + '@glimmer/component': ^1.1.2 || ^2.0.0 + '@glimmer/tracking': ^1.1.2 + ember-basic-dropdown: ^8.2.0 + ember-concurrency: ^4.0.2 + ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0 ember-qunit@8.0.1: resolution: {integrity: sha512-13PtywHNPTQKkDW4o8QRkJvcdsZr8hRyvh6xh/YLAX8+HaRLd3nPL8mBF4O/Kur/DAj3QWLvjzktZ2uRNGSh3A==} @@ -4017,6 +4810,10 @@ packages: resolution: {integrity: sha512-MnqGS8BnY3GJ+n5RZVVRqCwKjfXXMr5quKyqNu1vxft8oslOJuZ1f1dOesQouD+6LwD4Y9tWRVKNw+LOqM9ocw==} engines: {node: 8.* || >= 10.*} + ember-render-helpers@0.2.1: + resolution: {integrity: sha512-LbsUQRGcR4z9zQPdZsP5+ODU76xzbC9O97+1/ceDJPd5y0FqL9aFOWfSiqL3nEgcf93WW3im8MEVRzFWxz0Hzg==} + engines: {node: 8.* || >= 10.*} + ember-resolver@11.0.1: resolution: {integrity: sha512-ucBk3oM+PR+AfYoSUXeQh8cDQS1sSiEKp4Pcgbew5cFMSqPxJfqd1zyZsfQKNTuyubeGmWxBOyMVSTvX2LeCyg==} engines: {node: 14.* || 16.* || >= 18} @@ -4037,8 +4834,8 @@ packages: resolution: {integrity: sha512-89oVHVJwmLDvGvAUWgS87KpBoRhy3aZ6U0Ql6HOmU4TrPkyaa8pM0W81wj9cIwjYprcQtN9EwzZMHnq46+oUyw==} engines: {node: 8.* || 10.* || >= 12} - ember-simple-auth@6.0.0: - resolution: {integrity: sha512-9SzSFApxZ74CD4UxIeTV+poIPeXcRLXWM60cMvC1SwTYjoc/p9DeQF0pVm6m1XV6uA3kPUzEsEn4/GeHc2YX1w==} + ember-simple-auth@6.1.0: + resolution: {integrity: sha512-LhOl7TrOKlqb+0a/5STOoTSncDNuPELuFZ9+1SLduVX7DtdQr8VOEAmB8UaOnG0clJ9Bj6E3SczhXGjqd718Lw==} peerDependencies: '@ember/test-helpers': '>= 3 || > 2.7' peerDependenciesMeta: @@ -4062,10 +4859,24 @@ packages: peerDependencies: '@ember/string': ^3.0.1 + ember-style-modifier@4.5.1: + resolution: {integrity: sha512-ReVGW9fZmDIsCWsuJGH4joiiHOv9aF9Yv4lUZUjXjQyR9SEAae7RWjZcjPgmEJwpN7yDSyy4PIwdJa0smT2A3g==} + engines: {node: 18.* || >= 20, pnpm: '>= 10.*'} + peerDependencies: + '@ember/string': ^3.1.1 || ^4.0.0 + + ember-tag-input@3.1.0: + resolution: {integrity: sha512-DSLYpZ5n4Buyo2sWObmXw4dYoA3RB9y+HgFabK5Uz8k3EnBn1Mt9RzOh0nju4fWjlvQMjjjouIu6Afb+xIES8g==} + engines: {node: 12.* || 14.* || >= 16} + ember-template-imports@3.4.2: resolution: {integrity: sha512-OS8TUVG2kQYYwP3netunLVfeijPoOKIs1SvPQRTNOQX4Pu8xGGBEZmrv0U1YTnQn12Eg+p6w/0UdGbUnITjyzw==} engines: {node: 12.* || >= 14} + ember-template-imports@4.4.0: + resolution: {integrity: sha512-HNOHabTEMbRluci1uScvh3ljMDo9E46dHHNcJAIf5yjOhIQ/zN4Y0DVDWrRfcbihlHvt4v/iF69G+8tffC1YkA==} + engines: {node: 16.* || >= 18} + ember-template-lint@5.11.2: resolution: {integrity: sha512-G8KXmFCYLKM9ifMb+rluL8CNIawUl45i4z4VrK+Nn5ciWSo+Vx2jUp+sS6wKCdBqGYoiqjUgn/hmGnCVOId+yQ==} engines: {node: ^14.18.0 || ^16.0.0 || >= 18.0.0} @@ -4076,10 +4887,6 @@ packages: engines: {node: 12.* || 14.* || >= 16.*} hasBin: true - ember-text-measurer@0.6.0: - resolution: {integrity: sha512-/aZs2x2i6kT4a5tAW+zenH2wg8AbRK9jKxLkbVsKl/1ublNl27idVRdov1gJ+zgWu3DNK7whcfVycXtlaybYQw==} - engines: {node: 10.* || >= 12} - ember-tracked-storage-polyfill@1.0.0: resolution: {integrity: sha512-eL7lZat68E6P/D7b9UoTB5bB5Oh/0aju0Z7PCMi3aTwhaydRaxloE7TGrTRYU+NdJuyNVZXeGyxFxn2frvd3TA==} engines: {node: 12.* || >= 14} @@ -4128,6 +4935,9 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + engine.io-parser@5.2.2: resolution: {integrity: sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==} engines: {node: '>=10.0.0'} @@ -4180,6 +4990,10 @@ packages: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} @@ -4187,6 +5001,10 @@ packages: es-module-lexer@1.4.1: resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.2: resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} engines: {node: '>= 0.4'} @@ -4199,6 +5017,10 @@ packages: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -4432,6 +5254,10 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -4448,6 +5274,9 @@ packages: resolution: {integrity: sha512-7h9/x25c6AQwdU3mA8MZDUMR3UCy50f237egBrBkuwjnUZSmfu4ptCf91PZSKzON2Uh5VvIHozYKWcPPgcjxIw==} engines: {node: 10.* || >= 12.*} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fastboot-transform@0.1.3: resolution: {integrity: sha512-6otygPIJw1ARp1jJb+6KVO56iKBjhO+5x59RSC9qiZTbZRrv+HZAuP00KD3s+nWMvcFDemtdkugki9DNFTTwCQ==} @@ -4465,6 +5294,15 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + figgy-pudding@3.5.2: resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} deprecated: This module is no longer supported. @@ -4500,6 +5338,10 @@ packages: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + finalhandler@1.1.2: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} @@ -4516,6 +5358,9 @@ packages: resolution: {integrity: sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==} engines: {node: '>=16.0.0'} + find-babel-config@2.1.2: + resolution: {integrity: sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==} + find-cache-dir@2.1.0: resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} engines: {node: '>=6'} @@ -4585,8 +5430,8 @@ packages: flush-write-stream@1.1.1: resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} - focus-trap@6.9.4: - resolution: {integrity: sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==} + focus-trap@7.8.0: + resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} follow-redirects@1.15.5: resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} @@ -4600,6 +5445,10 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + for-in@1.0.2: resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} engines: {node: '>=0.10.0'} @@ -4612,8 +5461,8 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} fragment-cache@0.2.1: resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} @@ -4723,6 +5572,14 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stdin@4.0.1: resolution: {integrity: sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==} engines: {node: '>=0.10.0'} @@ -4854,6 +5711,10 @@ packages: gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + got@9.6.0: resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==} engines: {node: '>=8.6'} @@ -4912,6 +5773,10 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -4935,13 +5800,20 @@ packages: resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} engines: {node: '>=0.10.0'} - hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} + hash-base@3.0.5: + resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} + engines: {node: '>= 0.10'} + + hash-base@3.1.2: + resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==} + engines: {node: '>= 0.8'} hash-for-dep@1.5.1: resolution: {integrity: sha512-/dQ/A2cl7FBPI2pO0CANkvuuVi/IFS5oTyJ0PsOb6jW6WbVW1js5qJXMJTNbWHXBIPdFTWFbabjB+mE0d+gelw==} + hash-for-dep@1.5.2: + resolution: {integrity: sha512-+kJRJpgO+V8x6c3UQuzO+gzHu5euS8HDOIaIUsOPdQrVu7ajNKkMykbSC8O0VX3LuRnUNf4hHE0o/rJ+nB8czw==} + hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} @@ -4949,6 +5821,10 @@ packages: resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} engines: {node: '>= 0.4'} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + heimdalljs-fs-monitor@1.1.1: resolution: {integrity: sha512-BHB8oOXLRlrIaON0MqJSEjGVPDyqt2Y6gu+w2PaEZjrCxeVtZG7etEZp7M4ZQ80HNvnr66KIQ2lot2qdeG8HgQ==} @@ -5156,6 +6032,10 @@ packages: is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-data-descriptor@1.0.1: resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} engines: {node: '>= 0.4'} @@ -5297,6 +6177,10 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -5359,8 +6243,8 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} - jiti@1.21.0: - resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true js-string-escape@1.0.1: @@ -5394,6 +6278,11 @@ packages: engines: {node: '>=4'} hasBin: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.0: resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} @@ -5419,6 +6308,10 @@ packages: resolution: {integrity: sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==} engines: {node: '>= 0.4'} + json-stable-stringify@1.3.0: + resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} + engines: {node: '>= 0.4'} + json5@0.5.1: resolution: {integrity: sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==} hasBin: true @@ -5486,14 +6379,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - - lilconfig@3.1.0: - resolution: {integrity: sha512-p3cz0JV5vw/XeouBU3Ldnp+ZkBjE+n8ydJ4mcwBrOiXXPqNlrzGBqWs9X4MWF7f+iKUBu794Y8Hh8yawiJbCjw==} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} - deprecated: This version contains a security issue. Please upgrade to 3.1.1 or later. line-column@1.0.2: resolution: {integrity: sha512-Ktrjk5noGYlHsVnYWh62FLVs4hTb8A3e+vucNZMgPeAOITdshMSgv4cCZQeRDjm7+goqmo6+liZwTXo+U3sVww==} @@ -5630,6 +6518,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + log-symbols@2.2.0: resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} engines: {node: '>=4'} @@ -5715,8 +6606,8 @@ packages: resolution: {integrity: sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==} hasBin: true - markdown-it@14.1.0: - resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + markdown-it@14.1.1: + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} hasBin: true matcher-collection@1.1.2: @@ -5726,6 +6617,10 @@ packages: resolution: {integrity: sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==} engines: {node: 6.* || 8.* || >= 10.*} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mathml-tag-names@2.1.3: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} @@ -5749,6 +6644,10 @@ packages: resolution: {integrity: sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==} engines: {node: '>=8'} + mem@8.1.1: + resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==} + engines: {node: '>=10'} + memory-fs@0.4.1: resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} @@ -5794,6 +6693,10 @@ packages: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + miller-rabin@4.0.1: resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} hasBin: true @@ -5819,6 +6722,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-fn@3.1.0: + resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} + engines: {node: '>=8'} + mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -5827,6 +6734,12 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + mini-css-extract-plugin@2.10.0: + resolution: {integrity: sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + mini-css-extract-plugin@2.8.0: resolution: {integrity: sha512-CxmUYPFcTgET1zImteG/LZOy/4T5rTojesQXkSNBiquhydn78tfbCE9sjIjnJ/UcjNjOC1bphTCCW5rrS7cXAg==} engines: {node: '>= 12.13.0'} @@ -5846,6 +6759,9 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} @@ -5943,8 +6859,13 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nan@2.18.0: - resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} + nan@2.25.0: + resolution: {integrity: sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} @@ -5995,6 +6916,9 @@ packages: node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node-watch@0.7.3: resolution: {integrity: sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==} engines: {node: '>=6'} @@ -6015,10 +6939,6 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - normalize-url@4.5.1: resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==} engines: {node: '>=8'} @@ -6065,6 +6985,10 @@ packages: object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -6077,6 +7001,10 @@ packages: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + object.pick@1.3.0: resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} engines: {node: '>=0.10.0'} @@ -6224,8 +7152,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-asn1@5.1.6: - resolution: {integrity: sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==} + parse-asn1@5.1.9: + resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==} + engines: {node: '>= 0.10'} parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} @@ -6307,17 +7236,24 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} + pbkdf2@3.1.5: + resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} + engines: {node: '>= 0.10'} picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -6334,8 +7270,8 @@ packages: resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} engines: {node: '>=0.10.0'} - pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} pkg-dir@3.0.0: @@ -6349,6 +7285,9 @@ packages: pkg-entry-points@1.1.0: resolution: {integrity: sha512-9vL2T/he5Kb97GVY+V3Ih4jCC1lF3PQGIDUJIUqKM4Q6twmhrUSAa0OFj+kb8IEs4wYzEgB6kcc4oYy21kZnQw==} + pkg-entry-points@1.1.1: + resolution: {integrity: sha512-BhZa7iaPmB4b3vKIACoppyUoYn8/sFs17VJJtzrzPZvEnN2nqrgg911tdL65lA2m1ml6UI3iPeYbZQ4VXpn1mA==} + pkg-up@2.0.0: resolution: {integrity: sha512-fjAPuiws93rm7mPUu21RdBnkeZNrbfCFCwfAhPWY+rR3zG0ubpe5cEReHOw5fIbfmsxEV/g2kSxGTATY3Bpnwg==} engines: {node: '>=4'} @@ -6365,14 +7304,18 @@ packages: resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} engines: {node: '>=0.10.0'} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + postcss-at-rules-variables@0.3.0: resolution: {integrity: sha512-TmzLAG17XTsRYSqcpk96zXie+oU30Tn0F5f8mgSD3JagIAmhWUH7/3CLxY8XL8BhqiIjGiCSMuolIxwB4TE4NA==} engines: {node: '>=10'} peerDependencies: postcss: ^8.1.10 - postcss-attribute-case-insensitive@6.0.2: - resolution: {integrity: sha512-IRuCwwAAQbgaLhxQdQcIIK0dCVXg3XDUnzgKD8iwdiYdwU4rMWRWyl/W9/0nA4ihVpq5pyALiHB2veBJ0292pw==} + postcss-attribute-case-insensitive@6.0.3: + resolution: {integrity: sha512-KHkmCILThWBRtg+Jn1owTnHPnFit4OkqS+eKiGEOPIGke54DCeYGJ6r0Fx/HjfE9M9kznApCLcU0DvnPchazMQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6383,20 +7326,20 @@ packages: peerDependencies: postcss: ^8.4.6 - postcss-color-functional-notation@6.0.4: - resolution: {integrity: sha512-YBzfVvVUNR4U3N0imzU1NPKCuwxzfHJkEP6imJxzsJ8LozRKeej9mWmg9Ef1ovJdb0xrGTRVzUxgTrMun5iw/Q==} + postcss-color-functional-notation@6.0.14: + resolution: {integrity: sha512-dNUX+UH4dAozZ8uMHZ3CtCNYw8fyFAmqqdcyxMr7PEdM9jLXV19YscoYO0F25KqZYhmtWKQ+4tKrIZQrwzwg7A==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - postcss-color-hex-alpha@9.0.3: - resolution: {integrity: sha512-7sEHU4tAS6htlxun8AB9LDrCXoljxaC34tFVRlYKcvO+18r5fvGiXgv5bQzN40+4gXLCyWSMRK5FK31244WcCA==} + postcss-color-hex-alpha@9.0.4: + resolution: {integrity: sha512-XQZm4q4fNFqVCYMGPiBjcqDhuG7Ey2xrl99AnDJMyr5eDASsAGalndVgHZF8i97VFNy1GQeZc4q2ydagGmhelQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - postcss-color-rebeccapurple@9.0.2: - resolution: {integrity: sha512-f+RDEAPW2m8UbJWkSpRfV+QxhSaQhDMihI75DVGJJh4oRIoegjheeRtINFJum9D8BqGJcvD4GLjggTvCwZ4zuA==} + postcss-color-rebeccapurple@9.0.3: + resolution: {integrity: sha512-ruBqzEFDYHrcVq3FnW3XHgwRqVMrtEPLBtD7K2YmsLKVc2jbkxzzNEctJKsPCpDZ+LeMHLKRDoSShVefGc+CkQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6406,20 +7349,20 @@ packages: peerDependencies: postcss: ^8 - postcss-custom-media@10.0.2: - resolution: {integrity: sha512-zcEFNRmDm2fZvTPdI1pIW3W//UruMcLosmMiCdpQnrCsTRzWlKQPYMa1ud9auL0BmrryKK1+JjIGn19K0UjO/w==} + postcss-custom-media@10.0.8: + resolution: {integrity: sha512-V1KgPcmvlGdxTel4/CyQtBJEFhMVpEmRGFrnVtgfGIHj5PJX9vO36eFBxKBeJn+aCDTed70cc+98Mz3J/uVdGQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - postcss-custom-properties@13.3.4: - resolution: {integrity: sha512-9YN0gg9sG3OH+Z9xBrp2PWRb+O4msw+5Sbp3ZgqrblrwKspXVQe5zr5sVqi43gJGwW/Rv1A483PRQUzQOEewvA==} + postcss-custom-properties@13.3.12: + resolution: {integrity: sha512-oPn/OVqONB2ZLNqN185LDyaVByELAA/u3l2CS2TS16x2j2XsmV4kd8U49+TMxmUsEU9d8fB/I10E6U7kB0L1BA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - postcss-custom-selectors@7.1.6: - resolution: {integrity: sha512-svsjWRaxqL3vAzv71dV0/65P24/FB8TbPX+lWyyf9SZ7aZm4S4NhCn7N3Bg+Z5sZunG3FS8xQ80LrCU9hb37cw==} + postcss-custom-selectors@7.1.12: + resolution: {integrity: sha512-ctIoprBMJwByYMGjXG0F7IT2iMF2hnamQ+aWZETyBM0aAlyaYdVZTeUkk8RB+9h9wP+NdN3f01lfvKl2ZSqC0g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6430,8 +7373,8 @@ packages: peerDependencies: postcss: ^8.4 - postcss-double-position-gradients@5.0.3: - resolution: {integrity: sha512-QKYpwmaSm6HcdS0ndAuWSNNMv78R1oSySoh3mYBmctHWr2KWcwPJVakdOyU4lvFVW0GRu9wfIQwGeM4p3xU9ow==} + postcss-double-position-gradients@5.0.7: + resolution: {integrity: sha512-1xEhjV9u1s4l3iP5lRt1zvMjI/ya8492o9l/ivcxHhkO3nOz16moC4JpMxDUGrOs4R3hX+KWT7gKoV842cwRgg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6464,8 +7407,8 @@ packages: peerDependencies: postcss: ^8.4 - postcss-image-set-function@6.0.2: - resolution: {integrity: sha512-/O1xwqpJiz/apxGQi7UUfv1xUcorvkHZfvCYHPpRxxZj2WvjD0rg0+/+c+u5/Do5CpUg3XvfYxMrhcnjW1ArDQ==} + postcss-image-set-function@6.0.3: + resolution: {integrity: sha512-i2bXrBYzfbRzFnm+pVuxVePSTCRiNmlfssGI4H0tJQvDue+yywXwUxe68VyzXs7cGtMaH6MCLY6IbCShrSroCw==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6476,28 +7419,34 @@ packages: peerDependencies: postcss: ^8.0.0 - postcss-js@4.0.1: - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: postcss: ^8.4.21 - postcss-lab-function@6.0.9: - resolution: {integrity: sha512-PKFAVTBEWJYsoSTD7Kp/OzeiMsXaLX39Pv75XgUyF5VrbMfeTw+JqCGsvDP3dPhclh6BemdCFHcjXBG9gO4UCg==} + postcss-lab-function@6.0.19: + resolution: {integrity: sha512-vwln/mgvFrotJuGV8GFhpAOu9iGf3pvTBr6dLPDmUcqVD5OsQpEFyQMAFTxSxWXGEzBj6ld4pZ/9GDfEpXvo0g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} peerDependencies: + jiti: '>=1.21.0' postcss: '>=8.0.9' - ts-node: '>=9.0.0' + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: + jiti: + optional: true postcss: optional: true - ts-node: + tsx: + optional: true + yaml: optional: true postcss-logical@7.0.1: @@ -6536,14 +7485,14 @@ packages: peerDependencies: postcss: ^8.1.0 - postcss-nested@6.0.1: - resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 - postcss-nesting@12.0.2: - resolution: {integrity: sha512-63PpJHSeNs93S3ZUIyi+7kKx4JqOIEJ6QYtG3x+0qA4J03+4n0iwsyA1GAHyWxsHYljQS4/4ZK1o2sMi70b5wQ==} + postcss-nesting@12.1.5: + resolution: {integrity: sha512-N1NgI1PDCiAGWPTYrwqm8wpjv0bgDmkYHH72pNsqTCv9CObxjxftdYu6AKtGN+pnJa7FQjMm3v4sp8QJbFsYdQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6571,14 +7520,14 @@ packages: peerDependencies: postcss: ^8.4 - postcss-preset-env@9.3.0: - resolution: {integrity: sha512-ycw6doPrqV6QxDCtgiyGDef61bEfiSc59HGM4gOw/wxQxmKnhuEery61oOC/5ViENz/ycpRsuhTexs1kUBTvVw==} + postcss-preset-env@9.6.0: + resolution: {integrity: sha512-Lxfk4RYjUdwPCYkc321QMdgtdCP34AeI94z+/8kVmqnTIlD4bMRQeGcMZgwz8BxHrzQiFXYIR5d7k/9JMs2MEA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 - postcss-pseudo-class-any-link@9.0.1: - resolution: {integrity: sha512-cKYGGZ9yzUZi+dZd7XT2M8iSDfo+T2Ctbpiizf89uBTBfIpZpjvTavzIJXpCReMVXSKROqzpxClNu6fz4DHM0Q==} + postcss-pseudo-class-any-link@9.0.2: + resolution: {integrity: sha512-HFSsxIqQ9nA27ahyfH37cRWGk3SYyQLpk0LiWw/UGMV4VKT5YG2ONee4Pz/oFesnK0dn2AjcyequDbIjKJgB0g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6597,8 +7546,8 @@ packages: peerDependencies: postcss: ^8.3.3 - postcss-selector-not@7.0.1: - resolution: {integrity: sha512-1zT5C27b/zeJhchN7fP0kBr16Cc61mu7Si9uWWLoA3Px/D9tIJPKchJCkUH3tPO5D0pCFmGeApAv8XpXBQJ8SQ==} + postcss-selector-not@7.0.2: + resolution: {integrity: sha512-/SSxf/90Obye49VZIfc0ls4H0P6i6V1iHv0pzZH8SdgvZOPFkF37ef1r5cyWcMflJSFJ5bfuoluTnFnBBFiuSA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4 @@ -6607,6 +7556,10 @@ packages: resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==} engines: {node: '>=4'} + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + postcss-simple-vars@6.0.3: resolution: {integrity: sha512-fkNn4Zio8vN4vIig9IFdb8lVlxWnYR769RgvxCM6YWlFKie/nQaOcaMMMFz/s4gsfHW4/5bJW+i57zD67mQU7g==} engines: {node: '>=10.0'} @@ -6626,6 +7579,10 @@ packages: resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + preact@10.12.1: resolution: {integrity: sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==} @@ -6695,50 +7652,50 @@ packages: proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} - prosemirror-changeset@2.2.1: - resolution: {integrity: sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==} + prosemirror-changeset@2.4.0: + resolution: {integrity: sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng==} prosemirror-collab@1.3.1: resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} - prosemirror-commands@1.6.0: - resolution: {integrity: sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==} + prosemirror-commands@1.7.1: + resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} - prosemirror-dropcursor@1.8.1: - resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} + prosemirror-dropcursor@1.8.2: + resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} - prosemirror-gapcursor@1.3.2: - resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} + prosemirror-gapcursor@1.4.0: + resolution: {integrity: sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==} - prosemirror-history@1.4.1: - resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==} + prosemirror-history@1.5.0: + resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} - prosemirror-inputrules@1.4.0: - resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==} + prosemirror-inputrules@1.5.1: + resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} - prosemirror-keymap@1.2.2: - resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} - prosemirror-markdown@1.13.1: - resolution: {integrity: sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==} + prosemirror-markdown@1.13.4: + resolution: {integrity: sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==} - prosemirror-menu@1.2.4: - resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} + prosemirror-menu@1.3.0: + resolution: {integrity: sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==} - prosemirror-model@1.22.3: - resolution: {integrity: sha512-V4XCysitErI+i0rKFILGt/xClnFJaohe/wrrlT2NSZ+zk8ggQfDH4x2wNK7Gm0Hp4CIoWizvXFP7L9KMaCuI0Q==} + prosemirror-model@1.25.4: + resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} - prosemirror-schema-basic@1.2.3: - resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==} + prosemirror-schema-basic@1.2.4: + resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} - prosemirror-schema-list@1.4.1: - resolution: {integrity: sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==} + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} - prosemirror-state@1.4.3: - resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} + prosemirror-state@1.4.4: + resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} - prosemirror-tables@1.5.0: - resolution: {integrity: sha512-VMx4zlYWm7aBlZ5xtfJHpqa3Xgu3b7srV54fXYnXgsAcIGRqKSrhiK3f89omzzgaAgAtDOV4ImXnLKhVfheVNQ==} + prosemirror-tables@1.8.5: + resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} prosemirror-trailing-node@3.0.0: resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} @@ -6747,11 +7704,11 @@ packages: prosemirror-state: ^1.4.2 prosemirror-view: ^1.33.8 - prosemirror-transform@1.10.0: - resolution: {integrity: sha512-9UOgFSgN6Gj2ekQH5CTDJ8Rp/fnKR2IkYfGdzzp5zQMFsS4zDllLVx/+jGcX86YlACpG7UR5fwAXiWzxqWtBTg==} + prosemirror-transform@1.11.0: + resolution: {integrity: sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==} - prosemirror-view@1.34.3: - resolution: {integrity: sha512-mKZ54PrX19sSaQye+sef+YjBbNu2voNwLS1ivb6aD2IRmxRGW64HU9B644+7OfJStGLyxvOreKqEgfvXa91WIA==} + prosemirror-view@1.41.6: + resolution: {integrity: sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg==} proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} @@ -6769,6 +7726,9 @@ packages: pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pumpify@1.5.1: resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} @@ -6791,6 +7751,10 @@ packages: resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} engines: {node: '>=0.6'} + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + querystring-es3@0.2.1: resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} engines: {node: '>=0.4.x'} @@ -6880,6 +7844,10 @@ packages: resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} engines: {node: '>=4'} + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + regenerate@1.4.2: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} @@ -6907,6 +7875,10 @@ packages: resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} engines: {node: '>=4'} + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + registry-auth-token@4.2.2: resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==} engines: {node: '>=6.0.0'} @@ -6915,6 +7887,13 @@ packages: resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==} engines: {node: '>=8'} + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + hasBin: true + regjsparser@0.9.1: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true @@ -6923,6 +7902,10 @@ packages: resolution: {integrity: sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==} engines: {node: '>=8'} + remote-promises@1.0.0: + resolution: {integrity: sha512-+9LztCwsGzC8VXvm9UuA3qGhLIf4HvMbbev0+A+azLLUYHm3BK4C1BWxiZa45FPQ7JdfpHi4kVT7zT5F2E0iuQ==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + remove-trailing-separator@1.1.0: resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} @@ -7000,6 +7983,15 @@ packages: resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} deprecated: https://github.com/lydell/resolve-url#deprecated + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -7039,8 +8031,9 @@ packages: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + ripemd160@2.0.3: + resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} + engines: {node: '>= 0.8'} rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} @@ -7136,6 +8129,9 @@ packages: sc-errors@2.0.3: resolution: {integrity: sha512-HNpClBWpo7zxLBnhH0U/FbC19Gl3OJlVyPxo9Q2eomfdWgYfd84uhqe0LRgybc+nSpcYjtF08+/dKPLugLMMeQ==} + sc-errors@3.0.0: + resolution: {integrity: sha512-rIqv2HTPb9DVreZwK/DV0ytRUqyw2DbDcoB9XTKjEQL7oMEQKsfPA8V8dGGr7p8ZYfmvaRIGZ4Wu5qwvs/hGDA==} + sc-formatter@4.0.0: resolution: {integrity: sha512-MgUIvuca+90fBrCWY5LdlU9YUWjlkPFwdpvmomcwQEu3t2id/6YHdG2nhB6o7nhRp4ocfmcXQTh00r/tJtynSg==} @@ -7155,6 +8151,10 @@ packages: resolution: {integrity: sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==} engines: {node: '>= 12.13.0'} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -7168,6 +8168,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -7189,6 +8194,10 @@ packages: resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} engines: {node: '>= 0.4'} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} engines: {node: '>= 0.4'} @@ -7206,8 +8215,9 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} hasBin: true shallow-clone@3.0.1: @@ -7236,10 +8246,26 @@ packages: shellwords@0.1.1: resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + side-channel@1.0.5: resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} engines: {node: '>= 0.4'} + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -7312,6 +8338,10 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + source-map-resolve@0.5.3: resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} deprecated: See https://github.com/lydell/source-map-resolve#deprecated @@ -7529,8 +8559,8 @@ packages: engines: {node: ^14.13.1 || >=16.0.0} hasBin: true - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true @@ -7584,15 +8614,15 @@ packages: resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} engines: {node: ^14.18.0 || >=16.0.0} - tabbable@5.3.3: - resolution: {integrity: sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} table@6.8.1: resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} engines: {node: '>=10.0.0'} - tailwindcss@3.4.1: - resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==} + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} engines: {node: '>=14.0.0'} hasBin: true @@ -7608,12 +8638,16 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + temp@0.9.4: resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} engines: {node: '>=6.0.0'} - terser-webpack-plugin@1.4.5: - resolution: {integrity: sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==} + terser-webpack-plugin@1.4.6: + resolution: {integrity: sha512-2lBVf/VMVIddjSn3GqbT90GvIJ/eYXJkt8cTzU7NbjKqK8fwv18Ftr4PlbF46b/e88743iZFL5Dtr/rC4hjIeA==} engines: {node: '>= 6.9.0'} peerDependencies: webpack: ^4.0.0 @@ -7682,6 +8716,10 @@ packages: tiny-lr@2.0.0: resolution: {integrity: sha512-f6nh0VMRvhGx4KCeK1lQ/jaL0Zdb5WdR+Jk8q9OSUQnaSDxAEGH1fgqLZ+cMl5EW3F2MGnCsalBO1IsnnogW1Q==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + tmp@0.0.28: resolution: {integrity: sha512-c2mmfiBmND6SOVxzogm1oda0OJ1HZVIk/5n26N59dDTh80MUeavpiCls4PGAdkX1PFkKokLpcf7prSjCeXLsJg==} engines: {node: '>=0.4.0'} @@ -7704,6 +8742,10 @@ packages: to-arraybuffer@1.0.1: resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} + engines: {node: '>= 0.4'} + to-fast-properties@1.0.3: resolution: {integrity: sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==} engines: {node: '>=0.10.0'} @@ -7793,6 +8835,10 @@ packages: resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} engines: {node: '>=10'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -7801,6 +8847,10 @@ packages: resolution: {integrity: sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==} engines: {node: '>= 0.4'} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.0: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} engines: {node: '>= 0.4'} @@ -7856,6 +8906,10 @@ packages: resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} engines: {node: '>=4'} + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + unicode-property-aliases-ecmascript@2.1.0: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} @@ -7904,6 +8958,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -7915,8 +8975,9 @@ packages: resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==} engines: {node: '>=4'} - url@0.11.3: - resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} use@3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} @@ -8056,6 +9117,10 @@ packages: resolution: {integrity: sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==} engines: {node: '>= 0.4'} + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -8117,8 +9182,8 @@ packages: utf-8-validate: optional: true - ws@8.16.0: - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -8154,10 +9219,6 @@ packages: resolution: {integrity: sha512-Hv9xxHtsJ9228wNhk03xnlDReUuWVvHwM4rIbjdAXYvHLs17xjuyF50N6XXFMN6N0omBaqgOok/MCK3At9fTAg==} engines: {node: ^4.5 || 6.* || >= 7.*} - yaml@2.3.4: - resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} - engines: {node: '>= 14'} - yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -8194,8 +9255,16 @@ snapshots: '@babel/highlight': 7.23.4 chalk: 2.4.2 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.23.5': {} + '@babel/compat-data@7.29.0': {} + '@babel/core@7.23.2': dependencies: '@ampproject/remapping': 2.2.1 @@ -8216,6 +9285,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/eslint-parser@7.22.15(@babel/core@7.23.2)(eslint@8.52.0)': dependencies: '@babel/core': 7.23.2 @@ -8224,6 +9313,14 @@ snapshots: eslint-visitor-keys: 2.1.0 semver: 6.3.1 + '@babel/eslint-parser@7.28.6(@babel/core@7.23.2)(eslint@8.52.0)': + dependencies: + '@babel/core': 7.23.2 + '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 + eslint: 8.52.0 + eslint-visitor-keys: 2.1.0 + semver: 6.3.1 + '@babel/generator@7.23.6': dependencies: '@babel/types': 7.23.9 @@ -8231,10 +9328,22 @@ snapshots: '@jridgewell/trace-mapping': 0.3.22 jsesc: 2.5.2 + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.22.5': dependencies: '@babel/types': 7.23.9 + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': dependencies: '@babel/types': 7.23.9 @@ -8247,6 +9356,14 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8260,6 +9377,45 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.23.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8267,6 +9423,27 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.22.5 + regexpu-core: 5.3.2 + semver: 6.3.1 + + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8278,6 +9455,39 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-define-polyfill-provider@0.6.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + '@babel/helper-define-polyfill-provider@0.6.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + '@babel/helper-environment-visitor@7.22.20': {} '@babel/helper-function-name@7.23.0': @@ -8285,6 +9495,8 @@ snapshots: '@babel/template': 7.23.9 '@babel/types': 7.23.9 + '@babel/helper-globals@7.28.0': {} + '@babel/helper-hoist-variables@7.22.5': dependencies: '@babel/types': 7.23.9 @@ -8293,10 +9505,24 @@ snapshots: dependencies: '@babel/types': 7.23.9 - '@babel/helper-module-imports@7.22.15': + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.22.15': dependencies: '@babel/types': 7.23.9 + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8306,12 +9532,45 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-module-transforms@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-optimise-call-expression@7.22.5': dependencies: '@babel/types': 7.23.9 + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + '@babel/helper-plugin-utils@7.22.5': {} + '@babel/helper-plugin-utils@7.28.6': {} + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8319,6 +9578,31 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 + + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-replace-supers@7.22.20(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8326,6 +9610,31 @@ snapshots: '@babel/helper-member-expression-to-functions': 7.23.0 '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-simple-access@7.22.5': dependencies: '@babel/types': 7.23.9 @@ -8334,22 +9643,43 @@ snapshots: dependencies: '@babel/types': 7.23.9 + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-split-export-declaration@7.22.6': dependencies: '@babel/types': 7.23.9 '@babel/helper-string-parser@7.23.4': {} + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.22.20': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.23.5': {} + '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-wrap-function@7.22.20': dependencies: '@babel/helper-function-name': 7.23.0 '@babel/template': 7.23.9 '@babel/types': 7.23.9 + '@babel/helper-wrap-function@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helpers@7.23.9': dependencies: '@babel/template': 7.23.9 @@ -8358,6 +9688,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + '@babel/highlight@7.23.4': dependencies: '@babel/helper-validator-identifier': 7.22.20 @@ -8368,11 +9703,56 @@ snapshots: dependencies: '@babel/types': 7.23.9 + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8380,18 +9760,71 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.2) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.29.0) + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-proposal-decorators@7.23.2(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8401,6 +9834,15 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.23.2) + '@babel/plugin-proposal-decorators@7.23.2(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.29.0) + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8420,10 +9862,20 @@ snapshots: '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-proposal-private-property-in-object@7.21.11(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8432,387 +9884,1461 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.2) + '@babel/plugin-proposal-private-property-in-object@7.21.11(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-decorators@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-decorators@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.2)': + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.2)': + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.2)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.2)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.2)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.2)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.2)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-environment-visitor': 7.22.20 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.2) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.2) - '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.2) - '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.2) - '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.2)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.2) - '@babel/helper-split-export-declaration': 7.22.6 - globals: 11.12.0 - '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/template': 7.23.9 - '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.2)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-function-name': 7.23.0 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.2) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.2) + + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.29.0) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.23.2) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.2) + + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.29.0) + + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.2) + + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.2) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.29.0) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.23.2) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.23.9 + + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.23.9 + + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 + + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 + + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.2) + + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) + + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.2) + + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.29.0) + + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.2) + + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.2) + + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.2) + + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.2) + + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.2 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.2) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.2) + + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.29.0) + + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.23.2) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.23.2) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.2) + + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.29.0) + + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.2) + + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.2) + + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.2) + + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + regenerator-transform: 0.15.2 + + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + regenerator-transform: 0.15.2 + + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.2) - '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-simple-access': 7.22.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.2)': + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) + '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-identifier': 7.22.20 + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.2) + babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.2) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.2) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.2) + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.2)': + '@babel/plugin-transform-runtime@7.29.0(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.23.2) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.23.2) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.23.2) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-runtime@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.2) - '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.23.2)': dependencies: - '@babel/compat-data': 7.23.5 '@babel/core': 7.23.2 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.2) + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.2)': + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.2) - '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - regenerator-transform: 0.15.2 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.2)': + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 - babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.2) - babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.2) - babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.2) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.2)': + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.2)': dependencies: @@ -8822,6 +11348,36 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.2) + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.29.0) + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-typescript@7.4.5(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8847,24 +11403,93 @@ snapshots: '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.2) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.23.2) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/polyfill@7.12.1': dependencies: core-js: 2.6.12 @@ -8956,6 +11581,244 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/preset-env@7.23.9(@babel/core@7.29.0)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.29.0) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.29.0) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.29.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.29.0) + core-js-compat: 3.36.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-env@7.29.0(@babel/core@7.23.2)': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.23.2 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.23.2) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.2) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.2) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.23.2) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.23.2) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.23.2) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.23.2) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.23.2) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.23.2) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.23.2) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.23.2) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.2) + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.23.2) + babel-plugin-polyfill-corejs3: 0.14.0(@babel/core@7.23.2) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.23.2) + core-js-compat: 3.48.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-env@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.14.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 @@ -8963,6 +11826,13 @@ snapshots: '@babel/types': 7.23.9 esutils: 2.0.3 + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/types': 7.23.9 + esutils: 2.0.3 + '@babel/regjsgen@0.8.0': {} '@babel/runtime@7.12.18': @@ -8973,12 +11843,20 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.28.6': {} + '@babel/template@7.23.9': dependencies: '@babel/code-frame': 7.23.5 '@babel/parser': 7.23.9 '@babel/types': 7.23.9 + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@babel/traverse@7.23.9': dependencies: '@babel/code-frame': 7.23.5 @@ -8994,12 +11872,29 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.23.9': dependencies: '@babel/helper-string-parser': 7.23.4 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@cnakazawa/watch@1.0.4': dependencies: exec-sh: 0.3.6 @@ -9008,95 +11903,121 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@csstools/cascade-layer-name-parser@1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': + '@csstools/cascade-layer-name-parser@1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 - '@csstools/color-helpers@4.0.0': {} + '@csstools/color-helpers@4.2.1': {} - '@csstools/css-calc@1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': + '@csstools/css-calc@1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 - '@csstools/css-color-parser@1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': + '@csstools/css-color-parser@2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/color-helpers': 4.0.0 - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/color-helpers': 4.2.1 + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 '@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3)': dependencies: '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1)': + dependencies: + '@csstools/css-tokenizer': 2.4.1 + '@csstools/css-tokenizer@2.2.3': {} + '@csstools/css-tokenizer@2.4.1': {} + + '@csstools/media-query-list-parser@2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': + dependencies: + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/media-query-list-parser@2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3)': dependencies: '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-cascade-layers@4.0.2(postcss@8.4.35)': + '@csstools/postcss-cascade-layers@4.0.6(postcss@8.4.35)': dependencies: - '@csstools/selector-specificity': 3.0.1(postcss-selector-parser@6.0.15) + '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.2) postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 - '@csstools/postcss-color-function@3.0.9(postcss@8.4.35)': + '@csstools/postcss-color-function@3.0.19(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - '@csstools/postcss-color-mix-function@2.0.9(postcss@8.4.35)': + '@csstools/postcss-color-mix-function@2.0.19(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - '@csstools/postcss-exponential-functions@1.0.3(postcss@8.4.35)': + '@csstools/postcss-content-alt-text@1.0.0(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) + postcss: 8.4.35 + + '@csstools/postcss-exponential-functions@1.0.9(postcss@8.4.35)': + dependencies: + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.35 - '@csstools/postcss-font-format-keywords@3.0.1(postcss@8.4.35)': + '@csstools/postcss-font-format-keywords@3.0.2(postcss@8.4.35)': dependencies: + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 - '@csstools/postcss-gamut-mapping@1.0.2(postcss@8.4.35)': + '@csstools/postcss-gamut-mapping@1.0.11(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.35 - '@csstools/postcss-gradients-interpolation-method@4.0.9(postcss@8.4.35)': + '@csstools/postcss-gradients-interpolation-method@4.0.20(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - '@csstools/postcss-hwb-function@3.0.8(postcss@8.4.35)': + '@csstools/postcss-hwb-function@3.0.18(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - '@csstools/postcss-ic-unit@3.0.3(postcss@8.4.35)': + '@csstools/postcss-ic-unit@3.0.7(postcss@8.4.35)': dependencies: - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 @@ -9104,11 +12025,19 @@ snapshots: dependencies: postcss: 8.4.35 - '@csstools/postcss-is-pseudo-class@4.0.4(postcss@8.4.35)': + '@csstools/postcss-is-pseudo-class@4.0.8(postcss@8.4.35)': dependencies: - '@csstools/selector-specificity': 3.0.1(postcss-selector-parser@6.0.15) + '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.2) + postcss: 8.4.35 + postcss-selector-parser: 6.1.2 + + '@csstools/postcss-light-dark-function@1.0.8(postcss@8.4.35)': + dependencies: + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - postcss-selector-parser: 6.0.15 '@csstools/postcss-logical-float-and-clear@2.0.1(postcss@8.4.35)': dependencies: @@ -9127,28 +12056,30 @@ snapshots: postcss: 8.4.35 postcss-value-parser: 4.2.0 - '@csstools/postcss-logical-viewport-units@2.0.5(postcss@8.4.35)': + '@csstools/postcss-logical-viewport-units@2.0.11(postcss@8.4.35)': dependencies: - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-tokenizer': 2.4.1 + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - '@csstools/postcss-media-minmax@1.1.2(postcss@8.4.35)': + '@csstools/postcss-media-minmax@1.1.8(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) postcss: 8.4.35 - '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.5(postcss@8.4.35)': + '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.11(postcss@8.4.35)': dependencies: - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) postcss: 8.4.35 - '@csstools/postcss-nested-calc@3.0.1(postcss@8.4.35)': + '@csstools/postcss-nested-calc@3.0.2(postcss@8.4.35)': dependencies: + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 @@ -9157,60 +12088,74 @@ snapshots: postcss: 8.4.35 postcss-value-parser: 4.2.0 - '@csstools/postcss-oklab-function@3.0.9(postcss@8.4.35)': + '@csstools/postcss-oklab-function@3.0.19(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - '@csstools/postcss-progressive-custom-properties@3.0.3(postcss@8.4.35)': + '@csstools/postcss-progressive-custom-properties@3.3.0(postcss@8.4.35)': dependencies: postcss: 8.4.35 postcss-value-parser: 4.2.0 - '@csstools/postcss-relative-color-syntax@2.0.9(postcss@8.4.35)': + '@csstools/postcss-relative-color-syntax@2.0.19(postcss@8.4.35)': dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 '@csstools/postcss-scope-pseudo-class@3.0.1(postcss@8.4.35)': dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 - '@csstools/postcss-stepped-value-functions@3.0.4(postcss@8.4.35)': + '@csstools/postcss-stepped-value-functions@3.0.10(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.35 - '@csstools/postcss-text-decoration-shorthand@3.0.4(postcss@8.4.35)': + '@csstools/postcss-text-decoration-shorthand@3.0.7(postcss@8.4.35)': dependencies: - '@csstools/color-helpers': 4.0.0 + '@csstools/color-helpers': 4.2.1 postcss: 8.4.35 postcss-value-parser: 4.2.0 - '@csstools/postcss-trigonometric-functions@3.0.4(postcss@8.4.35)': + '@csstools/postcss-trigonometric-functions@3.0.10(postcss@8.4.35)': dependencies: - '@csstools/css-calc': 1.1.6(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.35 '@csstools/postcss-unset-value@3.0.1(postcss@8.4.35)': dependencies: postcss: 8.4.35 + '@csstools/selector-resolve-nested@1.1.0(postcss-selector-parser@6.1.2)': + dependencies: + postcss-selector-parser: 6.1.2 + '@csstools/selector-specificity@3.0.1(postcss-selector-parser@6.0.15)': dependencies: postcss-selector-parser: 6.0.15 + '@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.1.2)': + dependencies: + postcss-selector-parser: 6.1.2 + + '@csstools/utilities@1.0.0(postcss@8.4.35)': + dependencies: + postcss: 8.4.35 + '@ember-data/adapter@4.12.5(@ember-data/store@4.12.5(@babel/core@7.23.2)(@ember-data/graph@4.12.5)(@ember-data/json-api@4.12.5)(@ember-data/legacy-compat@4.12.5)(@ember-data/model@4.12.5)(@ember-data/tracking@4.12.5)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(@ember/string@3.1.1)(ember-inflector@4.0.2)': dependencies: '@ember-data/private-build-infra': 4.12.5 @@ -9418,7 +12363,7 @@ snapshots: '@ember/render-modifiers@2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': dependencies: - '@embroider/macros': 1.13.5 + '@embroider/macros': 1.20.0(@babel/core@7.23.2) ember-cli-babel: 7.26.11 ember-modifier-manager-polyfill: 1.2.0(@babel/core@7.23.2) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) @@ -9457,10 +12402,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@embroider/addon-shim@1.10.2': + dependencies: + '@embroider/shared-internals': 3.0.2 + broccoli-funnel: 3.0.8 + common-ancestor-path: 1.0.1 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + '@embroider/addon-shim@1.8.3': dependencies: '@embroider/shared-internals': 1.8.3 - semver: 7.6.0 + semver: 7.7.4 '@embroider/addon-shim@1.8.7': dependencies: @@ -9470,15 +12424,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@embroider/addon-shim@1.8.9': - dependencies: - '@embroider/shared-internals': 2.7.0 - broccoli-funnel: 3.0.8 - common-ancestor-path: 1.0.1 - semver: 7.6.0 - transitivePeerDependencies: - - supports-color - '@embroider/addon@0.30.0': dependencies: ember-cli-babel: 7.26.11 @@ -9498,15 +12443,48 @@ snapshots: transitivePeerDependencies: - supports-color + '@embroider/macros@1.20.0(@babel/core@7.23.2)': + dependencies: + '@embroider/shared-internals': 3.0.2 + assert-never: 1.4.0 + babel-import-util: 3.0.1 + ember-cli-babel: 8.3.1(@babel/core@7.23.2) + find-up: 5.0.0 + lodash: 4.17.23 + resolve: 1.22.11 + semver: 7.7.4 + transitivePeerDependencies: + - '@babel/core' + - supports-color + + '@embroider/macros@1.20.0(@babel/core@7.29.0)': + dependencies: + '@embroider/shared-internals': 3.0.2 + assert-never: 1.4.0 + babel-import-util: 3.0.1 + ember-cli-babel: 8.3.1(@babel/core@7.29.0) + find-up: 5.0.0 + lodash: 4.17.23 + resolve: 1.22.11 + semver: 7.7.4 + transitivePeerDependencies: + - '@babel/core' + - supports-color + + '@embroider/reverse-exports@0.2.0': + dependencies: + mem: 8.1.1 + resolve.exports: 2.0.3 + '@embroider/shared-internals@1.8.3': dependencies: babel-import-util: 1.4.1 ember-rfc176-data: 0.3.18 fs-extra: 9.1.0 js-string-escape: 1.0.1 - lodash: 4.17.21 + lodash: 4.17.23 resolve-package-path: 4.0.3 - semver: 7.6.0 + semver: 7.7.4 typescript-memoize: 1.1.1 '@embroider/shared-internals@2.5.2': @@ -9523,17 +12501,37 @@ snapshots: transitivePeerDependencies: - supports-color - '@embroider/shared-internals@2.7.0': + '@embroider/shared-internals@2.9.2': dependencies: - babel-import-util: 2.0.1 - debug: 4.3.4 + babel-import-util: 2.1.1 + debug: 4.4.3 ember-rfc176-data: 0.3.18 fs-extra: 9.1.0 + is-subdir: 1.2.0 js-string-escape: 1.0.1 - lodash: 4.17.21 - minimatch: 3.1.2 + lodash: 4.17.23 + minimatch: 3.1.5 + pkg-entry-points: 1.1.1 resolve-package-path: 4.0.3 - semver: 7.6.0 + semver: 7.7.4 + typescript-memoize: 1.1.1 + transitivePeerDependencies: + - supports-color + + '@embroider/shared-internals@3.0.2': + dependencies: + babel-import-util: 3.0.1 + debug: 4.4.3 + ember-rfc176-data: 0.3.18 + fs-extra: 9.1.0 + is-subdir: 1.2.0 + js-string-escape: 1.0.1 + lodash: 4.17.23 + minimatch: 3.1.5 + pkg-entry-points: 1.1.1 + resolve-package-path: 4.0.3 + resolve.exports: 2.0.3 + semver: 7.7.4 typescript-memoize: 1.1.1 transitivePeerDependencies: - supports-color @@ -9543,13 +12541,34 @@ snapshots: lodash: 4.17.21 resolve: 1.22.8 - '@embroider/util@1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': + '@embroider/util@1.12.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': dependencies: - '@embroider/macros': 1.13.5 + '@embroider/macros': 1.20.0(@babel/core@7.23.2) + broccoli-funnel: 3.0.8 + ember-cli-babel: 7.26.11 + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + transitivePeerDependencies: + - '@babel/core' + - supports-color + + '@embroider/util@1.13.5(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': + dependencies: + '@embroider/macros': 1.20.0(@babel/core@7.23.2) + broccoli-funnel: 3.0.8 + ember-cli-babel: 7.26.11 + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + transitivePeerDependencies: + - '@babel/core' + - supports-color + + '@embroider/util@1.13.5(@babel/core@7.29.0)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))': + dependencies: + '@embroider/macros': 1.20.0(@babel/core@7.29.0) broccoli-funnel: 3.0.8 ember-cli-babel: 7.26.11 ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: + - '@babel/core' - supports-color '@eslint-community/eslint-utils@4.4.0(eslint@8.52.0)': @@ -9584,25 +12603,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@fleetbase/ember-core@0.2.19(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)': + '@fleetbase/ember-core@0.3.12(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(eslint@8.52.0)(webpack@5.89.0)': dependencies: '@babel/core': 7.23.2 - compress-json: 3.1.0 + compress-json: 3.4.0 date-fns: 2.30.0 ember-auto-import: 2.8.1(webpack@5.89.0) - ember-can: 6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-can: 6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 - ember-cli-notifications: 9.0.0 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - ember-concurrency-decorators: 2.0.3(@babel/core@7.23.2) + ember-cli-notifications: 9.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-concurrency: 4.0.6(@babel/core@7.23.2) ember-decorators: 6.1.1 - ember-get-config: 2.1.1 - ember-inflector: 4.0.2 + ember-get-config: 2.1.1(@babel/core@7.23.2) + ember-inflector: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-intl: 6.3.2(@babel/core@7.23.2)(webpack@5.89.0) ember-loading: 2.0.0(@babel/core@7.23.2) ember-local-storage: 2.0.7(@babel/core@7.23.2) - ember-simple-auth: 6.0.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)) + ember-simple-auth: 6.1.0(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(eslint@8.52.0) ember-wormhole: 0.6.0 socketcluster-client: 17.2.2 transitivePeerDependencies: @@ -9612,80 +12630,81 @@ snapshots: - bufferutil - ember-resolver - ember-source + - eslint - supports-color - typescript - utf-8-validate - webpack - '@fleetbase/ember-ui@0.2.32(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(postcss@8.4.35)(rollup@2.79.1)(tracked-built-ins@3.3.0)(webpack@5.89.0)': + '@fleetbase/ember-ui@0.3.21(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(postcss@8.4.35)(rollup@2.79.1)(tracked-built-ins@3.3.0)(webpack@5.89.0)': dependencies: '@babel/core': 7.23.2 '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@ember/string': 3.1.1 '@embroider/addon': 0.30.0 - '@embroider/macros': 1.13.5 + '@embroider/macros': 1.20.0(@babel/core@7.23.2) '@fleetbase/ember-accounting': 0.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - '@floating-ui/dom': 1.6.3 - '@fortawesome/ember-fontawesome': 2.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0) + '@floating-ui/dom': 1.7.5 + '@fortawesome/ember-fontawesome': 2.0.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0) '@fortawesome/fontawesome-svg-core': 6.4.0 '@fortawesome/free-brands-svg-icons': 6.4.0 '@fortawesome/free-solid-svg-icons': 6.4.0 - '@fullcalendar/core': 6.1.10 - '@fullcalendar/daygrid': 6.1.10(@fullcalendar/core@6.1.10) - '@fullcalendar/interaction': 6.1.10(@fullcalendar/core@6.1.10) + '@fullcalendar/core': 6.1.20 + '@fullcalendar/daygrid': 6.1.20(@fullcalendar/core@6.1.20) + '@fullcalendar/interaction': 6.1.20(@fullcalendar/core@6.1.20) '@makepanic/ember-power-calendar-date-fns': 0.4.2 - '@tailwindcss/forms': 0.5.7(tailwindcss@3.4.1) - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/extension-color': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) - '@tiptap/extension-font-family': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) - '@tiptap/extension-highlight': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-image': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-placeholder': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) - '@tiptap/extension-subscript': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-superscript': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-table': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) - '@tiptap/extension-table-cell': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-table-header': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-table-row': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-text-align': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-underline': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-youtube': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/pm': 2.8.0 - '@tiptap/starter-kit': 2.8.0(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) - air-datepicker: 3.4.0 - autonumeric: 4.10.5 - autoprefixer: 10.4.17(postcss@8.4.35) - chart.js: 4.4.1 - chartjs-adapter-date-fns: 3.0.0(chart.js@4.4.1)(date-fns@2.30.0) + '@tailwindcss/forms': 0.5.11(tailwindcss@3.4.19) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/extension-color': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-text-style@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))) + '@tiptap/extension-font-family': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-text-style@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))) + '@tiptap/extension-highlight': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-image': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-placeholder': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) + '@tiptap/extension-subscript': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-superscript': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-table': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) + '@tiptap/extension-table-cell': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-table-header': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-table-row': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-text-align': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-text-style': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-underline': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-youtube': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/pm': 2.27.2 + '@tiptap/starter-kit': 2.27.2 + air-datepicker: 3.6.0 + autonumeric: 4.10.9 + autoprefixer: 10.4.27(postcss@8.4.35) + chart.js: 4.5.1 + chartjs-adapter-date-fns: 3.0.0(chart.js@4.5.1)(date-fns@2.30.0) date-fns: 2.30.0 - ember-animated: 1.1.4(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-animated: 1.1.4(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-auto-import: 2.8.1(webpack@5.89.0) - ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) - ember-can: 6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-basic-dropdown: 8.4.0(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-can: 6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 ember-cli-postcss: 8.2.0 ember-cli-string-helpers: 6.1.0 ember-composable-helpers: 5.0.0 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - ember-concurrency-decorators: 2.0.3(@babel/core@7.23.2) - ember-concurrency-test-waiter: 0.4.0(ember-concurrency@3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))) - ember-file-upload: 8.4.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-modifier@4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(tracked-built-ins@3.3.0)(webpack@5.89.0) - ember-focus-trap: 1.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - ember-get-config: 2.1.1 + ember-concurrency: 4.0.6(@babel/core@7.23.2) + ember-drag-sort: 4.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-file-upload: 8.4.0(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-modifier@4.3.0(@babel/core@7.23.2))(tracked-built-ins@3.3.0)(webpack@5.89.0) + ember-focus-trap: 1.2.0(@babel/core@7.23.2) + ember-get-config: 2.1.1(@babel/core@7.23.2) ember-gridstack: 4.0.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) - ember-inflector: 4.0.2 + ember-inflector: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-leaflet: 5.1.3(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(leaflet@1.9.4)(webpack@5.89.0) ember-loading: 2.0.0(@babel/core@7.23.2) ember-math-helpers: 4.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-modifier: 4.3.0(@babel/core@7.23.2) ember-on-helper: 0.1.0 ember-power-calendar: 0.18.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - ember-power-select: 7.2.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-power-select: 8.6.2(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-basic-dropdown@8.4.0(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-concurrency@4.0.6(@babel/core@7.23.2))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-ref-bucket: 4.1.0(@babel/core@7.23.2) ember-responsive: 5.0.0 - ember-style-modifier: 3.1.1(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-style-modifier: 3.1.1(@babel/core@7.23.2)(@ember/string@3.1.1)(webpack@5.89.0) + ember-tag-input: 3.1.0 ember-truth-helpers: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-window-mock: 0.9.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-wormhole: 0.6.0 @@ -9698,8 +12717,8 @@ snapshots: postcss-each: 1.1.0(postcss@8.4.35) postcss-import: 15.1.0(postcss@8.4.35) postcss-mixins: 9.0.4(postcss@8.4.35) - postcss-preset-env: 9.3.0(postcss@8.4.35) - tailwindcss: 3.4.1 + postcss-preset-env: 9.6.0(postcss@8.4.35) + tailwindcss: 3.4.19 transitivePeerDependencies: - '@ember/test-helpers' - '@glimmer/component' @@ -9714,15 +12733,16 @@ snapshots: - rollup - supports-color - tracked-built-ins - - ts-node + - tsx - webpack - webpack-cli - webpack-command + - yaml - '@fleetbase/fleetops-data@0.1.18(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)': + '@fleetbase/fleetops-data@0.1.25(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(eslint@8.52.0)(webpack@5.89.0)': dependencies: '@babel/core': 7.23.2 - '@fleetbase/ember-core': 0.2.19(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + '@fleetbase/ember-core': 0.3.12(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(eslint@8.52.0)(webpack@5.89.0) date-fns: 2.30.0 ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 @@ -9733,21 +12753,22 @@ snapshots: - bufferutil - ember-resolver - ember-source + - eslint - supports-color - typescript - utf-8-validate - webpack - '@floating-ui/core@1.6.0': + '@floating-ui/core@1.7.4': dependencies: - '@floating-ui/utils': 0.2.1 + '@floating-ui/utils': 0.2.10 - '@floating-ui/dom@1.6.3': + '@floating-ui/dom@1.7.5': dependencies: - '@floating-ui/core': 1.6.0 - '@floating-ui/utils': 0.2.1 + '@floating-ui/core': 1.7.4 + '@floating-ui/utils': 0.2.10 - '@floating-ui/utils@0.2.1': {} + '@floating-ui/utils@0.2.10': {} '@formatjs/ecma402-abstract@1.18.2': dependencies: @@ -9795,7 +12816,7 @@ snapshots: intl-messageformat: 10.5.11 tslib: 2.6.2 - '@fortawesome/ember-fontawesome@2.0.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0)': + '@fortawesome/ember-fontawesome@2.0.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(rollup@2.79.1)(webpack@5.89.0)': dependencies: '@fortawesome/fontawesome-svg-core': 6.4.0 '@rollup/plugin-node-resolve': 15.2.3(rollup@2.79.1) @@ -9810,11 +12831,12 @@ snapshots: ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 - ember-get-config: 2.1.1 + ember-get-config: 2.1.1(@babel/core@7.23.2) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) find-yarn-workspace-root: 2.0.0 glob: 10.3.10 transitivePeerDependencies: + - '@babel/core' - '@glint/template' - rollup - supports-color @@ -9834,17 +12856,17 @@ snapshots: dependencies: '@fortawesome/fontawesome-common-types': 6.4.0 - '@fullcalendar/core@6.1.10': + '@fullcalendar/core@6.1.20': dependencies: preact: 10.12.1 - '@fullcalendar/daygrid@6.1.10(@fullcalendar/core@6.1.10)': + '@fullcalendar/daygrid@6.1.20(@fullcalendar/core@6.1.20)': dependencies: - '@fullcalendar/core': 6.1.10 + '@fullcalendar/core': 6.1.20 - '@fullcalendar/interaction@6.1.10(@fullcalendar/core@6.1.10)': + '@fullcalendar/interaction@6.1.20(@fullcalendar/core@6.1.20)': dependencies: - '@fullcalendar/core': 6.1.10 + '@fullcalendar/core': 6.1.20 '@glimmer/compiler@0.84.3': dependencies: @@ -9899,6 +12921,11 @@ snapshots: dependencies: '@simple-dom/interface': 1.4.0 + '@glimmer/interfaces@0.94.6': + dependencies: + '@simple-dom/interface': 1.4.0 + type-fest: 4.41.0 + '@glimmer/low-level@0.78.2': {} '@glimmer/manager@0.84.3': @@ -9973,6 +13000,14 @@ snapshots: '@handlebars/parser': 2.0.0 simple-html-tokenizer: 0.5.11 + '@glimmer/syntax@0.95.0': + dependencies: + '@glimmer/interfaces': 0.94.6 + '@glimmer/util': 0.94.8 + '@glimmer/wire-format': 0.94.8 + '@handlebars/parser': 2.2.2 + simple-html-tokenizer: 0.5.11 + '@glimmer/tracking@1.1.2': dependencies: '@glimmer/env': 0.1.7 @@ -9986,6 +13021,10 @@ snapshots: '@glimmer/interfaces': 0.84.3 '@simple-dom/interface': 1.4.0 + '@glimmer/util@0.94.8': + dependencies: + '@glimmer/interfaces': 0.94.6 + '@glimmer/validator@0.44.0': {} '@glimmer/validator@0.84.3': @@ -10009,8 +13048,14 @@ snapshots: '@glimmer/interfaces': 0.84.3 '@glimmer/util': 0.84.3 + '@glimmer/wire-format@0.94.8': + dependencies: + '@glimmer/interfaces': 0.94.6 + '@handlebars/parser@2.0.0': {} + '@handlebars/parser@2.2.2': {} + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 @@ -10032,12 +13077,22 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping@0.3.3': dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.1.2': {} @@ -10049,12 +13104,19 @@ snapshots: '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.22': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@kurkle/color@0.3.2': {} + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@kurkle/color@0.3.4': {} '@lint-todo/utils@13.1.1': dependencies: @@ -10157,205 +13219,200 @@ snapshots: dependencies: defer-to-connect: 1.1.3 - '@tailwindcss/forms@0.5.7(tailwindcss@3.4.1)': + '@tailwindcss/forms@0.5.11(tailwindcss@3.4.19)': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.4.1 + tailwindcss: 3.4.19 - '@tiptap/core@2.8.0(@tiptap/pm@2.8.0)': + '@tiptap/core@2.27.2(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/pm': 2.8.0 + '@tiptap/pm': 2.27.2 - '@tiptap/extension-blockquote@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-blockquote@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-bold@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-bold@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-bullet-list@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + '@tiptap/extension-bullet-list@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/extension-list-item': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-code-block@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + '@tiptap/extension-code-block@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/pm': 2.8.0 + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': 2.27.2 - '@tiptap/extension-code@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-code@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-color@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + '@tiptap/extension-color@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-text-style@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/extension-text-style': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) - '@tiptap/extension-document@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-document@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-dropcursor@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + '@tiptap/extension-dropcursor@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/pm': 2.8.0 + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': 2.27.2 - '@tiptap/extension-font-family@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + '@tiptap/extension-font-family@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-text-style@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/extension-text-style': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) - '@tiptap/extension-gapcursor@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + '@tiptap/extension-gapcursor@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/pm': 2.8.0 + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': 2.27.2 - '@tiptap/extension-hard-break@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-hard-break@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-heading@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-heading@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-highlight@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-highlight@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-history@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + '@tiptap/extension-history@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/pm': 2.8.0 + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': 2.27.2 - '@tiptap/extension-horizontal-rule@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + '@tiptap/extension-horizontal-rule@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/pm': 2.8.0 + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': 2.27.2 - '@tiptap/extension-image@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-image@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-italic@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-italic@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-list-item@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-ordered-list@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': + '@tiptap/extension-ordered-list@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/extension-list-item': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-text-style': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-paragraph@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-paragraph@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-placeholder@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + '@tiptap/extension-placeholder@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/pm': 2.8.0 + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': 2.27.2 - '@tiptap/extension-strike@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-strike@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-subscript@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-subscript@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-superscript@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-superscript@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-table-cell@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-table-cell@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-table-header@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-table-header@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-table-row@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-table-row@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-table@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0)': + '@tiptap/extension-table@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/pm': 2.8.0 + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': 2.27.2 - '@tiptap/extension-text-align@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-text-align@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-text-style@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-text@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-text@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-underline@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-underline@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/extension-youtube@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))': + '@tiptap/extension-youtube@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))': dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) - '@tiptap/pm@2.8.0': + '@tiptap/pm@2.27.2': dependencies: - prosemirror-changeset: 2.2.1 + prosemirror-changeset: 2.4.0 prosemirror-collab: 1.3.1 - prosemirror-commands: 1.6.0 - prosemirror-dropcursor: 1.8.1 - prosemirror-gapcursor: 1.3.2 - prosemirror-history: 1.4.1 - prosemirror-inputrules: 1.4.0 - prosemirror-keymap: 1.2.2 - prosemirror-markdown: 1.13.1 - prosemirror-menu: 1.2.4 - prosemirror-model: 1.22.3 - prosemirror-schema-basic: 1.2.3 - prosemirror-schema-list: 1.4.1 - prosemirror-state: 1.4.3 - prosemirror-tables: 1.5.0 - prosemirror-trailing-node: 3.0.0(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.34.3) - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 - - '@tiptap/starter-kit@2.8.0(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))': - dependencies: - '@tiptap/core': 2.8.0(@tiptap/pm@2.8.0) - '@tiptap/extension-blockquote': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-bold': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-bullet-list': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) - '@tiptap/extension-code': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-code-block': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) - '@tiptap/extension-document': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-dropcursor': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) - '@tiptap/extension-gapcursor': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) - '@tiptap/extension-hard-break': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-heading': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-history': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) - '@tiptap/extension-horizontal-rule': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/pm@2.8.0) - '@tiptap/extension-italic': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-list-item': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-ordered-list': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))(@tiptap/extension-list-item@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)))(@tiptap/extension-text-style@2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0))) - '@tiptap/extension-paragraph': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-strike': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/extension-text': 2.8.0(@tiptap/core@2.8.0(@tiptap/pm@2.8.0)) - '@tiptap/pm': 2.8.0 - transitivePeerDependencies: - - '@tiptap/extension-text-style' + prosemirror-commands: 1.7.1 + prosemirror-dropcursor: 1.8.2 + prosemirror-gapcursor: 1.4.0 + prosemirror-history: 1.5.0 + prosemirror-inputrules: 1.5.1 + prosemirror-keymap: 1.2.3 + prosemirror-markdown: 1.13.4 + prosemirror-menu: 1.3.0 + prosemirror-model: 1.25.4 + prosemirror-schema-basic: 1.2.4 + prosemirror-schema-list: 1.5.1 + prosemirror-state: 1.4.4 + prosemirror-tables: 1.8.5 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6) + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + '@tiptap/starter-kit@2.27.2': + dependencies: + '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/extension-blockquote': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-bold': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-bullet-list': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-code': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-code-block': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) + '@tiptap/extension-document': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-dropcursor': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) + '@tiptap/extension-gapcursor': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) + '@tiptap/extension-hard-break': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-heading': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-history': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) + '@tiptap/extension-horizontal-rule': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) + '@tiptap/extension-italic': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-list-item': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-ordered-list': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-paragraph': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-strike': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-text': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/extension-text-style': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) + '@tiptap/pm': 2.27.2 '@types/body-parser@1.19.5': dependencies: @@ -10685,33 +13742,48 @@ snapshots: acorn@8.11.3: {} + acorn@8.16.0: {} + ag-channel@5.0.0: dependencies: consumable-stream: 2.0.0 - ag-request@1.0.1: + ag-request@1.1.0: dependencies: - sc-errors: 2.0.3 + sc-errors: 3.0.0 - air-datepicker@3.4.0: {} + air-datepicker@3.6.0: {} - ajv-errors@1.0.1(ajv@6.12.6): + ajv-errors@1.0.1(ajv@6.14.0): dependencies: - ajv: 6.12.6 + ajv: 6.14.0 ajv-formats@2.1.1(ajv@8.12.0): optionalDependencies: ajv: 8.12.0 + ajv-formats@2.1.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + ajv-keywords@3.5.2(ajv@6.12.6): dependencies: ajv: 6.12.6 + ajv-keywords@3.5.2(ajv@6.14.0): + dependencies: + ajv: 6.14.0 + ajv-keywords@5.1.0(ajv@8.12.0): dependencies: ajv: 8.12.0 fast-deep-equal: 3.1.3 + ajv-keywords@5.1.0(ajv@8.18.0): + dependencies: + ajv: 8.18.0 + fast-deep-equal: 3.1.3 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -10719,6 +13791,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ajv@8.12.0: dependencies: fast-deep-equal: 3.1.3 @@ -10726,6 +13805,13 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + amd-name-resolver@0.0.6: dependencies: ensure-posix-path: 1.1.1 @@ -10846,18 +13932,19 @@ snapshots: arrify@1.0.1: {} - asn1.js@5.4.1: + asn1.js@4.10.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 inherits: 2.0.4 minimalistic-assert: 1.0.1 - safer-buffer: 2.1.2 assert-never@1.2.1: {} + assert-never@1.4.0: {} + assert@1.5.1: dependencies: - object.assign: 4.1.5 + object.assign: 4.1.7 util: 0.10.4 assign-symbols@1.0.0: {} @@ -10914,20 +14001,23 @@ snapshots: atob@2.1.2: {} - autonumeric@4.10.5: {} + autonumeric@4.10.9: {} - autoprefixer@10.4.17(postcss@8.4.35): + autoprefixer@10.4.27(postcss@8.4.35): dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001588 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.0 + browserslist: 4.28.1 + caniuse-lite: 1.0.30001774 + fraction.js: 5.3.4 + picocolors: 1.1.1 postcss: 8.4.35 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.6: {} + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + babel-code-frame@6.26.0: dependencies: chalk: 1.1.3 @@ -10949,8 +14039,8 @@ snapshots: convert-source-map: 1.9.0 debug: 2.6.9 json5: 0.5.1 - lodash: 4.17.21 - minimatch: 3.1.2 + lodash: 4.17.23 + minimatch: 3.1.5 path-is-absolute: 1.0.1 private: 0.1.8 slash: 1.0.0 @@ -10965,7 +14055,7 @@ snapshots: babel-types: 6.26.0 detect-indent: 4.0.0 jsesc: 1.3.0 - lodash: 4.17.21 + lodash: 4.17.23 source-map: 0.5.7 trim-right: 1.0.1 @@ -10982,9 +14072,20 @@ snapshots: babel-import-util@2.0.1: {} - babel-import-util@3.0.0: {} + babel-import-util@2.1.1: {} + + babel-import-util@3.0.1: {} + + babel-loader@8.3.0(@babel/core@7.23.2)(webpack@5.89.0): + dependencies: + '@babel/core': 7.23.2 + find-cache-dir: 3.3.2 + loader-utils: 2.0.4 + make-dir: 3.1.0 + schema-utils: 2.7.1 + webpack: 5.89.0 - babel-loader@8.3.0(@babel/core@7.23.2)(webpack@4.47.0): + babel-loader@8.4.1(@babel/core@7.23.2)(webpack@4.47.0): dependencies: '@babel/core': 7.23.2 find-cache-dir: 3.3.2 @@ -10993,7 +14094,7 @@ snapshots: schema-utils: 2.7.1 webpack: 4.47.0 - babel-loader@8.3.0(@babel/core@7.23.2)(webpack@5.89.0): + babel-loader@8.4.1(@babel/core@7.23.2)(webpack@5.89.0): dependencies: '@babel/core': 7.23.2 find-cache-dir: 3.3.2 @@ -11018,6 +14119,11 @@ snapshots: '@babel/core': 7.23.2 semver: 5.7.2 + babel-plugin-debug-macros@0.3.4(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + semver: 5.7.2 + babel-plugin-ember-data-packages-polyfill@0.1.2: dependencies: '@ember-data/rfc395-data': 0.0.4 @@ -11031,6 +14137,11 @@ snapshots: '@glimmer/syntax': 0.84.3 babel-import-util: 2.0.1 + babel-plugin-ember-template-compilation@2.4.1: + dependencies: + '@glimmer/syntax': 0.95.0 + babel-import-util: 3.0.1 + babel-plugin-filter-imports@4.0.0: dependencies: '@babel/types': 7.23.9 @@ -11062,6 +14173,32 @@ snapshots: reselect: 4.1.8 resolve: 1.22.8 + babel-plugin-module-resolver@5.0.2: + dependencies: + find-babel-config: 2.1.2 + glob: 9.3.5 + pkg-up: 3.1.0 + reselect: 4.1.8 + resolve: 1.22.11 + + babel-plugin-polyfill-corejs2@0.4.15(@babel/core@7.23.2): + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.23.2 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.23.2) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs2@0.4.15(@babel/core@7.29.0): + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.23.2): dependencies: '@babel/compat-data': 7.23.5 @@ -11071,6 +14208,47 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.29.0): + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.23.2): + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.23.2) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.0(@babel/core@7.23.2): + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.23.2) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.23.2): dependencies: '@babel/core': 7.23.2 @@ -11079,6 +14257,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.29.0) + core-js-compat: 3.36.0 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.23.2): dependencies: '@babel/core': 7.23.2 @@ -11086,6 +14272,27 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.6(@babel/core@7.23.2): + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.6(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + babel-plugin-syntax-dynamic-import@6.18.0: {} babel-register@6.26.0: @@ -11094,7 +14301,7 @@ snapshots: babel-runtime: 6.26.0 core-js: 2.6.12 home-or-tmp: 2.0.0 - lodash: 4.17.21 + lodash: 4.17.23 mkdirp: 0.5.6 source-map-support: 0.4.18 transitivePeerDependencies: @@ -11111,7 +14318,7 @@ snapshots: babel-traverse: 6.26.0 babel-types: 6.26.0 babylon: 6.18.0 - lodash: 4.17.21 + lodash: 4.17.23 transitivePeerDependencies: - supports-color @@ -11125,7 +14332,7 @@ snapshots: debug: 2.6.9 globals: 9.18.0 invariant: 2.2.4 - lodash: 4.17.21 + lodash: 4.17.23 transitivePeerDependencies: - supports-color @@ -11133,7 +14340,7 @@ snapshots: dependencies: babel-runtime: 6.26.0 esutils: 2.0.3 - lodash: 4.17.21 + lodash: 4.17.23 to-fast-properties: 1.0.3 babel6-plugin-strip-class-callcheck@6.0.0: {} @@ -11164,6 +14371,8 @@ snapshots: mixin-deep: 1.3.2 pascalcase: 0.1.1 + baseline-browser-mapping@2.10.0: {} + basic-auth@2.0.1: dependencies: safe-buffer: 5.1.2 @@ -11177,7 +14386,7 @@ snapshots: binary-extensions@1.13.1: optional: true - binary-extensions@2.2.0: {} + binary-extensions@2.3.0: {} binaryextensions@2.3.0: {} @@ -11203,9 +14412,9 @@ snapshots: bluebird@3.7.2: {} - bn.js@4.12.0: {} + bn.js@4.12.3: {} - bn.js@5.2.1: {} + bn.js@5.2.3: {} body-parser@1.20.1: dependencies: @@ -11236,6 +14445,11 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 @@ -11259,6 +14473,10 @@ snapshots: dependencies: fill-range: 7.0.1 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + broccoli-asset-rev@3.0.0: dependencies: broccoli-asset-rewrite: 2.0.0 @@ -11307,6 +14525,48 @@ snapshots: transitivePeerDependencies: - supports-color + broccoli-babel-transpiler@8.0.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + broccoli-persistent-filter: 3.1.3 + clone: 2.1.2 + hash-for-dep: 1.5.1 + heimdalljs: 0.2.6 + heimdalljs-logger: 0.1.10 + json-stable-stringify: 1.1.1 + rsvp: 4.8.5 + workerpool: 6.5.1 + transitivePeerDependencies: + - supports-color + + broccoli-babel-transpiler@8.0.2(@babel/core@7.23.2): + dependencies: + '@babel/core': 7.23.2 + broccoli-persistent-filter: 3.1.3 + clone: 2.1.2 + hash-for-dep: 1.5.2 + heimdalljs: 0.2.6 + heimdalljs-logger: 0.1.10 + json-stable-stringify: 1.3.0 + rsvp: 4.8.5 + workerpool: 6.5.1 + transitivePeerDependencies: + - supports-color + + broccoli-babel-transpiler@8.0.2(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + broccoli-persistent-filter: 3.1.3 + clone: 2.1.2 + hash-for-dep: 1.5.2 + heimdalljs: 0.2.6 + heimdalljs-logger: 0.1.10 + json-stable-stringify: 1.3.0 + rsvp: 4.8.5 + workerpool: 6.5.1 + transitivePeerDependencies: + - supports-color + broccoli-builder@0.18.14: dependencies: broccoli-node-info: 1.1.0 @@ -11341,6 +14601,16 @@ snapshots: transitivePeerDependencies: - supports-color + broccoli-caching-writer@3.1.0: + dependencies: + broccoli-plugin: 1.3.1 + debug: 3.2.7 + rimraf: 2.7.1 + rsvp: 3.6.2 + walk-sync: 0.3.4 + transitivePeerDependencies: + - supports-color + broccoli-clean-css@1.1.0: dependencies: broccoli-persistent-filter: 1.4.6 @@ -11642,12 +14912,12 @@ snapshots: broccoli-postcss-single@5.0.2: dependencies: - broccoli-caching-writer: 3.0.3 + broccoli-caching-writer: 3.1.0 include-path-searcher: 0.1.0 minimist: 1.2.8 mkdirp: 1.0.4 object-assign: 4.1.1 - postcss: 8.4.35 + postcss: 8.5.6 transitivePeerDependencies: - supports-color @@ -11657,7 +14927,7 @@ snapshots: broccoli-persistent-filter: 3.1.3 minimist: 1.2.8 object-assign: 4.1.1 - postcss: 8.4.35 + postcss: 8.5.6 transitivePeerDependencies: - supports-color @@ -11736,7 +15006,7 @@ snapshots: broccoli-string-replace@0.1.2: dependencies: broccoli-persistent-filter: 1.4.6 - minimatch: 3.1.2 + minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -11789,7 +15059,7 @@ snapshots: browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 - cipher-base: 1.0.4 + cipher-base: 1.0.7 create-hash: 1.2.0 evp_bytestokey: 1.0.3 inherits: 2.0.4 @@ -11803,26 +15073,27 @@ snapshots: browserify-des@1.0.2: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.7 des.js: 1.1.0 inherits: 2.0.4 safe-buffer: 5.2.1 - browserify-rsa@4.1.0: + browserify-rsa@4.1.1: dependencies: - bn.js: 5.2.1 + bn.js: 5.2.3 randombytes: 2.1.0 + safe-buffer: 5.2.1 - browserify-sign@4.2.2: + browserify-sign@4.2.5: dependencies: - bn.js: 5.2.1 - browserify-rsa: 4.1.0 + bn.js: 5.2.3 + browserify-rsa: 4.1.1 create-hash: 1.2.0 create-hmac: 1.1.7 - elliptic: 6.5.4 + elliptic: 6.6.1 inherits: 2.0.4 - parse-asn1: 5.1.6 - readable-stream: 3.6.2 + parse-asn1: 5.1.9 + readable-stream: 2.3.8 safe-buffer: 5.2.1 browserify-zlib@0.2.0: @@ -11836,6 +15107,14 @@ snapshots: node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001774 + electron-to-chromium: 1.5.302 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + bser@2.1.1: dependencies: node-int64: 0.4.0 @@ -11913,6 +15192,11 @@ snapshots: dependencies: json-stable-stringify: 1.1.1 + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -11921,6 +15205,18 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.1 + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + call-me-maybe@1.0.2: {} callsites@3.1.0: {} @@ -11947,13 +15243,15 @@ snapshots: caniuse-api@3.0.0: dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001588 + browserslist: 4.28.1 + caniuse-lite: 1.0.30001774 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 caniuse-lite@1.0.30001588: {} + caniuse-lite@1.0.30001774: {} + capture-exit@2.0.0: dependencies: rsvp: 4.8.5 @@ -11990,13 +15288,13 @@ snapshots: dependencies: inherits: 2.0.4 - chart.js@4.4.1: + chart.js@4.5.1: dependencies: - '@kurkle/color': 0.3.2 + '@kurkle/color': 0.3.4 - chartjs-adapter-date-fns@3.0.0(chart.js@4.4.1)(date-fns@2.30.0): + chartjs-adapter-date-fns@3.0.0(chart.js@4.5.1)(date-fns@2.30.0): dependencies: - chart.js: 4.4.1 + chart.js: 4.5.1 date-fns: 2.30.0 chokidar@2.1.8: @@ -12021,7 +15319,7 @@ snapshots: chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -12034,12 +15332,15 @@ snapshots: chrome-trace-event@1.0.3: {} + chrome-trace-event@1.0.4: {} + ci-info@3.9.0: {} - cipher-base@1.0.4: + cipher-base@1.0.7: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 + to-buffer: 1.2.2 class-utils@0.3.6: dependencies: @@ -12164,7 +15465,7 @@ snapshots: component-emitter@1.3.1: {} - compress-json@3.1.0: {} + compress-json@3.4.0: {} compressible@2.0.18: dependencies: @@ -12233,13 +15534,13 @@ snapshots: ora: 3.4.0 through2: 3.0.2 - consolidate@0.16.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(mustache@4.2.0)(underscore@1.13.6): + consolidate@0.16.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(mustache@4.2.0)(underscore@1.13.6): dependencies: bluebird: 3.7.2 optionalDependencies: babel-core: 6.26.3 handlebars: 4.7.8 - lodash: 4.17.21 + lodash: 4.17.23 mustache: 4.2.0 underscore: 1.13.6 @@ -12251,6 +15552,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-tag@4.1.0: {} + content-type@1.0.5: {} continuable-cache@0.3.1: {} @@ -12282,6 +15585,10 @@ snapshots: dependencies: browserslist: 4.23.0 + core-js-compat@3.48.0: + dependencies: + browserslist: 4.28.1 + core-js@2.6.12: {} core-object@3.1.5: @@ -12304,25 +15611,25 @@ snapshots: create-ecdh@4.0.4: dependencies: - bn.js: 4.12.0 - elliptic: 6.5.4 + bn.js: 4.12.3 + elliptic: 6.6.1 create-hash@1.2.0: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.7 inherits: 2.0.4 md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 + ripemd160: 2.0.3 + sha.js: 2.4.12 create-hmac@1.1.7: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.7 create-hash: 1.2.0 inherits: 2.0.4 - ripemd160: 2.0.2 + ripemd160: 2.0.3 safe-buffer: 5.2.1 - sha.js: 2.4.11 + sha.js: 2.4.12 crelt@1.0.6: {} @@ -12340,26 +15647,27 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crypto-browserify@3.12.0: + crypto-browserify@3.12.1: dependencies: browserify-cipher: 1.0.1 - browserify-sign: 4.2.2 + browserify-sign: 4.2.5 create-ecdh: 4.0.4 create-hash: 1.2.0 create-hmac: 1.1.7 diffie-hellman: 5.0.3 + hash-base: 3.0.5 inherits: 2.0.4 - pbkdf2: 3.1.2 + pbkdf2: 3.1.5 public-encrypt: 4.0.3 randombytes: 2.1.0 randomfill: 1.0.4 crypto-random-string@2.0.0: {} - css-blank-pseudo@6.0.1(postcss@8.4.35): + css-blank-pseudo@6.0.2(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 css-color-converter@2.0.0: dependencies: @@ -12369,11 +15677,11 @@ snapshots: css-functions-list@3.2.1: {} - css-has-pseudo@6.0.1(postcss@8.4.35): + css-has-pseudo@6.0.5(postcss@8.4.35): dependencies: - '@csstools/selector-specificity': 3.0.1(postcss-selector-parser@6.0.15) + '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.2) postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 css-loader@5.2.7(webpack@5.89.0): @@ -12401,17 +15709,19 @@ snapshots: css-unit-converter@1.1.2: {} - cssdb@7.11.0: {} + cssdb@8.8.0: {} cssesc@3.0.0: {} + csstype@3.2.3: {} + cyclist@1.0.2: {} dag-map@2.0.2: {} date-fns@2.30.0: dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.28.6 debug@2.6.9: dependencies: @@ -12425,6 +15735,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.4.3: + dependencies: + ms: 2.1.3 + decamelize-keys@1.1.1: dependencies: decamelize: 1.2.0 @@ -12440,10 +15754,24 @@ snapshots: dependencies: mimic-response: 1.0.1 - decorator-transforms@2.2.2(@babel/core@7.23.2): + decorator-transforms@1.2.1(@babel/core@7.23.2): dependencies: - '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.23.2) - babel-import-util: 3.0.0 + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.23.2) + babel-import-util: 2.1.1 + transitivePeerDependencies: + - '@babel/core' + + decorator-transforms@2.3.1(@babel/core@7.23.2): + dependencies: + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.23.2) + babel-import-util: 3.0.1 + transitivePeerDependencies: + - '@babel/core' + + decorator-transforms@2.3.1(@babel/core@7.29.0): + dependencies: + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.0) + babel-import-util: 3.0.1 transitivePeerDependencies: - '@babel/core' @@ -12515,7 +15843,7 @@ snapshots: diffie-hellman@5.0.3: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 miller-rabin: 4.0.1 randombytes: 2.1.0 @@ -12540,11 +15868,17 @@ snapshots: dependencies: is-obj: 2.0.0 + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + duplexer3@0.1.5: {} duplexify@3.7.1: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 inherits: 2.0.4 readable-stream: 2.3.8 stream-shift: 1.0.3 @@ -12562,11 +15896,13 @@ snapshots: electron-to-chromium@1.4.673: {} + electron-to-chromium@1.5.302: {} + element-closest@3.0.2: {} - elliptic@6.5.4: + elliptic@6.6.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 brorand: 1.1.0 hash.js: 1.1.7 hmac-drbg: 1.0.1 @@ -12574,16 +15910,17 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - ember-animated@1.1.4(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + ember-animated@1.1.4(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: - '@embroider/addon-shim': 1.8.7 - '@embroider/macros': 1.13.5 - '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - assert-never: 1.2.1 - ember-element-helper: 0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + '@embroider/addon-shim': 1.10.2 + '@embroider/macros': 1.20.0(@babel/core@7.23.2) + '@embroider/util': 1.13.5(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + assert-never: 1.4.0 + ember-element-helper: 0.8.8 optionalDependencies: '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) transitivePeerDependencies: + - '@babel/core' - '@glint/environment-ember-loose' - '@glint/template' - ember-source @@ -12607,17 +15944,23 @@ snapshots: transitivePeerDependencies: - supports-color + ember-assign-helper@0.5.1: + dependencies: + '@embroider/addon-shim': 1.10.2 + transitivePeerDependencies: + - supports-color + ember-ast-helpers@0.4.0: {} ember-auto-import@1.12.2: dependencies: '@babel/core': 7.23.2 - '@babel/preset-env': 7.23.9(@babel/core@7.23.2) - '@babel/traverse': 7.23.9 - '@babel/types': 7.23.9 + '@babel/preset-env': 7.29.0(@babel/core@7.23.2) + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@embroider/shared-internals': 1.8.3 babel-core: 6.26.3 - babel-loader: 8.3.0(@babel/core@7.23.2)(webpack@4.47.0) + babel-loader: 8.4.1(@babel/core@7.23.2)(webpack@4.47.0) babel-plugin-syntax-dynamic-import: 6.18.0 babylon: 6.18.0 broccoli-debug: 0.6.5 @@ -12631,11 +15974,11 @@ snapshots: fs-tree-diff: 2.0.1 handlebars: 4.7.8 js-string-escape: 1.0.1 - lodash: 4.17.21 + lodash: 4.17.23 mkdirp: 0.5.6 resolve-package-path: 3.1.0 rimraf: 2.7.1 - semver: 7.6.0 + semver: 7.7.4 symlink-or-copy: 1.3.1 typescript-memoize: 1.1.1 walk-sync: 0.3.4 @@ -12645,6 +15988,50 @@ snapshots: - webpack-cli - webpack-command + ember-auto-import@2.12.1(webpack@5.89.0): + dependencies: + '@babel/core': 7.23.2 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.2) + '@babel/plugin-proposal-decorators': 7.23.2(@babel/core@7.23.2) + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.23.2) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.23.2) + '@babel/preset-env': 7.29.0(@babel/core@7.23.2) + '@embroider/macros': 1.20.0(@babel/core@7.23.2) + '@embroider/reverse-exports': 0.2.0 + '@embroider/shared-internals': 2.9.2 + babel-loader: 8.4.1(@babel/core@7.23.2)(webpack@5.89.0) + babel-plugin-ember-modules-api-polyfill: 3.5.0 + babel-plugin-ember-template-compilation: 2.4.1 + babel-plugin-htmlbars-inline-precompile: 5.3.1 + babel-plugin-syntax-dynamic-import: 6.18.0 + broccoli-debug: 0.6.5 + broccoli-funnel: 3.0.8 + broccoli-merge-trees: 4.2.0 + broccoli-plugin: 4.0.7 + broccoli-source: 3.0.1 + css-loader: 5.2.7(webpack@5.89.0) + debug: 4.4.3 + fs-extra: 10.1.0 + fs-tree-diff: 2.0.1 + handlebars: 4.7.8 + is-subdir: 1.2.0 + js-string-escape: 1.0.1 + lodash: 4.17.23 + mini-css-extract-plugin: 2.10.0(webpack@5.89.0) + minimatch: 3.1.5 + parse5: 6.0.1 + pkg-entry-points: 1.1.1 + resolve: 1.22.11 + resolve-package-path: 4.0.3 + semver: 7.7.4 + style-loader: 2.0.0(webpack@5.89.0) + typescript-memoize: 1.1.1 + walk-sync: 3.0.0 + transitivePeerDependencies: + - '@glint/template' + - supports-color + - webpack + ember-auto-import@2.8.1(webpack@5.89.0): dependencies: '@babel/core': 7.23.2 @@ -12688,30 +16075,27 @@ snapshots: - supports-color - webpack - ember-basic-dropdown@7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): + ember-basic-dropdown@8.4.0(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: - '@embroider/macros': 1.13.5 - '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + '@babel/core': 7.29.0 + '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + '@embroider/addon-shim': 1.10.2 + '@embroider/macros': 1.20.0(@babel/core@7.29.0) + '@embroider/util': 1.13.5(@babel/core@7.29.0)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) '@glimmer/component': 1.1.2(@babel/core@7.23.2) '@glimmer/tracking': 1.1.2 - ember-auto-import: 2.8.1(webpack@5.89.0) - ember-cli-babel: 7.26.11 - ember-cli-htmlbars: 6.3.0 - ember-cli-typescript: 5.2.1 - ember-element-helper: 0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - ember-get-config: 2.1.1 - ember-maybe-in-element: 2.1.0 - ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + decorator-transforms: 2.3.1(@babel/core@7.29.0) + ember-element-helper: 0.8.8 + ember-lifeline: 7.0.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)) + ember-modifier: 4.3.0(@babel/core@7.29.0) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) - ember-style-modifier: 3.1.1(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-style-modifier: 4.5.1(@babel/core@7.29.0)(@ember/string@3.1.1) ember-truth-helpers: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) transitivePeerDependencies: - - '@babel/core' - '@ember/string' - '@glint/environment-ember-loose' - '@glint/template' - supports-color - - webpack ember-cache-primitive-polyfill@1.0.1(@babel/core@7.23.2): dependencies: @@ -12737,12 +16121,12 @@ snapshots: - '@glint/template' - supports-color - ember-can@6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.2)(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + ember-can@6.0.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-inflector@4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@ember/string': 3.1.1 - '@embroider/addon-shim': 1.8.9 - decorator-transforms: 2.2.2(@babel/core@7.23.2) - ember-inflector: 4.0.2 + '@embroider/addon-shim': 1.10.2 + decorator-transforms: 2.3.1(@babel/core@7.23.2) + ember-inflector: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-resolver: 11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: @@ -12819,6 +16203,105 @@ snapshots: transitivePeerDependencies: - supports-color + ember-cli-babel@8.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-proposal-decorators': 7.23.2(@babel/core@7.29.0) + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.11(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.23.9(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.29.0) + '@babel/preset-env': 7.23.9(@babel/core@7.29.0) + '@babel/runtime': 7.12.18 + amd-name-resolver: 1.3.1 + babel-plugin-debug-macros: 0.3.4(@babel/core@7.29.0) + babel-plugin-ember-data-packages-polyfill: 0.1.2 + babel-plugin-ember-modules-api-polyfill: 3.5.0 + babel-plugin-module-resolver: 5.0.0 + broccoli-babel-transpiler: 8.0.0(@babel/core@7.29.0) + broccoli-debug: 0.6.5 + broccoli-funnel: 3.0.8 + broccoli-source: 3.0.1 + calculate-cache-key-for-tree: 2.0.0 + clone: 2.1.2 + ember-cli-babel-plugin-helpers: 1.1.1 + ember-cli-version-checker: 5.1.2 + ensure-posix-path: 1.1.1 + resolve-package-path: 4.0.3 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + + ember-cli-babel@8.3.1(@babel/core@7.23.2): + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/plugin-proposal-decorators': 7.23.2(@babel/core@7.23.2) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.23.2) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.23.2) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.23.2) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.23.2) + '@babel/preset-env': 7.29.0(@babel/core@7.23.2) + '@babel/runtime': 7.12.18 + amd-name-resolver: 1.3.1 + babel-plugin-debug-macros: 0.3.4(@babel/core@7.23.2) + babel-plugin-ember-data-packages-polyfill: 0.1.2 + babel-plugin-ember-modules-api-polyfill: 3.5.0 + babel-plugin-module-resolver: 5.0.2 + broccoli-babel-transpiler: 8.0.2(@babel/core@7.23.2) + broccoli-debug: 0.6.5 + broccoli-funnel: 3.0.8 + broccoli-source: 3.0.1 + calculate-cache-key-for-tree: 2.0.0 + clone: 2.1.2 + ember-cli-babel-plugin-helpers: 1.1.1 + ember-cli-version-checker: 5.1.2 + ensure-posix-path: 1.1.1 + resolve-package-path: 4.0.3 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + + ember-cli-babel@8.3.1(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/plugin-proposal-decorators': 7.23.2(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/runtime': 7.12.18 + amd-name-resolver: 1.3.1 + babel-plugin-debug-macros: 0.3.4(@babel/core@7.29.0) + babel-plugin-ember-data-packages-polyfill: 0.1.2 + babel-plugin-ember-modules-api-polyfill: 3.5.0 + babel-plugin-module-resolver: 5.0.2 + broccoli-babel-transpiler: 8.0.2(@babel/core@7.29.0) + broccoli-debug: 0.6.5 + broccoli-funnel: 3.0.8 + broccoli-source: 3.0.1 + calculate-cache-key-for-tree: 2.0.0 + clone: 2.1.2 + ember-cli-babel-plugin-helpers: 1.1.1 + ember-cli-version-checker: 5.1.2 + ensure-posix-path: 1.1.1 + resolve-package-path: 4.0.3 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + ember-cli-clean-css@3.0.0: dependencies: broccoli-persistent-filter: 3.1.3 @@ -12827,10 +16310,10 @@ snapshots: transitivePeerDependencies: - supports-color - ember-cli-dependency-checker@3.3.2(ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6)): + ember-cli-dependency-checker@3.3.2(ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(underscore@1.13.6)): dependencies: chalk: 2.4.2 - ember-cli: 5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6) + ember-cli: 5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(underscore@1.13.6) find-yarn-workspace-root: 1.2.1 is-git-url: 1.0.0 resolve: 1.22.8 @@ -12924,10 +16407,13 @@ snapshots: transitivePeerDependencies: - supports-color - ember-cli-notifications@9.0.0: + ember-cli-notifications@9.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: - '@embroider/addon-shim': 1.8.7 + '@embroider/addon-shim': 1.10.2 + decorator-transforms: 2.3.1(@babel/core@7.23.2) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: + - '@babel/core' - supports-color ember-cli-path-utils@1.0.0: {} @@ -12969,7 +16455,7 @@ snapshots: '@babel/core': 7.23.2 broccoli-funnel: 3.0.8 ember-cli-babel: 7.26.11 - resolve: 1.22.8 + resolve: 1.22.11 transitivePeerDependencies: - supports-color @@ -13083,9 +16569,24 @@ snapshots: transitivePeerDependencies: - supports-color + ember-cli-typescript@5.3.0: + dependencies: + ansi-to-html: 0.6.15 + broccoli-stew: 3.0.0 + debug: 4.4.3 + execa: 4.1.0 + fs-extra: 9.1.0 + resolve: 1.22.11 + rsvp: 4.8.5 + semver: 7.7.4 + stagehand: 1.0.1 + walk-sync: 2.2.0 + transitivePeerDependencies: + - supports-color + ember-cli-version-checker@2.2.0: dependencies: - resolve: 1.22.8 + resolve: 1.22.11 semver: 5.7.2 ember-cli-version-checker@3.1.3: @@ -13109,7 +16610,7 @@ snapshots: transitivePeerDependencies: - supports-color - ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6): + ember-cli@5.4.1(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(underscore@1.13.6): dependencies: '@pnpm/find-workspace-dir': 6.0.2 broccoli: 3.5.2 @@ -13187,7 +16688,7 @@ snapshots: sort-package-json: 1.57.0 symlink-or-copy: 1.3.1 temp: 0.9.4 - testem: 3.11.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6) + testem: 3.11.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(underscore@1.13.6) tiny-lr: 2.0.0 tree-sync: 2.1.0 walk-sync: 3.0.0 @@ -13271,7 +16772,7 @@ snapshots: ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 8.2.0(@babel/core@7.23.2) ember-cli-htmlbars: 6.3.0 - ember-element-helper: 0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-element-helper: 0.8.5(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - '@glint/environment-ember-loose' @@ -13279,6 +16780,22 @@ snapshots: - supports-color - webpack + ember-composability-tools@1.3.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): + dependencies: + '@babel/core': 7.23.2 + '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + '@glimmer/component': 1.1.2(@babel/core@7.23.2) + ember-auto-import: 2.8.1(webpack@5.89.0) + ember-cli-babel: 8.2.0(@babel/core@7.23.2) + ember-cli-htmlbars: 6.3.0 + ember-element-helper: 0.8.8 + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + remote-promises: 1.0.0 + transitivePeerDependencies: + - '@glint/template' + - supports-color + - webpack + ember-composable-helpers@5.0.0: dependencies: '@babel/core': 7.23.2 @@ -13290,8 +16807,8 @@ snapshots: ember-concurrency-async@1.0.0(ember-concurrency@2.3.7(@babel/core@7.23.2)): dependencies: - '@babel/helper-plugin-utils': 7.22.5 - '@babel/types': 7.23.9 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 ember-cli-babel: 7.26.11 ember-cli-babel-plugin-helpers: 1.1.1 ember-cli-htmlbars: 4.5.0 @@ -13309,13 +16826,6 @@ snapshots: - '@babel/core' - supports-color - ember-concurrency-test-waiter@0.4.0(ember-concurrency@3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))): - dependencies: - ember-cli-babel: 7.26.11 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - transitivePeerDependencies: - - supports-color - ember-concurrency-ts@0.3.1(ember-concurrency@2.3.7(@babel/core@7.23.2)): dependencies: ember-cli-babel: 7.26.11 @@ -13326,8 +16836,8 @@ snapshots: ember-concurrency@2.3.7(@babel/core@7.23.2): dependencies: - '@babel/helper-plugin-utils': 7.22.5 - '@babel/types': 7.23.9 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 '@glimmer/tracking': 1.1.2 ember-cli-babel: 7.26.11 ember-cli-babel-plugin-helpers: 1.1.1 @@ -13352,9 +16862,21 @@ snapshots: - '@babel/core' - supports-color - ember-cookies@1.1.2: + ember-concurrency@4.0.6(@babel/core@7.23.2): dependencies: - '@embroider/addon-shim': 1.8.7 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 + '@embroider/addon-shim': 1.10.2 + decorator-transforms: 1.2.1(@babel/core@7.23.2) + transitivePeerDependencies: + - '@babel/core' + - supports-color + + ember-cookies@1.3.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + dependencies: + '@embroider/addon-shim': 1.10.2 + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -13410,27 +16932,49 @@ snapshots: - '@babel/core' - supports-color - ember-element-helper@0.6.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + ember-drag-sort@4.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): + dependencies: + '@babel/core': 7.29.0 + ember-auto-import: 2.12.1(webpack@5.89.0) + ember-cli-babel: 8.2.0(@babel/core@7.29.0) + ember-cli-htmlbars: 6.3.0 + ember-element-helper: 0.8.8 + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + ember-template-imports: 4.4.0 + transitivePeerDependencies: + - '@glint/template' + - supports-color + - webpack + + ember-element-helper@0.6.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: - '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + '@embroider/util': 1.13.5(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: + - '@babel/core' - '@glint/environment-ember-loose' - '@glint/template' - supports-color - ember-element-helper@0.8.5(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + ember-element-helper@0.8.5(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/addon-shim': 1.8.3 - '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + '@embroider/util': 1.12.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: + - '@babel/core' - '@glint/environment-ember-loose' - '@glint/template' - supports-color + ember-element-helper@0.8.8: + dependencies: + '@embroider/addon-shim': 1.10.2 + transitivePeerDependencies: + - supports-color + ember-engines@0.9.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: '@embroider/macros': 1.13.5 @@ -13455,44 +16999,47 @@ snapshots: - '@glint/template' - supports-color - ember-file-upload@8.4.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-modifier@4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(tracked-built-ins@3.3.0)(webpack@5.89.0): + ember-file-upload@8.4.0(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-modifier@4.3.0(@babel/core@7.23.2))(tracked-built-ins@3.3.0)(webpack@5.89.0): dependencies: '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) '@ember/test-waiters': 3.1.0 - '@embroider/addon-shim': 1.8.7 - '@embroider/macros': 1.13.5 + '@embroider/addon-shim': 1.10.2 + '@embroider/macros': 1.20.0(@babel/core@7.23.2) '@glimmer/component': 1.1.2(@babel/core@7.23.2) '@glimmer/tracking': 1.1.2 ember-auto-import: 2.8.1(webpack@5.89.0) - ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-modifier: 4.3.0(@babel/core@7.23.2) tracked-built-ins: 3.3.0 transitivePeerDependencies: + - '@babel/core' - '@glint/template' - supports-color - webpack - ember-focus-trap@1.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + ember-focus-trap@1.2.0(@babel/core@7.23.2): dependencies: - '@embroider/addon-shim': 1.8.7 - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) - focus-trap: 6.9.4 + '@embroider/addon-shim': 1.10.2 + decorator-transforms: 2.3.1(@babel/core@7.23.2) + focus-trap: 7.8.0 transitivePeerDependencies: + - '@babel/core' - supports-color - ember-functions-as-helper-polyfill@2.1.2(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + ember-functions-as-helper-polyfill@2.1.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: ember-cli-babel: 7.26.11 - ember-cli-typescript: 5.2.1 + ember-cli-typescript: 5.3.0 ember-cli-version-checker: 5.1.2 ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color - ember-get-config@2.1.1: + ember-get-config@2.1.1(@babel/core@7.23.2): dependencies: - '@embroider/macros': 1.13.5 + '@embroider/macros': 1.20.0(@babel/core@7.23.2) ember-cli-babel: 7.26.11 transitivePeerDependencies: + - '@babel/core' - '@glint/template' - supports-color @@ -13502,7 +17049,7 @@ snapshots: ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 - ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-modifier: 4.3.0(@babel/core@7.23.2) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) gridstack: 7.3.0 transitivePeerDependencies: @@ -13526,6 +17073,13 @@ snapshots: transitivePeerDependencies: - supports-color + ember-inflector@4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + dependencies: + ember-cli-babel: 7.26.11 + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + transitivePeerDependencies: + - supports-color + ember-intl@6.3.2(@babel/core@7.23.2)(webpack@5.89.0): dependencies: '@formatjs/icu-messageformat-parser': 2.7.6 @@ -13584,20 +17138,27 @@ snapshots: broccoli-merge-trees: 4.2.0 ember-cli-babel: 7.26.11 ember-cli-htmlbars: 6.3.0 - ember-composability-tools: 1.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + ember-composability-tools: 1.3.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) ember-in-element-polyfill: 1.0.1 - ember-render-helpers: 0.2.0 + ember-render-helpers: 0.2.1 ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) fastboot-transform: 0.1.3 leaflet: 1.9.4 - resolve: 1.22.8 + resolve: 1.22.11 transitivePeerDependencies: - '@babel/core' - - '@glint/environment-ember-loose' - '@glint/template' - supports-color - webpack + ember-lifeline@7.0.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)): + dependencies: + '@embroider/addon-shim': 1.10.2 + optionalDependencies: + '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + transitivePeerDependencies: + - supports-color + ember-load-initializers@2.1.2(@babel/core@7.23.2): dependencies: ember-cli-babel: 7.26.11 @@ -13640,14 +17201,6 @@ snapshots: transitivePeerDependencies: - supports-color - ember-maybe-in-element@2.1.0: - dependencies: - ember-cli-babel: 7.26.11 - ember-cli-htmlbars: 6.3.0 - ember-cli-version-checker: 5.1.2 - transitivePeerDependencies: - - supports-color - ember-modifier-manager-polyfill@1.2.0(@babel/core@7.23.2): dependencies: ember-cli-babel: 7.26.11 @@ -13662,20 +17215,26 @@ snapshots: ember-cli-babel: 7.26.11 ember-cli-normalize-entity-name: 1.0.0 ember-cli-string-utils: 1.1.0 - ember-cli-typescript: 5.2.1 + ember-cli-typescript: 5.3.0 ember-compatibility-helpers: 1.2.7(@babel/core@7.23.2) transitivePeerDependencies: - '@babel/core' - supports-color - ember-modifier@4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + ember-modifier@4.3.0(@babel/core@7.23.2): dependencies: - '@embroider/addon-shim': 1.8.7 - ember-cli-normalize-entity-name: 1.0.0 - ember-cli-string-utils: 1.1.0 - optionalDependencies: - ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) + '@embroider/addon-shim': 1.10.2 + decorator-transforms: 2.3.1(@babel/core@7.23.2) transitivePeerDependencies: + - '@babel/core' + - supports-color + + ember-modifier@4.3.0(@babel/core@7.29.0): + dependencies: + '@embroider/addon-shim': 1.10.2 + decorator-transforms: 2.3.1(@babel/core@7.29.0) + transitivePeerDependencies: + - '@babel/core' - supports-color ember-on-helper@0.1.0: @@ -13698,7 +17257,7 @@ snapshots: ember-cli-htmlbars: 6.3.0 ember-concurrency: 2.3.7(@babel/core@7.23.2) ember-decorators: 6.1.1 - ember-element-helper: 0.6.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-element-helper: 0.6.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-truth-helpers: 3.1.1 transitivePeerDependencies: - '@babel/core' @@ -13707,29 +17266,26 @@ snapshots: - ember-source - supports-color - ember-power-select@7.2.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): - dependencies: - '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - '@ember/string': 3.1.1 - '@embroider/util': 1.12.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - '@glimmer/component': 1.1.2(@babel/core@7.23.2) - '@glimmer/tracking': 1.1.2 - ember-assign-helper: 0.4.0 - ember-auto-import: 2.8.1(webpack@5.89.0) - ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) - ember-cli-babel: 7.26.11 - ember-cli-htmlbars: 6.3.0 - ember-cli-typescript: 5.2.1 - ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) - ember-text-measurer: 0.6.0 + ember-power-select@8.6.2(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-basic-dropdown@8.4.0(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)))(ember-concurrency@4.0.6(@babel/core@7.23.2))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): + dependencies: + '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) + '@embroider/addon-shim': 1.10.2 + '@embroider/util': 1.13.5(@babel/core@7.23.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + '@glimmer/component': 1.1.2(@babel/core@7.23.2) + '@glimmer/tracking': 1.1.2 + decorator-transforms: 2.3.1(@babel/core@7.23.2) + ember-assign-helper: 0.5.1 + ember-basic-dropdown: 8.4.0(@ember/string@3.1.1)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(@glimmer/component@1.1.2(@babel/core@7.23.2))(@glimmer/tracking@1.1.2)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-concurrency: 4.0.6(@babel/core@7.23.2) + ember-lifeline: 7.0.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)) + ember-modifier: 4.3.0(@babel/core@7.23.2) + ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) ember-truth-helpers: 4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) transitivePeerDependencies: - '@babel/core' - '@glint/environment-ember-loose' - '@glint/template' - - ember-source - supports-color - - webpack ember-qunit@8.0.1(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(qunit@2.20.0): dependencies: @@ -13771,6 +17327,13 @@ snapshots: transitivePeerDependencies: - supports-color + ember-render-helpers@0.2.1: + dependencies: + ember-cli-babel: 7.26.11 + ember-cli-typescript: 4.2.1 + transitivePeerDependencies: + - supports-color + ember-resolver@11.0.1(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: ember-cli-babel: 7.26.11 @@ -13795,18 +17358,22 @@ snapshots: transitivePeerDependencies: - supports-color - ember-simple-auth@6.0.0(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0)): + ember-simple-auth@6.1.0(@babel/core@7.23.2)(@ember/test-helpers@3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0))(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(eslint@8.52.0): dependencies: + '@babel/eslint-parser': 7.28.6(@babel/core@7.23.2)(eslint@8.52.0) '@ember/test-waiters': 3.1.0 - '@embroider/addon-shim': 1.8.7 - '@embroider/macros': 1.13.5 + '@embroider/addon-shim': 1.10.2 + '@embroider/macros': 1.20.0(@babel/core@7.23.2) ember-cli-is-package-missing: 1.0.0 - ember-cookies: 1.1.2 + ember-cookies: 1.3.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) silent-error: 1.1.1 optionalDependencies: '@ember/test-helpers': 3.2.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0) transitivePeerDependencies: + - '@babel/core' - '@glint/template' + - ember-source + - eslint - supports-color ember-source-channel-url@3.0.0: @@ -13870,18 +17437,36 @@ snapshots: - supports-color - webpack - ember-style-modifier@3.1.1(@ember/string@3.1.1)(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0))(webpack@5.89.0): + ember-style-modifier@3.1.1(@babel/core@7.23.2)(@ember/string@3.1.1)(webpack@5.89.0): dependencies: '@ember/string': 3.1.1 ember-auto-import: 2.8.1(webpack@5.89.0) ember-cli-babel: 7.26.11 - ember-modifier: 4.1.0(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + ember-modifier: 4.3.0(@babel/core@7.23.2) transitivePeerDependencies: + - '@babel/core' - '@glint/template' - - ember-source - supports-color - webpack + ember-style-modifier@4.5.1(@babel/core@7.29.0)(@ember/string@3.1.1): + dependencies: + '@ember/string': 3.1.1 + '@embroider/addon-shim': 1.10.2 + csstype: 3.2.3 + decorator-transforms: 2.3.1(@babel/core@7.29.0) + ember-modifier: 4.3.0(@babel/core@7.29.0) + transitivePeerDependencies: + - '@babel/core' + - supports-color + + ember-tag-input@3.1.0: + dependencies: + ember-cli-babel: 7.26.11 + ember-cli-htmlbars: 6.3.0 + transitivePeerDependencies: + - supports-color + ember-template-imports@3.4.2: dependencies: babel-import-util: 0.2.0 @@ -13896,6 +17481,14 @@ snapshots: transitivePeerDependencies: - supports-color + ember-template-imports@4.4.0: + dependencies: + broccoli-stew: 3.0.0 + content-tag: 4.1.0 + ember-cli-version-checker: 5.1.2 + transitivePeerDependencies: + - supports-color + ember-template-lint@5.11.2: dependencies: '@lint-todo/utils': 13.1.1 @@ -13935,13 +17528,6 @@ snapshots: transitivePeerDependencies: - supports-color - ember-text-measurer@0.6.0: - dependencies: - ember-cli-babel: 7.26.11 - ember-cli-htmlbars: 4.5.0 - transitivePeerDependencies: - - supports-color - ember-tracked-storage-polyfill@1.0.0: dependencies: ember-cli-babel: 7.26.11 @@ -13957,8 +17543,8 @@ snapshots: ember-truth-helpers@4.0.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)): dependencies: - '@embroider/addon-shim': 1.8.7 - ember-functions-as-helper-polyfill: 2.1.2(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) + '@embroider/addon-shim': 1.10.2 + ember-functions-as-helper-polyfill: 2.1.3(ember-source@5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0)) ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2(@babel/core@7.23.2))(rsvp@4.8.5)(webpack@5.89.0) transitivePeerDependencies: - supports-color @@ -14017,6 +17603,10 @@ snapshots: dependencies: once: 1.4.0 + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + engine.io-parser@5.2.2: {} engine.io@6.5.4: @@ -14117,10 +17707,16 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + es-define-property@1.0.1: {} + es-errors@1.3.0: {} es-module-lexer@1.4.1: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + es-set-tostringtag@2.0.2: dependencies: get-intrinsic: 1.2.4 @@ -14135,6 +17731,8 @@ snapshots: escalade@3.1.2: {} + escalade@3.2.0: {} + escape-html@1.0.3: {} escape-string-regexp@1.0.5: {} @@ -14489,6 +18087,14 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.5 + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -14511,6 +18117,8 @@ snapshots: transitivePeerDependencies: - supports-color + fast-uri@3.1.0: {} + fastboot-transform@0.1.3: dependencies: broccoli-stew: 1.6.0 @@ -14532,6 +18140,10 @@ snapshots: dependencies: bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + figgy-pudding@3.5.2: {} figures@2.0.0: @@ -14566,6 +18178,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + finalhandler@1.1.2: dependencies: debug: 2.6.9 @@ -14600,6 +18216,10 @@ snapshots: json5: 2.2.3 path-exists: 4.0.0 + find-babel-config@2.1.2: + dependencies: + json5: 2.2.3 + find-cache-dir@2.1.0: dependencies: commondir: 1.0.1 @@ -14704,9 +18324,9 @@ snapshots: inherits: 2.0.4 readable-stream: 2.3.8 - focus-trap@6.9.4: + focus-trap@7.8.0: dependencies: - tabbable: 5.3.3 + tabbable: 6.4.0 follow-redirects@1.15.5: {} @@ -14714,6 +18334,10 @@ snapshots: dependencies: is-callable: 1.2.7 + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + for-in@1.0.2: {} foreground-child@3.1.1: @@ -14723,7 +18347,7 @@ snapshots: forwarded@0.2.0: {} - fraction.js@4.3.7: {} + fraction.js@5.3.4: {} fragment-cache@0.2.1: dependencies: @@ -14849,7 +18473,7 @@ snapshots: fsevents@1.2.13: dependencies: bindings: 1.5.0 - nan: 2.18.0 + nan: 2.25.0 optional: true fsevents@2.3.3: @@ -14891,6 +18515,24 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.1 + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-stdin@4.0.1: {} get-stdin@9.0.0: {} @@ -15052,6 +18694,8 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + gopd@1.2.0: {} + got@9.6.0: dependencies: '@sindresorhus/is': 0.14.0 @@ -15111,6 +18755,8 @@ snapshots: has-symbols@1.0.3: {} + has-symbols@1.1.0: {} + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 @@ -15136,12 +18782,18 @@ snapshots: is-number: 3.0.0 kind-of: 4.0.0 - hash-base@3.1.0: + hash-base@3.0.5: dependencies: inherits: 2.0.4 - readable-stream: 3.6.2 safe-buffer: 5.2.1 + hash-base@3.1.2: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + hash-for-dep@1.5.1: dependencies: broccoli-kitchen-sink-helpers: 0.3.1 @@ -15153,6 +18805,15 @@ snapshots: transitivePeerDependencies: - supports-color + hash-for-dep@1.5.2: + dependencies: + heimdalljs: 0.2.6 + heimdalljs-logger: 0.1.10 + resolve: 1.22.11 + resolve-package-path: 1.2.7 + transitivePeerDependencies: + - supports-color + hash.js@1.1.7: dependencies: inherits: 2.0.4 @@ -15162,6 +18823,10 @@ snapshots: dependencies: function-bind: 1.1.2 + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + heimdalljs-fs-monitor@1.1.1: dependencies: callsites: 3.1.0 @@ -15392,7 +19057,7 @@ snapshots: is-binary-path@2.1.0: dependencies: - binary-extensions: 2.2.0 + binary-extensions: 2.3.0 is-boolean-object@1.1.2: dependencies: @@ -15411,6 +19076,10 @@ snapshots: dependencies: hasown: 2.0.1 + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-data-descriptor@1.0.1: dependencies: hasown: 2.0.1 @@ -15522,6 +19191,10 @@ snapshots: dependencies: which-typed-array: 1.1.14 + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + is-typedarray@1.0.0: {} is-unicode-supported@0.1.0: {} @@ -15578,7 +19251,7 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jiti@1.21.0: {} + jiti@1.21.7: {} js-string-escape@1.0.1: {} @@ -15601,6 +19274,8 @@ snapshots: jsesc@2.5.2: {} + jsesc@3.1.0: {} + json-buffer@3.0.0: {} json-buffer@3.0.1: {} @@ -15622,6 +19297,14 @@ snapshots: jsonify: 0.0.1 object-keys: 1.1.1 + json-stable-stringify@1.3.0: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + isarray: 2.0.5 + jsonify: 0.0.1 + object-keys: 1.1.1 + json5@0.5.1: {} json5@1.0.2: @@ -15687,9 +19370,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lilconfig@2.1.0: {} - - lilconfig@3.1.0: {} + lilconfig@3.1.3: {} line-column@1.0.2: dependencies: @@ -15815,6 +19496,8 @@ snapshots: lodash@4.17.21: {} + lodash@4.17.23: {} + log-symbols@2.2.0: dependencies: chalk: 2.4.2 @@ -15899,7 +19582,7 @@ snapshots: mdurl: 1.0.1 uc.micro: 1.0.6 - markdown-it@14.1.0: + markdown-it@14.1.1: dependencies: argparse: 2.0.1 entities: 4.5.0 @@ -15917,11 +19600,13 @@ snapshots: '@types/minimatch': 3.0.5 minimatch: 3.1.2 + math-intrinsics@1.1.0: {} + mathml-tag-names@2.1.3: {} md5.js@1.3.5: dependencies: - hash-base: 3.1.0 + hash-base: 3.0.5 inherits: 2.0.4 safe-buffer: 5.2.1 @@ -15939,6 +19624,11 @@ snapshots: mimic-fn: 2.1.0 p-is-promise: 2.1.0 + mem@8.1.1: + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 3.1.0 + memory-fs@0.4.1: dependencies: errno: 0.1.8 @@ -16019,9 +19709,14 @@ snapshots: braces: 3.0.2 picomatch: 2.3.1 + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + miller-rabin@4.0.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 brorand: 1.1.0 mime-db@1.52.0: {} @@ -16036,10 +19731,18 @@ snapshots: mimic-fn@2.1.0: {} + mimic-fn@3.1.0: {} + mimic-response@1.0.1: {} min-indent@1.0.1: {} + mini-css-extract-plugin@2.10.0(webpack@5.89.0): + dependencies: + schema-utils: 4.3.3 + tapable: 2.3.0 + webpack: 5.89.0 + mini-css-extract-plugin@2.8.0(webpack@5.89.0): dependencies: schema-utils: 4.2.0 @@ -16056,6 +19759,10 @@ snapshots: dependencies: brace-expansion: 1.1.11 + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + minimatch@5.1.6: dependencies: brace-expansion: 2.0.1 @@ -16093,11 +19800,11 @@ snapshots: dependencies: concat-stream: 1.6.2 duplexify: 3.7.1 - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 flush-write-stream: 1.1.1 from2: 2.3.0 parallel-transform: 1.2.0 - pump: 3.0.0 + pump: 3.0.3 pumpify: 1.5.1 stream-each: 1.2.3 through2: 2.0.5 @@ -16162,9 +19869,11 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nan@2.18.0: + nan@2.25.0: optional: true + nanoid@3.3.11: {} + nanoid@3.3.7: {} nanomatch@1.2.13: @@ -16209,7 +19918,7 @@ snapshots: buffer: 4.9.2 console-browserify: 1.2.0 constants-browserify: 1.0.0 - crypto-browserify: 3.12.0 + crypto-browserify: 3.12.1 domain-browser: 1.2.0 events: 3.3.0 https-browserify: 1.0.0 @@ -16224,7 +19933,7 @@ snapshots: string_decoder: 1.3.0 timers-browserify: 2.0.12 tty-browserify: 0.0.0 - url: 0.11.3 + url: 0.11.4 util: 0.11.1 vm-browserify: 1.1.2 @@ -16241,6 +19950,8 @@ snapshots: node-releases@2.0.14: {} + node-releases@2.0.27: {} + node-watch@0.7.3: {} nopt@3.0.6: @@ -16260,8 +19971,6 @@ snapshots: normalize-path@3.0.0: {} - normalize-range@0.1.2: {} - normalize-url@4.5.1: {} npm-git-info@1.0.3: {} @@ -16306,6 +20015,8 @@ snapshots: object-inspect@1.13.1: {} + object-inspect@1.13.4: {} + object-keys@1.1.1: {} object-visit@1.0.1: @@ -16319,6 +20030,15 @@ snapshots: has-symbols: 1.0.3 object-keys: 1.1.1 + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + object.pick@1.3.0: dependencies: isobject: 3.0.1 @@ -16468,12 +20188,12 @@ snapshots: dependencies: callsites: 3.1.0 - parse-asn1@5.1.6: + parse-asn1@5.1.9: dependencies: - asn1.js: 5.4.1 + asn1.js: 4.10.1 browserify-aes: 1.2.0 evp_bytestokey: 1.0.3 - pbkdf2: 3.1.2 + pbkdf2: 3.1.5 safe-buffer: 5.2.1 parse-json@5.2.0: @@ -16533,18 +20253,23 @@ snapshots: path-type@4.0.0: {} - pbkdf2@3.1.2: + pbkdf2@3.1.5: dependencies: create-hash: 1.2.0 create-hmac: 1.1.7 - ripemd160: 2.0.2 + ripemd160: 2.0.3 safe-buffer: 5.2.1 - sha.js: 2.4.11 + sha.js: 2.4.12 + to-buffer: 1.2.2 picocolors@1.0.0: {} + picocolors@1.1.1: {} + picomatch@2.3.1: {} + picomatch@4.0.3: {} + pify@2.3.0: {} pify@4.0.1: {} @@ -16555,7 +20280,7 @@ snapshots: pinkie@2.0.4: {} - pirates@4.0.6: {} + pirates@4.0.7: {} pkg-dir@3.0.0: dependencies: @@ -16567,6 +20292,8 @@ snapshots: pkg-entry-points@1.1.0: {} + pkg-entry-points@1.1.1: {} + pkg-up@2.0.0: dependencies: find-up: 2.1.0 @@ -16585,35 +20312,40 @@ snapshots: posix-character-classes@0.1.1: {} + possible-typed-array-names@1.1.0: {} + postcss-at-rules-variables@0.3.0(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-attribute-case-insensitive@6.0.2(postcss@8.4.35): + postcss-attribute-case-insensitive@6.0.3(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-clamp@4.1.0(postcss@8.4.35): dependencies: postcss: 8.4.35 postcss-value-parser: 4.2.0 - postcss-color-functional-notation@6.0.4(postcss@8.4.35): + postcss-color-functional-notation@6.0.14(postcss@8.4.35): dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - postcss-color-hex-alpha@9.0.3(postcss@8.4.35): + postcss-color-hex-alpha@9.0.4(postcss@8.4.35): dependencies: + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 - postcss-color-rebeccapurple@9.0.2(postcss@8.4.35): + postcss-color-rebeccapurple@9.0.3(postcss@8.4.35): dependencies: + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 @@ -16623,38 +20355,40 @@ snapshots: css-unit-converter: 1.1.2 postcss: 8.4.35 - postcss-custom-media@10.0.2(postcss@8.4.35): + postcss-custom-media@10.0.8(postcss@8.4.35): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/media-query-list-parser': 2.1.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) + '@csstools/cascade-layer-name-parser': 1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) postcss: 8.4.35 - postcss-custom-properties@13.3.4(postcss@8.4.35): + postcss-custom-properties@13.3.12(postcss@8.4.35): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/cascade-layer-name-parser': 1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 - postcss-custom-selectors@7.1.6(postcss@8.4.35): + postcss-custom-selectors@7.1.12(postcss@8.4.35): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.7(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 + '@csstools/cascade-layer-name-parser': 1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-dir-pseudo-class@8.0.1(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 - postcss-double-position-gradients@5.0.3(postcss@8.4.35): + postcss-double-position-gradients@5.0.7(postcss@8.4.35): dependencies: - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 @@ -16666,12 +20400,12 @@ snapshots: postcss-focus-visible@9.0.1(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-focus-within@8.0.1(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-font-variant@5.0.0(postcss@8.4.35): dependencies: @@ -16681,8 +20415,9 @@ snapshots: dependencies: postcss: 8.4.35 - postcss-image-set-function@6.0.2(postcss@8.4.35): + postcss-image-set-function@6.0.3(postcss@8.4.35): dependencies: + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 postcss-value-parser: 4.2.0 @@ -16691,27 +20426,40 @@ snapshots: postcss: 8.4.35 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.8 + resolve: 1.22.11 + + postcss-import@15.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 - postcss-js@4.0.1(postcss@8.4.35): + postcss-js@4.1.0(postcss@8.4.35): dependencies: camelcase-css: 2.0.1 postcss: 8.4.35 - postcss-lab-function@6.0.9(postcss@8.4.35): + postcss-js@4.1.0(postcss@8.5.6): dependencies: - '@csstools/css-color-parser': 1.5.1(@csstools/css-parser-algorithms@2.5.0(@csstools/css-tokenizer@2.2.3))(@csstools/css-tokenizer@2.2.3) - '@csstools/css-parser-algorithms': 2.5.0(@csstools/css-tokenizer@2.2.3) - '@csstools/css-tokenizer': 2.2.3 - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) + camelcase-css: 2.0.1 + postcss: 8.5.6 + + postcss-lab-function@6.0.19(postcss@8.4.35): + dependencies: + '@csstools/css-color-parser': 2.0.5(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/utilities': 1.0.0(postcss@8.4.35) postcss: 8.4.35 - postcss-load-config@4.0.2(postcss@8.4.35): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6): dependencies: - lilconfig: 3.1.0 - yaml: 2.3.4 + lilconfig: 3.1.3 optionalDependencies: - postcss: 8.4.35 + jiti: 1.21.7 + postcss: 8.5.6 postcss-logical@7.0.1(postcss@8.4.35): dependencies: @@ -16720,9 +20468,9 @@ snapshots: postcss-mixins@9.0.4(postcss@8.4.35): dependencies: - fast-glob: 3.3.2 + fast-glob: 3.3.3 postcss: 8.4.35 - postcss-js: 4.0.1(postcss@8.4.35) + postcss-js: 4.1.0(postcss@8.4.35) postcss-simple-vars: 7.0.1(postcss@8.4.35) sugarss: 4.0.1(postcss@8.4.35) @@ -16747,16 +20495,17 @@ snapshots: icss-utils: 5.1.0(postcss@8.4.35) postcss: 8.4.35 - postcss-nested@6.0.1(postcss@8.4.35): + postcss-nested@6.2.0(postcss@8.5.6): dependencies: - postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 - postcss-nesting@12.0.2(postcss@8.4.35): + postcss-nesting@12.1.5(postcss@8.4.35): dependencies: - '@csstools/selector-specificity': 3.0.1(postcss-selector-parser@6.0.15) + '@csstools/selector-resolve-nested': 1.1.0(postcss-selector-parser@6.1.2) + '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.2) postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-opacity-percentage@2.0.0(postcss@8.4.35): dependencies: @@ -16776,74 +20525,75 @@ snapshots: postcss: 8.4.35 postcss-value-parser: 4.2.0 - postcss-preset-env@9.3.0(postcss@8.4.35): - dependencies: - '@csstools/postcss-cascade-layers': 4.0.2(postcss@8.4.35) - '@csstools/postcss-color-function': 3.0.9(postcss@8.4.35) - '@csstools/postcss-color-mix-function': 2.0.9(postcss@8.4.35) - '@csstools/postcss-exponential-functions': 1.0.3(postcss@8.4.35) - '@csstools/postcss-font-format-keywords': 3.0.1(postcss@8.4.35) - '@csstools/postcss-gamut-mapping': 1.0.2(postcss@8.4.35) - '@csstools/postcss-gradients-interpolation-method': 4.0.9(postcss@8.4.35) - '@csstools/postcss-hwb-function': 3.0.8(postcss@8.4.35) - '@csstools/postcss-ic-unit': 3.0.3(postcss@8.4.35) + postcss-preset-env@9.6.0(postcss@8.4.35): + dependencies: + '@csstools/postcss-cascade-layers': 4.0.6(postcss@8.4.35) + '@csstools/postcss-color-function': 3.0.19(postcss@8.4.35) + '@csstools/postcss-color-mix-function': 2.0.19(postcss@8.4.35) + '@csstools/postcss-content-alt-text': 1.0.0(postcss@8.4.35) + '@csstools/postcss-exponential-functions': 1.0.9(postcss@8.4.35) + '@csstools/postcss-font-format-keywords': 3.0.2(postcss@8.4.35) + '@csstools/postcss-gamut-mapping': 1.0.11(postcss@8.4.35) + '@csstools/postcss-gradients-interpolation-method': 4.0.20(postcss@8.4.35) + '@csstools/postcss-hwb-function': 3.0.18(postcss@8.4.35) + '@csstools/postcss-ic-unit': 3.0.7(postcss@8.4.35) '@csstools/postcss-initial': 1.0.1(postcss@8.4.35) - '@csstools/postcss-is-pseudo-class': 4.0.4(postcss@8.4.35) + '@csstools/postcss-is-pseudo-class': 4.0.8(postcss@8.4.35) + '@csstools/postcss-light-dark-function': 1.0.8(postcss@8.4.35) '@csstools/postcss-logical-float-and-clear': 2.0.1(postcss@8.4.35) '@csstools/postcss-logical-overflow': 1.0.1(postcss@8.4.35) '@csstools/postcss-logical-overscroll-behavior': 1.0.1(postcss@8.4.35) '@csstools/postcss-logical-resize': 2.0.1(postcss@8.4.35) - '@csstools/postcss-logical-viewport-units': 2.0.5(postcss@8.4.35) - '@csstools/postcss-media-minmax': 1.1.2(postcss@8.4.35) - '@csstools/postcss-media-queries-aspect-ratio-number-values': 2.0.5(postcss@8.4.35) - '@csstools/postcss-nested-calc': 3.0.1(postcss@8.4.35) + '@csstools/postcss-logical-viewport-units': 2.0.11(postcss@8.4.35) + '@csstools/postcss-media-minmax': 1.1.8(postcss@8.4.35) + '@csstools/postcss-media-queries-aspect-ratio-number-values': 2.0.11(postcss@8.4.35) + '@csstools/postcss-nested-calc': 3.0.2(postcss@8.4.35) '@csstools/postcss-normalize-display-values': 3.0.2(postcss@8.4.35) - '@csstools/postcss-oklab-function': 3.0.9(postcss@8.4.35) - '@csstools/postcss-progressive-custom-properties': 3.0.3(postcss@8.4.35) - '@csstools/postcss-relative-color-syntax': 2.0.9(postcss@8.4.35) + '@csstools/postcss-oklab-function': 3.0.19(postcss@8.4.35) + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.35) + '@csstools/postcss-relative-color-syntax': 2.0.19(postcss@8.4.35) '@csstools/postcss-scope-pseudo-class': 3.0.1(postcss@8.4.35) - '@csstools/postcss-stepped-value-functions': 3.0.4(postcss@8.4.35) - '@csstools/postcss-text-decoration-shorthand': 3.0.4(postcss@8.4.35) - '@csstools/postcss-trigonometric-functions': 3.0.4(postcss@8.4.35) + '@csstools/postcss-stepped-value-functions': 3.0.10(postcss@8.4.35) + '@csstools/postcss-text-decoration-shorthand': 3.0.7(postcss@8.4.35) + '@csstools/postcss-trigonometric-functions': 3.0.10(postcss@8.4.35) '@csstools/postcss-unset-value': 3.0.1(postcss@8.4.35) - autoprefixer: 10.4.17(postcss@8.4.35) - browserslist: 4.23.0 - css-blank-pseudo: 6.0.1(postcss@8.4.35) - css-has-pseudo: 6.0.1(postcss@8.4.35) + autoprefixer: 10.4.27(postcss@8.4.35) + browserslist: 4.28.1 + css-blank-pseudo: 6.0.2(postcss@8.4.35) + css-has-pseudo: 6.0.5(postcss@8.4.35) css-prefers-color-scheme: 9.0.1(postcss@8.4.35) - cssdb: 7.11.0 + cssdb: 8.8.0 postcss: 8.4.35 - postcss-attribute-case-insensitive: 6.0.2(postcss@8.4.35) + postcss-attribute-case-insensitive: 6.0.3(postcss@8.4.35) postcss-clamp: 4.1.0(postcss@8.4.35) - postcss-color-functional-notation: 6.0.4(postcss@8.4.35) - postcss-color-hex-alpha: 9.0.3(postcss@8.4.35) - postcss-color-rebeccapurple: 9.0.2(postcss@8.4.35) - postcss-custom-media: 10.0.2(postcss@8.4.35) - postcss-custom-properties: 13.3.4(postcss@8.4.35) - postcss-custom-selectors: 7.1.6(postcss@8.4.35) + postcss-color-functional-notation: 6.0.14(postcss@8.4.35) + postcss-color-hex-alpha: 9.0.4(postcss@8.4.35) + postcss-color-rebeccapurple: 9.0.3(postcss@8.4.35) + postcss-custom-media: 10.0.8(postcss@8.4.35) + postcss-custom-properties: 13.3.12(postcss@8.4.35) + postcss-custom-selectors: 7.1.12(postcss@8.4.35) postcss-dir-pseudo-class: 8.0.1(postcss@8.4.35) - postcss-double-position-gradients: 5.0.3(postcss@8.4.35) + postcss-double-position-gradients: 5.0.7(postcss@8.4.35) postcss-focus-visible: 9.0.1(postcss@8.4.35) postcss-focus-within: 8.0.1(postcss@8.4.35) postcss-font-variant: 5.0.0(postcss@8.4.35) postcss-gap-properties: 5.0.1(postcss@8.4.35) - postcss-image-set-function: 6.0.2(postcss@8.4.35) - postcss-lab-function: 6.0.9(postcss@8.4.35) + postcss-image-set-function: 6.0.3(postcss@8.4.35) + postcss-lab-function: 6.0.19(postcss@8.4.35) postcss-logical: 7.0.1(postcss@8.4.35) - postcss-nesting: 12.0.2(postcss@8.4.35) + postcss-nesting: 12.1.5(postcss@8.4.35) postcss-opacity-percentage: 2.0.0(postcss@8.4.35) postcss-overflow-shorthand: 5.0.1(postcss@8.4.35) postcss-page-break: 3.0.4(postcss@8.4.35) postcss-place: 9.0.1(postcss@8.4.35) - postcss-pseudo-class-any-link: 9.0.1(postcss@8.4.35) + postcss-pseudo-class-any-link: 9.0.2(postcss@8.4.35) postcss-replace-overflow-wrap: 4.0.0(postcss@8.4.35) - postcss-selector-not: 7.0.1(postcss@8.4.35) - postcss-value-parser: 4.2.0 + postcss-selector-not: 7.0.2(postcss@8.4.35) - postcss-pseudo-class-any-link@9.0.1(postcss@8.4.35): + postcss-pseudo-class-any-link@9.0.2(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-replace-overflow-wrap@4.0.0(postcss@8.4.35): dependencies: @@ -16855,16 +20605,21 @@ snapshots: dependencies: postcss: 8.4.35 - postcss-selector-not@7.0.1(postcss@8.4.35): + postcss-selector-not@7.0.2(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.1.2 postcss-selector-parser@6.0.15: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-simple-vars@6.0.3(postcss@8.4.35): dependencies: postcss: 8.4.35 @@ -16881,6 +20636,12 @@ snapshots: picocolors: 1.0.0 source-map-js: 1.0.2 + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + preact@10.12.1: {} prelude-ls@1.2.1: {} @@ -16927,108 +20688,108 @@ snapshots: retry: 0.12.0 signal-exit: 3.0.7 - prosemirror-changeset@2.2.1: + prosemirror-changeset@2.4.0: dependencies: - prosemirror-transform: 1.10.0 + prosemirror-transform: 1.11.0 prosemirror-collab@1.3.1: dependencies: - prosemirror-state: 1.4.3 + prosemirror-state: 1.4.4 - prosemirror-commands@1.6.0: + prosemirror-commands@1.7.1: dependencies: - prosemirror-model: 1.22.3 - prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 - prosemirror-dropcursor@1.8.1: + prosemirror-dropcursor@1.8.2: dependencies: - prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 - prosemirror-gapcursor@1.3.2: + prosemirror-gapcursor@1.4.0: dependencies: - prosemirror-keymap: 1.2.2 - prosemirror-model: 1.22.3 - prosemirror-state: 1.4.3 - prosemirror-view: 1.34.3 + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.6 - prosemirror-history@1.4.1: + prosemirror-history@1.5.0: dependencies: - prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 rope-sequence: 1.3.4 - prosemirror-inputrules@1.4.0: + prosemirror-inputrules@1.5.1: dependencies: - prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 - prosemirror-keymap@1.2.2: + prosemirror-keymap@1.2.3: dependencies: - prosemirror-state: 1.4.3 + prosemirror-state: 1.4.4 w3c-keyname: 2.2.8 - prosemirror-markdown@1.13.1: + prosemirror-markdown@1.13.4: dependencies: '@types/markdown-it': 14.1.2 - markdown-it: 14.1.0 - prosemirror-model: 1.22.3 + markdown-it: 14.1.1 + prosemirror-model: 1.25.4 - prosemirror-menu@1.2.4: + prosemirror-menu@1.3.0: dependencies: crelt: 1.0.6 - prosemirror-commands: 1.6.0 - prosemirror-history: 1.4.1 - prosemirror-state: 1.4.3 + prosemirror-commands: 1.7.1 + prosemirror-history: 1.5.0 + prosemirror-state: 1.4.4 - prosemirror-model@1.22.3: + prosemirror-model@1.25.4: dependencies: orderedmap: 2.1.1 - prosemirror-schema-basic@1.2.3: + prosemirror-schema-basic@1.2.4: dependencies: - prosemirror-model: 1.22.3 + prosemirror-model: 1.25.4 - prosemirror-schema-list@1.4.1: + prosemirror-schema-list@1.5.1: dependencies: - prosemirror-model: 1.22.3 - prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 - prosemirror-state@1.4.3: + prosemirror-state@1.4.4: dependencies: - prosemirror-model: 1.22.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-model: 1.25.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 - prosemirror-tables@1.5.0: + prosemirror-tables@1.8.5: dependencies: - prosemirror-keymap: 1.2.2 - prosemirror-model: 1.22.3 - prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 - prosemirror-trailing-node@3.0.0(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.34.3): + prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6): dependencies: '@remirror/core-constants': 3.0.0 escape-string-regexp: 4.0.0 - prosemirror-model: 1.22.3 - prosemirror-state: 1.4.3 - prosemirror-view: 1.34.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.6 - prosemirror-transform@1.10.0: + prosemirror-transform@1.11.0: dependencies: - prosemirror-model: 1.22.3 + prosemirror-model: 1.25.4 - prosemirror-view@1.34.3: + prosemirror-view@1.41.6: dependencies: - prosemirror-model: 1.22.3 - prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 proxy-addr@2.0.7: dependencies: @@ -17039,16 +20800,16 @@ snapshots: public-encrypt@4.0.3: dependencies: - bn.js: 4.12.0 - browserify-rsa: 4.1.0 + bn.js: 4.12.3 + browserify-rsa: 4.1.1 create-hash: 1.2.0 - parse-asn1: 5.1.6 + parse-asn1: 5.1.9 randombytes: 2.1.0 safe-buffer: 5.2.1 pump@2.0.1: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 pump@3.0.0: @@ -17056,6 +20817,11 @@ snapshots: end-of-stream: 1.4.4 once: 1.4.0 + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + pumpify@1.5.1: dependencies: duplexify: 3.7.1 @@ -17076,6 +20842,10 @@ snapshots: dependencies: side-channel: 1.0.5 + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + querystring-es3@0.2.1: {} queue-microtask@1.2.3: {} @@ -17206,6 +20976,10 @@ snapshots: dependencies: regenerate: 1.4.2 + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + regenerate@1.4.2: {} regenerator-runtime@0.11.1: {} @@ -17239,6 +21013,15 @@ snapshots: unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.1.0 + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.0 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + registry-auth-token@4.2.2: dependencies: rc: 1.2.8 @@ -17247,12 +21030,20 @@ snapshots: dependencies: rc: 1.2.8 + regjsgen@0.8.0: {} + + regjsparser@0.13.0: + dependencies: + jsesc: 3.1.0 + regjsparser@0.9.1: dependencies: jsesc: 0.5.0 remote-git-tags@3.0.0: {} + remote-promises@1.0.0: {} + remove-trailing-separator@1.1.0: {} remove-types@1.0.0: @@ -17321,6 +21112,14 @@ snapshots: resolve-url@0.2.1: {} + resolve.exports@2.0.3: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -17359,9 +21158,9 @@ snapshots: dependencies: glob: 7.2.3 - ripemd160@2.0.2: + ripemd160@2.0.3: dependencies: - hash-base: 3.1.0 + hash-base: 3.1.2 inherits: 2.0.4 rollup-pluginutils@2.8.2: @@ -17463,13 +21262,15 @@ snapshots: sc-errors@2.0.3: {} + sc-errors@3.0.0: {} + sc-formatter@4.0.0: {} schema-utils@1.0.0: dependencies: - ajv: 6.12.6 - ajv-errors: 1.0.1(ajv@6.12.6) - ajv-keywords: 3.5.2(ajv@6.12.6) + ajv: 6.14.0 + ajv-errors: 1.0.1(ajv@6.14.0) + ajv-keywords: 3.5.2(ajv@6.14.0) schema-utils@2.7.1: dependencies: @@ -17490,6 +21291,13 @@ snapshots: ajv-formats: 2.1.1(ajv@8.12.0) ajv-keywords: 5.1.0(ajv@8.12.0) + schema-utils@4.3.3: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.18.0 + ajv-formats: 2.1.1(ajv@8.18.0) + ajv-keywords: 5.1.0(ajv@8.18.0) + semver@5.7.2: {} semver@6.3.1: {} @@ -17498,6 +21306,8 @@ snapshots: dependencies: lru-cache: 6.0.0 + semver@7.7.4: {} + send@0.18.0: dependencies: debug: 2.6.9 @@ -17544,6 +21354,15 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.2 + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + set-function-name@2.0.1: dependencies: define-data-property: 1.1.4 @@ -17563,10 +21382,11 @@ snapshots: setprototypeof@1.2.0: {} - sha.js@2.4.11: + sha.js@2.4.12: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 + to-buffer: 1.2.2 shallow-clone@3.0.1: dependencies: @@ -17588,6 +21408,26 @@ snapshots: shellwords@0.1.1: {} + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + side-channel@1.0.5: dependencies: call-bind: 1.0.7 @@ -17595,6 +21435,14 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -17678,7 +21526,7 @@ snapshots: socketcluster-client@17.2.2: dependencies: ag-channel: 5.0.0 - ag-request: 1.0.1 + ag-request: 1.1.0 async-stream-emitter: 4.1.0 buffer: 5.7.1 clone-deep: 4.0.1 @@ -17688,7 +21536,7 @@ snapshots: stream-demux: 8.1.0 uuid: 8.3.2 vinyl-buffer: 1.0.1 - ws: 8.16.0 + ws: 8.19.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -17708,6 +21556,8 @@ snapshots: source-map-js@1.0.2: {} + source-map-js@1.2.1: {} + source-map-resolve@0.5.3: dependencies: atob: 2.1.2 @@ -17798,7 +21648,7 @@ snapshots: stream-each@1.2.3: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 stream-shift: 1.0.3 stream-http@2.8.3: @@ -17975,14 +21825,14 @@ snapshots: - supports-color - typescript - sucrase@3.35.0: + sucrase@3.35.1: dependencies: - '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/gen-mapping': 0.3.13 commander: 4.1.1 - glob: 10.3.10 lines-and-columns: 1.2.4 mz: 2.7.0 - pirates: 4.0.6 + pirates: 4.0.7 + tinyglobby: 0.2.15 ts-interface-checker: 0.1.13 sugarss@4.0.1(postcss@8.4.35): @@ -18043,7 +21893,7 @@ snapshots: '@pkgr/core': 0.1.1 tslib: 2.6.2 - tabbable@5.3.3: {} + tabbable@6.4.0: {} table@6.8.1: dependencies: @@ -18053,32 +21903,33 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tailwindcss@3.4.1: + tailwindcss@3.4.19: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 chokidar: 3.6.0 didyoumean: 1.2.2 dlv: 1.1.3 - fast-glob: 3.3.2 + fast-glob: 3.3.3 glob-parent: 6.0.2 is-glob: 4.0.3 - jiti: 1.21.0 - lilconfig: 2.1.0 - micromatch: 4.0.5 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.0.0 - postcss: 8.4.35 - postcss-import: 15.1.0(postcss@8.4.35) - postcss-js: 4.0.1(postcss@8.4.35) - postcss-load-config: 4.0.2(postcss@8.4.35) - postcss-nested: 6.0.1(postcss@8.4.35) - postcss-selector-parser: 6.0.15 - resolve: 1.22.8 - sucrase: 3.35.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6) + postcss-nested: 6.2.0(postcss@8.5.6) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 transitivePeerDependencies: - - ts-node + - tsx + - yaml tap-parser@7.0.0: dependencies: @@ -18090,12 +21941,14 @@ snapshots: tapable@2.2.1: {} + tapable@2.3.0: {} + temp@0.9.4: dependencies: mkdirp: 0.5.6 rimraf: 2.6.3 - terser-webpack-plugin@1.4.5(webpack@4.47.0): + terser-webpack-plugin@1.4.6(webpack@4.47.0): dependencies: cacache: 12.0.4 find-cache-dir: 2.1.0 @@ -18119,7 +21972,7 @@ snapshots: terser@4.8.1: dependencies: - acorn: 8.11.3 + acorn: 8.16.0 commander: 2.20.3 source-map: 0.6.1 source-map-support: 0.5.21 @@ -18131,7 +21984,7 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - testem@3.11.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(underscore@1.13.6): + testem@3.11.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(underscore@1.13.6): dependencies: '@xmldom/xmldom': 0.8.10 backbone: 1.6.0 @@ -18139,7 +21992,7 @@ snapshots: charm: 1.0.2 commander: 2.20.3 compression: 1.7.4 - consolidate: 0.16.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.21)(mustache@4.2.0)(underscore@1.13.6) + consolidate: 0.16.0(babel-core@6.26.3)(handlebars@4.7.8)(lodash@4.17.23)(mustache@4.2.0)(underscore@1.13.6) execa: 1.0.0 express: 4.18.2 fireworm: 0.7.2 @@ -18264,6 +22117,11 @@ snapshots: transitivePeerDependencies: - supports-color + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + tmp@0.0.28: dependencies: os-tmpdir: 1.0.2 @@ -18284,6 +22142,12 @@ snapshots: to-arraybuffer@1.0.1: {} + to-buffer@1.2.2: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + to-fast-properties@1.0.3: {} to-fast-properties@2.0.0: {} @@ -18316,7 +22180,7 @@ snapshots: tracked-built-ins@3.3.0: dependencies: - '@embroider/addon-shim': 1.8.7 + '@embroider/addon-shim': 1.10.2 ember-tracked-storage-polyfill: 1.0.0 transitivePeerDependencies: - supports-color @@ -18367,6 +22231,8 @@ snapshots: type-fest@1.4.0: {} + type-fest@4.41.0: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -18378,6 +22244,12 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.13 + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + typed-array-byte-length@1.0.0: dependencies: call-bind: 1.0.7 @@ -18440,6 +22312,8 @@ snapshots: unicode-match-property-value-ecmascript@2.1.0: {} + unicode-match-property-value-ecmascript@2.2.1: {} + unicode-property-aliases-ecmascript@2.1.0: {} union-value@1.0.1: @@ -18483,6 +22357,12 @@ snapshots: escalade: 3.1.2 picocolors: 1.0.0 + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -18493,10 +22373,10 @@ snapshots: dependencies: prepend-http: 2.0.0 - url@0.11.3: + url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.11.2 + qs: 6.15.0 use@3.1.1: {} @@ -18627,9 +22507,9 @@ snapshots: '@webassemblyjs/wasm-edit': 1.9.0 '@webassemblyjs/wasm-parser': 1.9.0 acorn: 6.4.2 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - chrome-trace-event: 1.0.3 + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) + chrome-trace-event: 1.0.4 enhanced-resolve: 4.5.0 eslint-scope: 4.0.3 json-parse-better-errors: 1.0.2 @@ -18642,7 +22522,7 @@ snapshots: node-libs-browser: 2.2.1 schema-utils: 1.0.0 tapable: 1.1.3 - terser-webpack-plugin: 1.4.5(webpack@4.47.0) + terser-webpack-plugin: 1.4.6(webpack@4.47.0) watchpack: 1.7.5 webpack-sources: 1.4.3 transitivePeerDependencies: @@ -18708,6 +22588,16 @@ snapshots: gopd: 1.0.1 has-tostringtag: 1.0.2 + which-typed-array@1.1.20: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@1.3.1: dependencies: isexe: 2.0.0 @@ -18774,7 +22664,7 @@ snapshots: ws@8.11.0: {} - ws@8.16.0: {} + ws@8.19.0: {} xdg-basedir@4.0.0: {} @@ -18793,8 +22683,6 @@ snapshots: fs-extra: 4.0.3 lodash.merge: 4.6.2 - yaml@2.3.4: {} - yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} From 3856dc0a1a089e36970252aa81e2c17a90cf77ed Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sat, 28 Feb 2026 02:30:24 -0500 Subject: [PATCH 004/209] =?UTF-8?q?feat(ledger):=20implement=20Milestone?= =?UTF-8?q?=201=20=E2=80=94=20core=20backend=20stabilisation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M1.1 — Fix WalletService accounting direction - Deposit: DEBIT Cash (asset+), CREDIT Wallet Liability (liability+) - Withdrawal: DEBIT Wallet Liability (liability-), CREDIT Cash (asset-) - Added currency propagation from wallet to journal entry - Replaced getDefaultExpenseAccount with getDefaultCashAccount for withdrawals (expense account is used for driver payouts in M3, not raw withdrawals) M1.2 — Add HasPublicId trait to Journal model - Added use HasPublicId trait - Set publicIdPrefix = 'journal' - Added public_id to $fillable and $appends M1.3 — Migration: add public_id to ledger_journals table - New migration: 2024_01_01_000006_add_public_id_to_ledger_journals_table.php - Adds nullable unique string column after _key M1.4 — Enrich LedgerService::createJournalEntry - Transaction payload now populates: subject_uuid, subject_type, gateway_uuid, notes, gateway_transaction_id from $options - currency falls back to debit account currency before defaulting to USD - Added getTrialBalance() method (debit/credit totals across all accounts) - Improved getGeneralLedger() with eager-loaded relations and secondary sort - Improved getBalanceAtDate() with explicit int cast - Enriched docblocks on all public methods M1.5 — Improve InvoiceService::createItemsFromOrder - Three-strategy item resolution: 1. FleetOps payload entities (native order items) 2. Order meta 'items' array (storefront-style) 3. Fallback single summary line item - Separate line items for delivery_fee and service_fee from order meta - Currency resolved from options > order meta > default USD - recordPayment now passes subject_uuid/subject_type to journal entry M1.6 — Add LedgerSeeder - New file: server/seeds/LedgerSeeder.php - Seeds 24 default system accounts (assets, liabilities, equity, revenue, expenses) - Idempotent via firstOrCreate — safe to run multiple times - runForCompany() method for use in company provisioning hooks - Covers: Cash, Bank, AR, AP, Wallet Pool, Driver Payable, Tax Payable, Stripe Clearing, Gateway Clearing, Delivery Revenue, Service Fee Revenue, Driver Payout Expense, Gateway Fees, Refunds, and more M1.7 — Add journal entry routes and reporting routes - GET/POST/DELETE ledger/int/v1/journals (JournalController) - GET ledger/int/v1/accounts/{id}/ledger (general ledger per account) - GET ledger/int/v1/reports/trial-balance (ReportController) - POST ledger/int/v1/invoices/{id}/send (InvoiceController::send) - New controllers: JournalController, ReportController - AccountController: injected LedgerService, added generalLedger() method - InvoiceController: added send() method with customer email validation --- ...add_public_id_to_ledger_journals_table.php | 37 +++ server/seeds/LedgerSeeder.php | 284 ++++++++++++++++++ .../Internal/v1/AccountController.php | 51 ++++ .../Internal/v1/InvoiceController.php | 39 +++ .../Internal/v1/JournalController.php | 197 ++++++++++++ .../Internal/v1/ReportController.php | 56 ++++ server/src/Models/Journal.php | 12 +- server/src/Services/InvoiceService.php | 162 ++++++++-- server/src/Services/LedgerService.php | 212 ++++++++++--- server/src/Services/WalletService.php | 91 +++--- server/src/routes.php | 44 ++- 11 files changed, 1057 insertions(+), 128 deletions(-) create mode 100644 server/migrations/2024_01_01_000006_add_public_id_to_ledger_journals_table.php create mode 100644 server/seeds/LedgerSeeder.php create mode 100644 server/src/Http/Controllers/Internal/v1/JournalController.php create mode 100644 server/src/Http/Controllers/Internal/v1/ReportController.php diff --git a/server/migrations/2024_01_01_000006_add_public_id_to_ledger_journals_table.php b/server/migrations/2024_01_01_000006_add_public_id_to_ledger_journals_table.php new file mode 100644 index 0000000..d3ca57b --- /dev/null +++ b/server/migrations/2024_01_01_000006_add_public_id_to_ledger_journals_table.php @@ -0,0 +1,37 @@ +string('public_id', 191)->nullable()->unique()->after('_key'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('ledger_journals', function (Blueprint $table) { + $table->dropColumn('public_id'); + }); + } +}; diff --git a/server/seeds/LedgerSeeder.php b/server/seeds/LedgerSeeder.php new file mode 100644 index 0000000..48154ec --- /dev/null +++ b/server/seeds/LedgerSeeder.php @@ -0,0 +1,284 @@ +runForCompany($companyUuid); + */ +class LedgerSeeder extends Seeder +{ + /** + * The default system accounts to seed. + * Each entry maps to a row in `ledger_accounts`. + * + * @var array> + */ + protected array $defaultAccounts = [ + // ----------------------------------------------------------------------- + // ASSETS (1000–1999) + // ----------------------------------------------------------------------- + [ + 'code' => 'CASH-DEFAULT', + 'name' => 'Cash', + 'type' => 'asset', + 'description' => 'Primary cash account for all cash receipts and payments.', + 'is_system_account' => true, + ], + [ + 'code' => 'BANK-DEFAULT', + 'name' => 'Bank Account', + 'type' => 'asset', + 'description' => 'Primary bank / checking account.', + 'is_system_account' => true, + ], + [ + 'code' => 'AR-DEFAULT', + 'name' => 'Accounts Receivable', + 'type' => 'asset', + 'description' => 'Amounts owed to the company by customers for delivered services.', + 'is_system_account' => true, + ], + [ + 'code' => 'STRIPE-CLEARING', + 'name' => 'Stripe Clearing Account', + 'type' => 'asset', + 'description' => 'Funds in transit from Stripe before settlement to the bank account.', + 'is_system_account' => true, + ], + [ + 'code' => 'GATEWAY-CLEARING', + 'name' => 'Payment Gateway Clearing', + 'type' => 'asset', + 'description' => 'Generic clearing account for payment gateway funds in transit.', + 'is_system_account' => true, + ], + [ + 'code' => 'PREPAID-DEFAULT', + 'name' => 'Prepaid Expenses', + 'type' => 'asset', + 'description' => 'Expenses paid in advance (e.g. prepaid insurance, subscriptions).', + 'is_system_account' => true, + ], + + // ----------------------------------------------------------------------- + // LIABILITIES (2000–2999) + // ----------------------------------------------------------------------- + [ + 'code' => 'AP-DEFAULT', + 'name' => 'Accounts Payable', + 'type' => 'liability', + 'description' => 'Amounts owed by the company to suppliers and service providers.', + 'is_system_account' => true, + ], + [ + 'code' => 'WALLET-POOL', + 'name' => 'Wallet Liability Pool', + 'type' => 'liability', + 'description' => 'Aggregate liability representing all customer and driver wallet balances.', + 'is_system_account' => true, + ], + [ + 'code' => 'DRIVER-PAYABLE', + 'name' => 'Driver Earnings Payable', + 'type' => 'liability', + 'description' => 'Earnings accrued to drivers that have not yet been paid out.', + 'is_system_account' => true, + ], + [ + 'code' => 'CUSTOMER-CREDIT', + 'name' => 'Customer Credit Liability', + 'type' => 'liability', + 'description' => 'Credit balances held on behalf of customers (refunds, promotions).', + 'is_system_account' => true, + ], + [ + 'code' => 'TAX-PAYABLE', + 'name' => 'Tax Payable', + 'type' => 'liability', + 'description' => 'Sales tax and VAT collected from customers, payable to tax authorities.', + 'is_system_account' => true, + ], + [ + 'code' => 'STRIPE-FEES-PAYABLE', + 'name' => 'Stripe Fees Payable', + 'type' => 'liability', + 'description' => 'Processing fees charged by Stripe, accrued before settlement.', + 'is_system_account' => true, + ], + [ + 'code' => 'DEFERRED-REVENUE', + 'name' => 'Deferred Revenue', + 'type' => 'liability', + 'description' => 'Payments received before the service has been delivered.', + 'is_system_account' => true, + ], + + // ----------------------------------------------------------------------- + // EQUITY (3000–3999) + // ----------------------------------------------------------------------- + [ + 'code' => 'EQUITY-DEFAULT', + 'name' => 'Owner\'s Equity', + 'type' => 'equity', + 'description' => 'Residual interest in the company assets after deducting liabilities.', + 'is_system_account' => true, + ], + [ + 'code' => 'RETAINED-EARNINGS', + 'name' => 'Retained Earnings', + 'type' => 'equity', + 'description' => 'Cumulative net income retained in the business.', + 'is_system_account' => true, + ], + + // ----------------------------------------------------------------------- + // REVENUE (4000–4999) + // ----------------------------------------------------------------------- + [ + 'code' => 'REVENUE-DELIVERY', + 'name' => 'Delivery Revenue', + 'type' => 'revenue', + 'description' => 'Revenue earned from completed delivery orders.', + 'is_system_account' => true, + ], + [ + 'code' => 'REVENUE-SERVICE-FEE', + 'name' => 'Service Fee Revenue', + 'type' => 'revenue', + 'description' => 'Platform service fees charged on top of delivery revenue.', + 'is_system_account' => true, + ], + [ + 'code' => 'REVENUE-SUBSCRIPTION', + 'name' => 'Subscription Revenue', + 'type' => 'revenue', + 'description' => 'Recurring subscription fees from merchants and partners.', + 'is_system_account' => true, + ], + [ + 'code' => 'REVENUE-OTHER', + 'name' => 'Other Revenue', + 'type' => 'revenue', + 'description' => 'Miscellaneous revenue not classified elsewhere.', + 'is_system_account' => true, + ], + + // ----------------------------------------------------------------------- + // EXPENSES (5000–5999) + // ----------------------------------------------------------------------- + [ + 'code' => 'EXPENSE-DRIVER-PAYOUT', + 'name' => 'Driver Payout Expense', + 'type' => 'expense', + 'description' => 'Earnings paid out to drivers for completed deliveries.', + 'is_system_account' => true, + ], + [ + 'code' => 'EXPENSE-GATEWAY-FEES', + 'name' => 'Payment Gateway Fees', + 'type' => 'expense', + 'description' => 'Transaction processing fees charged by payment gateways (Stripe, QPay, etc.).', + 'is_system_account' => true, + ], + [ + 'code' => 'EXPENSE-REFUNDS', + 'name' => 'Refunds & Chargebacks', + 'type' => 'expense', + 'description' => 'Customer refunds and chargeback losses.', + 'is_system_account' => true, + ], + [ + 'code' => 'EXPENSE-WALLET', + 'name' => 'Wallet Expenses', + 'type' => 'expense', + 'description' => 'Expenses arising from wallet top-up promotions and adjustments.', + 'is_system_account' => true, + ], + [ + 'code' => 'EXPENSE-OTHER', + 'name' => 'Other Operating Expenses', + 'type' => 'expense', + 'description' => 'Miscellaneous operating expenses not classified elsewhere.', + 'is_system_account' => true, + ], + ]; + + /** + * Run the seeder for all companies. + * + * When called via `php artisan db:seed`, this method seeds accounts for + * every company currently in the database. + * + * @return void + */ + public function run(): void + { + // Resolve the Company model dynamically to avoid a hard dependency on + // the core-api package at class-load time. + $companyModel = app('Fleetbase\Models\Company'); + $companies = $companyModel::all(); + + foreach ($companies as $company) { + $this->runForCompany($company->uuid); + } + + $this->command?->info( + sprintf( + '[Ledger] Seeded %d default accounts for %d companies.', + count($this->defaultAccounts), + $companies->count() + ) + ); + } + + /** + * Seed default system accounts for a specific company. + * + * This method is safe to call from company-provisioning hooks, onboarding + * flows, or tests. It is idempotent — existing accounts are not modified. + * + * @param string $companyUuid + * + * @return void + */ + public function runForCompany(string $companyUuid): void + { + foreach ($this->defaultAccounts as $accountData) { + Account::firstOrCreate( + [ + 'company_uuid' => $companyUuid, + 'code' => $accountData['code'], + ], + array_merge($accountData, [ + 'company_uuid' => $companyUuid, + 'balance' => 0, + 'is_active' => true, + ]) + ); + } + } +} diff --git a/server/src/Http/Controllers/Internal/v1/AccountController.php b/server/src/Http/Controllers/Internal/v1/AccountController.php index 5369dc5..482bd84 100644 --- a/server/src/Http/Controllers/Internal/v1/AccountController.php +++ b/server/src/Http/Controllers/Internal/v1/AccountController.php @@ -5,6 +5,8 @@ use Fleetbase\Http\Controllers\Controller; use Fleetbase\Ledger\Http\Resources\v1\Account as AccountResource; use Fleetbase\Ledger\Models\Account; +use Fleetbase\Ledger\Services\LedgerService; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class AccountController extends Controller @@ -23,6 +25,23 @@ class AccountController extends Controller */ public $model = Account::class; + /** + * The ledger service instance. + * + * @var LedgerService + */ + protected LedgerService $ledgerService; + + /** + * Create a new AccountController instance. + * + * @param LedgerService $ledgerService + */ + public function __construct(LedgerService $ledgerService) + { + $this->ledgerService = $ledgerService; + } + /** * Query for accounts. * @@ -166,4 +185,36 @@ public function recalculateBalance($id, Request $request) return new AccountResource($account); } + + /** + * Return the general ledger for a specific account. + * + * Returns all journal entries where this account appears on either the debit + * or credit side, ordered chronologically. Supports optional date range filtering + * via `date_from` and `date_to` query parameters. + * + * @param string $id + * @param Request $request + * + * @return JsonResponse + */ + public function generalLedger($id, Request $request): JsonResponse + { + $account = Account::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + $entries = $this->ledgerService->getGeneralLedger( + $account, + $request->input('date_from'), + $request->input('date_to') + ); + + return response()->json([ + 'account' => new AccountResource($account), + 'entries' => $entries, + ]); + } } diff --git a/server/src/Http/Controllers/Internal/v1/InvoiceController.php b/server/src/Http/Controllers/Internal/v1/InvoiceController.php index 4a2e3c6..6d936b5 100644 --- a/server/src/Http/Controllers/Internal/v1/InvoiceController.php +++ b/server/src/Http/Controllers/Internal/v1/InvoiceController.php @@ -258,4 +258,43 @@ public function markAsSent($id, Request $request) return new InvoiceResource($invoice); } + + /** + * Send an invoice to the customer via email. + * + * Marks the invoice as sent and dispatches a notification to the customer's + * email address. If the invoice has no customer or the customer has no email, + * a 422 error is returned. + * + * @param string $id + * @param Request $request + * + * @return \Illuminate\Http\Response + */ + public function send($id, Request $request) + { + $invoice = Invoice::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->with('customer') + ->firstOrFail(); + + // Validate that the invoice has a sendable customer + if (!$invoice->customer || !$invoice->customer->email) { + return response()->json( + ['error' => 'Invoice customer does not have a valid email address.'], + 422 + ); + } + + // Mark as sent + $invoice->markAsSent(); + + // TODO (M5): Dispatch InvoiceSentNotification to $invoice->customer->email + // \Illuminate\Support\Facades\Notification::route('mail', $invoice->customer->email) + // ->notify(new \Fleetbase\Ledger\Notifications\InvoiceSentNotification($invoice)); + + return new InvoiceResource($invoice->load(['customer', 'items'])); + } } diff --git a/server/src/Http/Controllers/Internal/v1/JournalController.php b/server/src/Http/Controllers/Internal/v1/JournalController.php new file mode 100644 index 0000000..fe75867 --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/JournalController.php @@ -0,0 +1,197 @@ +ledgerService = $ledgerService; + } + + /** + * Query journal entries for the authenticated company. + * + * Supports filtering by: + * - debit_account_uuid — entries where this account was debited + * - credit_account_uuid — entries where this account was credited + * - account_uuid — entries where this account appears on either side + * - date_from — inclusive start date (ISO format) + * - date_to — inclusive end date (ISO format) + * - search — partial match on description + * + * @param Request $request + * + * @return JsonResponse + */ + public function query(Request $request): JsonResponse + { + $query = Journal::with(['transaction', 'debitAccount', 'creditAccount']) + ->where('company_uuid', session('company')); + + // Filter by a specific account on either side of the entry + if ($request->filled('account_uuid')) { + $accountUuid = $request->input('account_uuid'); + $query->where(function ($q) use ($accountUuid) { + $q->where('debit_account_uuid', $accountUuid) + ->orWhere('credit_account_uuid', $accountUuid); + }); + } + + if ($request->filled('debit_account_uuid')) { + $query->where('debit_account_uuid', $request->input('debit_account_uuid')); + } + + if ($request->filled('credit_account_uuid')) { + $query->where('credit_account_uuid', $request->input('credit_account_uuid')); + } + + if ($request->filled('date_from')) { + $query->where('date', '>=', $request->input('date_from')); + } + + if ($request->filled('date_to')) { + $query->where('date', '<=', $request->input('date_to')); + } + + if ($request->filled('search')) { + $search = $request->input('search'); + $query->where('description', 'like', "%{$search}%"); + } + + $results = $query + ->orderBy($request->input('sort', 'date'), $request->input('order', 'desc')) + ->orderBy('created_at', 'desc') + ->paginate($request->input('limit', 15)); + + return response()->json($results); + } + + /** + * Find a single journal entry by UUID or public_id. + * + * @param string $id + * @param Request $request + * + * @return JsonResponse + */ + public function find(string $id, Request $request): JsonResponse + { + $journal = Journal::with(['transaction', 'debitAccount', 'creditAccount']) + ->where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + return response()->json($journal); + } + + /** + * Create a manual journal entry. + * + * Manual entries allow operators to record adjustments, corrections, or + * opening balances that are not generated automatically by system events. + * + * @param Request $request + * + * @return JsonResponse + */ + public function create(Request $request): JsonResponse + { + $request->validate([ + 'debit_account_uuid' => 'required|uuid|exists:ledger_accounts,uuid', + 'credit_account_uuid' => 'required|uuid|exists:ledger_accounts,uuid|different:debit_account_uuid', + 'amount' => 'required|integer|min:1', + 'currency' => 'nullable|string|size:3', + 'description' => 'required|string|max:500', + 'date' => 'nullable|date', + ]); + + $debitAccount = \Fleetbase\Ledger\Models\Account::where('company_uuid', session('company')) + ->where('uuid', $request->input('debit_account_uuid')) + ->firstOrFail(); + + $creditAccount = \Fleetbase\Ledger\Models\Account::where('company_uuid', session('company')) + ->where('uuid', $request->input('credit_account_uuid')) + ->firstOrFail(); + + $journal = $this->ledgerService->createJournalEntry( + $debitAccount, + $creditAccount, + (int) $request->input('amount'), + $request->input('description'), + [ + 'company_uuid' => session('company'), + 'currency' => $request->input('currency', 'USD'), + 'type' => 'manual_entry', + 'date' => $request->input('date', now()), + ] + ); + + return response()->json($journal->load(['transaction', 'debitAccount', 'creditAccount']), 201); + } + + /** + * Delete a journal entry. + * + * Only non-system-generated entries (type = 'manual_entry') may be deleted. + * Deleting a journal entry does not reverse the associated Transaction record + * but does recalculate the affected account balances. + * + * @param string $id + * @param Request $request + * + * @return JsonResponse + */ + public function delete(string $id, Request $request): JsonResponse + { + $journal = Journal::where('company_uuid', session('company')) + ->where(function ($query) use ($id) { + $query->where('uuid', $id)->orWhere('public_id', $id); + }) + ->firstOrFail(); + + // Prevent deletion of system-generated entries + if ($journal->transaction && $journal->transaction->type !== 'manual_entry') { + return response()->json( + ['error' => 'Only manual journal entries may be deleted. System-generated entries are immutable.'], + 422 + ); + } + + // Capture accounts before deletion so we can recalculate their balances + $debitAccount = $journal->debitAccount; + $creditAccount = $journal->creditAccount; + + $journal->delete(); + + // Recalculate balances on both affected accounts + if ($debitAccount) { + $debitAccount->updateBalance(); + } + if ($creditAccount) { + $creditAccount->updateBalance(); + } + + return response()->json(['status' => 'ok']); + } +} diff --git a/server/src/Http/Controllers/Internal/v1/ReportController.php b/server/src/Http/Controllers/Internal/v1/ReportController.php new file mode 100644 index 0000000..f1cefee --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/ReportController.php @@ -0,0 +1,56 @@ +ledgerService = $ledgerService; + } + + /** + * Generate a trial balance report for the authenticated company. + * + * The trial balance lists every active account with its debit and credit + * totals as of a given date. The sum of all debit-normal balances must + * equal the sum of all credit-normal balances for the books to be balanced. + * + * Query parameters: + * - as_of_date (string, optional) ISO date string; defaults to today. + * + * @param Request $request + * + * @return JsonResponse + */ + public function trialBalance(Request $request): JsonResponse + { + $request->validate([ + 'as_of_date' => 'nullable|date', + ]); + + $companyUuid = session('company'); + $asOfDate = $request->input('as_of_date'); + + $trialBalance = $this->ledgerService->getTrialBalance($companyUuid, $asOfDate); + + return response()->json($trialBalance); + } +} diff --git a/server/src/Models/Journal.php b/server/src/Models/Journal.php index a13a3cc..97f6343 100644 --- a/server/src/Models/Journal.php +++ b/server/src/Models/Journal.php @@ -7,6 +7,7 @@ use Fleetbase\Models\Transaction; use Fleetbase\Traits\HasApiModelBehavior; use Fleetbase\Traits\HasMetaAttributes; +use Fleetbase\Traits\HasPublicId; use Fleetbase\Traits\HasUuid; use Fleetbase\Traits\TracksApiCredential; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -14,10 +15,18 @@ class Journal extends Model { use HasUuid; + use HasPublicId; use HasApiModelBehavior; use HasMetaAttributes; use TracksApiCredential; + /** + * The prefix used when auto-generating public IDs for journal entries. + * + * @var string + */ + public $publicIdPrefix = 'journal'; + /** * The database table used by the model. * @@ -32,6 +41,7 @@ class Journal extends Model */ protected $fillable = [ '_key', + 'public_id', 'company_uuid', 'transaction_uuid', 'debit_account_uuid', @@ -59,7 +69,7 @@ class Journal extends Model * * @var array */ - protected $appends = []; + protected $appends = ['public_id']; /** * The attributes excluded from the model's JSON form. diff --git a/server/src/Services/InvoiceService.php b/server/src/Services/InvoiceService.php index de9ac36..67a1860 100644 --- a/server/src/Services/InvoiceService.php +++ b/server/src/Services/InvoiceService.php @@ -28,7 +28,12 @@ public function __construct(LedgerService $ledgerService) } /** - * Create an invoice from an order. + * Create an invoice from a FleetOps order. + * + * Generates a draft invoice with line items derived from the order's payload + * (entities/items, delivery fee, service fees, etc.). The invoice is linked + * to the order via `order_uuid` and to the customer via the order's customer + * polymorphic relationship. * * @param Order $order * @param array $options @@ -38,7 +43,12 @@ public function __construct(LedgerService $ledgerService) public function createFromOrder(Order $order, array $options = []): Invoice { return DB::transaction(function () use ($order, $options) { - // Create the invoice + // Resolve currency from options, order meta, or company default + $currency = $options['currency'] + ?? $order->getMeta('currency') + ?? 'USD'; + + // Create the invoice header $invoice = Invoice::create([ 'company_uuid' => $order->company_uuid, 'customer_uuid' => $order->customer_uuid, @@ -47,16 +57,16 @@ public function createFromOrder(Order $order, array $options = []): Invoice 'number' => $options['number'] ?? Invoice::generateNumber(), 'date' => $options['date'] ?? now(), 'due_date' => $options['due_date'] ?? now()->addDays(30), - 'currency' => $options['currency'] ?? 'USD', + 'currency' => $currency, 'status' => 'draft', 'notes' => $options['notes'] ?? null, 'terms' => $options['terms'] ?? null, ]); - // Create invoice items from order + // Create line items from the order's payload $this->createItemsFromOrder($invoice, $order); - // Calculate totals + // Calculate and persist subtotal, tax, and total $invoice->calculateTotals(); $invoice->save(); @@ -65,7 +75,15 @@ public function createFromOrder(Order $order, array $options = []): Invoice } /** - * Create invoice items from an order. + * Create invoice line items from a FleetOps order. + * + * Resolution order for line items: + * 1. Order payload entities (goods being transported) — each entity becomes a line item. + * 2. Order meta `items` array — storefront-style line items stored in meta. + * 3. Fallback — a single summary line item using the order's total from meta. + * + * Delivery fee and service fees stored in order meta are added as separate line items + * so the invoice accurately reflects the full charge breakdown. * * @param Invoice $invoice * @param Order $order @@ -74,23 +92,115 @@ public function createFromOrder(Order $order, array $options = []): Invoice */ protected function createItemsFromOrder(Invoice $invoice, Order $order): void { - // Create a line item for the order - InvoiceItem::create([ - 'invoice_uuid' => $invoice->uuid, - 'description' => "Order: {$order->public_id}", - 'quantity' => 1, - 'unit_price' => $order->getMeta('total', 0), - 'amount' => $order->getMeta('total', 0), - 'tax_rate' => 0, - 'tax_amount' => 0, - ]); + $itemsCreated = 0; + + // --- Strategy 1: Order payload entities (FleetOps native) --- + // Each entity in the order payload represents a physical item being transported. + if ($order->relationLoaded('payload') || $order->payload) { + $payload = $order->payload; + if ($payload && $payload->entities && $payload->entities->isNotEmpty()) { + foreach ($payload->entities as $entity) { + $unitPrice = (int) ($entity->price ?? $entity->getMeta('price', 0)); + $quantity = (int) ($entity->qty ?? $entity->getMeta('qty', 1)); + $quantity = max(1, $quantity); + + InvoiceItem::create([ + 'invoice_uuid' => $invoice->uuid, + 'description' => $entity->name ?? $entity->description ?? "Item from order {$order->public_id}", + 'quantity' => $quantity, + 'unit_price' => $unitPrice, + 'amount' => $unitPrice * $quantity, + 'tax_rate' => 0, + 'tax_amount' => 0, + ]); + + $itemsCreated++; + } + } + } + + // --- Strategy 2: Order meta `items` array (storefront-style) --- + // Storefront orders store line items as a JSON array in order meta. + if ($itemsCreated === 0) { + $metaItems = $order->getMeta('items', []); + if (is_array($metaItems) && count($metaItems) > 0) { + foreach ($metaItems as $item) { + $unitPrice = (int) ($item['price'] ?? $item['unit_price'] ?? 0); + $quantity = (int) ($item['quantity'] ?? $item['qty'] ?? 1); + $quantity = max(1, $quantity); + + InvoiceItem::create([ + 'invoice_uuid' => $invoice->uuid, + 'description' => $item['name'] ?? $item['description'] ?? 'Order item', + 'quantity' => $quantity, + 'unit_price' => $unitPrice, + 'amount' => $unitPrice * $quantity, + 'tax_rate' => (int) ($item['tax_rate'] ?? 0), + 'tax_amount' => (int) ($item['tax_amount'] ?? 0), + ]); + + $itemsCreated++; + } + } + } + + // --- Strategy 3: Fallback — single summary line item --- + // If no structured items could be resolved, create a single line item + // representing the order total so the invoice is never empty. + if ($itemsCreated === 0) { + $total = (int) $order->getMeta('total', 0); + + InvoiceItem::create([ + 'invoice_uuid' => $invoice->uuid, + 'description' => "Delivery service — Order {$order->public_id}", + 'quantity' => 1, + 'unit_price' => $total, + 'amount' => $total, + 'tax_rate' => 0, + 'tax_amount' => 0, + ]); + + $itemsCreated++; + } + + // --- Delivery fee line item --- + // Add a separate line item for the delivery fee if present in order meta. + $deliveryFee = (int) $order->getMeta('delivery_fee', 0); + if ($deliveryFee > 0) { + InvoiceItem::create([ + 'invoice_uuid' => $invoice->uuid, + 'description' => 'Delivery fee', + 'quantity' => 1, + 'unit_price' => $deliveryFee, + 'amount' => $deliveryFee, + 'tax_rate' => 0, + 'tax_amount' => 0, + ]); + } + + // --- Service fee line item --- + $serviceFee = (int) $order->getMeta('service_fee', 0); + if ($serviceFee > 0) { + InvoiceItem::create([ + 'invoice_uuid' => $invoice->uuid, + 'description' => 'Service fee', + 'quantity' => 1, + 'unit_price' => $serviceFee, + 'amount' => $serviceFee, + 'tax_rate' => 0, + 'tax_amount' => 0, + ]); + } } /** - * Record a payment for an invoice. + * Record a payment against an invoice. + * + * Creates the double-entry journal entry (Debit Cash, Credit Accounts Receivable) + * and updates the invoice's paid amount, balance, and status accordingly. * * @param Invoice $invoice - * @param int $amount + * @param int $amount Amount in smallest currency unit (e.g. cents). * @param array $options * * @return Invoice @@ -98,11 +208,10 @@ protected function createItemsFromOrder(Invoice $invoice, Order $order): void public function recordPayment(Invoice $invoice, int $amount, array $options = []): Invoice { return DB::transaction(function () use ($invoice, $amount, $options) { - // Get accounts $cashAccount = $this->getCashAccount($invoice->company_uuid); $arAccount = $this->getAccountsReceivableAccount($invoice->company_uuid); - // Create journal entry: Debit Cash, Credit Accounts Receivable + // DEBIT Cash (asset increases — money received), CREDIT Accounts Receivable (asset decreases — AR settled) $journal = $this->ledgerService->createJournalEntry( $cashAccount, $arAccount, @@ -110,13 +219,16 @@ public function recordPayment(Invoice $invoice, int $amount, array $options = [] "Payment for invoice {$invoice->number}", array_merge($options, [ 'company_uuid' => $invoice->company_uuid, + 'currency' => $invoice->currency, 'type' => 'invoice_payment', + 'subject_uuid' => $invoice->uuid, + 'subject_type' => Invoice::class, ]) ); - // Update invoice + // Update invoice payment tracking $invoice->amount_paid += $amount; - $invoice->balance = $invoice->total_amount - $invoice->amount_paid; + $invoice->balance = $invoice->total_amount - $invoice->amount_paid; if ($invoice->balance <= 0) { $invoice->markAsPaid(); @@ -124,7 +236,7 @@ public function recordPayment(Invoice $invoice, int $amount, array $options = [] $invoice->status = 'partial'; } - // Link the transaction to the invoice + // Link the core Transaction to the invoice on first payment if (!$invoice->transaction_uuid) { $invoice->transaction_uuid = $journal->transaction_uuid; } @@ -136,7 +248,7 @@ public function recordPayment(Invoice $invoice, int $amount, array $options = [] } /** - * Get or create the cash account. + * Get or create the default cash account for a company. * * @param string $companyUuid * @@ -159,7 +271,7 @@ protected function getCashAccount(string $companyUuid): Account } /** - * Get or create the accounts receivable account. + * Get or create the default accounts receivable account for a company. * * @param string $companyUuid * diff --git a/server/src/Services/LedgerService.php b/server/src/Services/LedgerService.php index 31d5da9..aff2224 100644 --- a/server/src/Services/LedgerService.php +++ b/server/src/Services/LedgerService.php @@ -10,13 +10,33 @@ class LedgerService { /** - * Create a journal entry with double-entry bookkeeping. + * Create a double-entry journal entry and the corresponding core Transaction record. * - * @param Account $debitAccount - * @param Account $creditAccount - * @param int $amount - * @param string $description - * @param array $options + * Every financial movement in Ledger is represented as a pair of records: + * 1. A `Transaction` (core-api primitive) - the canonical, auditable money-movement record. + * 2. A `Journal` (Ledger model) - the double-entry bookkeeping entry that links the + * debit and credit accounts to that transaction. + * + * All monetary amounts are stored in the smallest currency unit (e.g. cents for USD). + * + * Supported $options keys: + * - company_uuid (string) Company context; falls back to session('company'). + * - currency (string) ISO 4217 currency code; defaults to account currency or 'USD'. + * - type (string) Transaction type label (e.g. 'wallet_deposit', 'invoice_payment'). + * - status (string) Transaction status; defaults to 'completed'. + * - date (mixed) Journal entry date; defaults to now(). + * - transaction_id (string) External/gateway transaction reference ID. + * - subject_uuid (string) UUID of the polymorphic subject (order, driver, customer, etc.). + * - subject_type (string) Fully-qualified class name of the subject. + * - gateway_uuid (string) UUID of the payment gateway used (if applicable). + * - meta (array) Arbitrary key-value metadata stored on both records. + * - notes (string) Human-readable notes attached to the transaction. + * + * @param Account $debitAccount The account to debit. + * @param Account $creditAccount The account to credit. + * @param int $amount Amount in smallest currency unit (e.g. cents). + * @param string $description Human-readable description of the entry. + * @param array $options Additional options (see above). * * @return Journal */ @@ -28,32 +48,63 @@ public function createJournalEntry( array $options = [] ): Journal { return DB::transaction(function () use ($debitAccount, $creditAccount, $amount, $description, $options) { - // Create the core transaction record - $transaction = Transaction::create([ - 'company_uuid' => $options['company_uuid'] ?? session('company'), - 'gateway_transaction_id' => $options['transaction_id'] ?? Transaction::generateNumber(), - 'amount' => $amount, - 'currency' => $options['currency'] ?? 'USD', - 'description' => $description, - 'type' => $options['type'] ?? 'ledger', - 'status' => $options['status'] ?? 'completed', - 'meta' => $options['meta'] ?? [], - ]); + $companyUuid = $options['company_uuid'] ?? session('company'); + $currency = $options['currency'] ?? $debitAccount->currency ?? 'USD'; + $type = $options['type'] ?? 'ledger'; + $status = $options['status'] ?? 'completed'; + $meta = $options['meta'] ?? []; + + // Build the Transaction payload, populating every relevant field from the + // core-api Transaction model so the record is fully queryable from the + // standard transactions API without needing Ledger-specific queries. + $transactionPayload = [ + 'company_uuid' => $companyUuid, + 'amount' => $amount, + 'currency' => $currency, + 'description' => $description, + 'type' => $type, + 'status' => $status, + 'meta' => $meta, + ]; - // Create the journal entry + // Attach optional contextual fields when provided + if (!empty($options['transaction_id'])) { + $transactionPayload['gateway_transaction_id'] = $options['transaction_id']; + } + + if (!empty($options['subject_uuid'])) { + $transactionPayload['subject_uuid'] = $options['subject_uuid']; + } + + if (!empty($options['subject_type'])) { + $transactionPayload['subject_type'] = $options['subject_type']; + } + + if (!empty($options['gateway_uuid'])) { + $transactionPayload['gateway_uuid'] = $options['gateway_uuid']; + } + + if (!empty($options['notes'])) { + $transactionPayload['notes'] = $options['notes']; + } + + // Create the canonical Transaction record in core-api + $transaction = Transaction::create($transactionPayload); + + // Create the double-entry Journal record linking debit and credit accounts $journal = Journal::create([ - 'company_uuid' => $transaction->company_uuid, + 'company_uuid' => $companyUuid, 'transaction_uuid' => $transaction->uuid, 'debit_account_uuid' => $debitAccount->uuid, 'credit_account_uuid' => $creditAccount->uuid, 'amount' => $amount, - 'currency' => $transaction->currency, + 'currency' => $currency, 'description' => $description, 'date' => $options['date'] ?? now(), - 'meta' => $options['meta'] ?? [], + 'meta' => $meta, ]); - // Update account balances + // Recalculate and persist the cached balance on both affected accounts $debitAccount->updateBalance(); $creditAccount->updateBalance(); @@ -64,9 +115,9 @@ public function createJournalEntry( /** * Transfer funds between two accounts. * - * @param Account $fromAccount - * @param Account $toAccount - * @param int $amount + * @param Account $fromAccount Account to debit (source). + * @param Account $toAccount Account to credit (destination). + * @param int $amount Amount in smallest currency unit. * @param string $description * @param array $options * @@ -79,14 +130,22 @@ public function transfer( string $description = '', array $options = [] ): Journal { - return $this->createJournalEntry($fromAccount, $toAccount, $amount, $description, $options); + return $this->createJournalEntry( + $fromAccount, + $toAccount, + $amount, + $description, + array_merge(['type' => 'transfer'], $options) + ); } /** - * Record revenue. + * Record revenue received. * - * @param Account $assetAccount - * @param Account $revenueAccount + * Correct treatment: DEBIT Asset (cash/AR increases), CREDIT Revenue (revenue increases). + * + * @param Account $assetAccount The asset account receiving the funds (debit). + * @param Account $revenueAccount The revenue account being recognised (credit). * @param int $amount * @param string $description * @param array $options @@ -100,14 +159,22 @@ public function recordRevenue( string $description = '', array $options = [] ): Journal { - return $this->createJournalEntry($assetAccount, $revenueAccount, $amount, $description, $options); + return $this->createJournalEntry( + $assetAccount, + $revenueAccount, + $amount, + $description, + array_merge(['type' => 'revenue'], $options) + ); } /** - * Record an expense. + * Record an expense incurred. + * + * Correct treatment: DEBIT Expense (expense increases), CREDIT Asset (cash/AP decreases). * - * @param Account $expenseAccount - * @param Account $assetAccount + * @param Account $expenseAccount The expense account being charged (debit). + * @param Account $assetAccount The asset account being reduced (credit). * @param int $amount * @param string $description * @param array $options @@ -121,24 +188,31 @@ public function recordExpense( string $description = '', array $options = [] ): Journal { - return $this->createJournalEntry($expenseAccount, $assetAccount, $amount, $description, $options); + return $this->createJournalEntry( + $expenseAccount, + $assetAccount, + $amount, + $description, + array_merge(['type' => 'expense'], $options) + ); } /** - * Get the general ledger for a specific account. + * Get all journal entries for a specific account (the general ledger view). * - * @param Account $account - * @param string|null $startDate - * @param string|null $endDate + * @param Account $account + * @param string|null $startDate ISO date string (inclusive lower bound). + * @param string|null $endDate ISO date string (inclusive upper bound). * * @return \Illuminate\Support\Collection */ public function getGeneralLedger(Account $account, ?string $startDate = null, ?string $endDate = null) { - $query = Journal::where(function ($q) use ($account) { - $q->where('debit_account_uuid', $account->uuid) - ->orWhere('credit_account_uuid', $account->uuid); - }); + $query = Journal::with(['transaction', 'debitAccount', 'creditAccount']) + ->where(function ($q) use ($account) { + $q->where('debit_account_uuid', $account->uuid) + ->orWhere('credit_account_uuid', $account->uuid); + }); if ($startDate) { $query->where('date', '>=', $startDate); @@ -148,16 +222,20 @@ public function getGeneralLedger(Account $account, ?string $startDate = null, ?s $query->where('date', '<=', $endDate); } - return $query->orderBy('date', 'asc')->get(); + return $query->orderBy('date', 'asc')->orderBy('created_at', 'asc')->get(); } /** - * Calculate the balance for an account at a specific date. + * Calculate the balance for an account at (or up to) a specific date. + * + * Uses the standard accounting normal balance rules: + * - Asset & Expense accounts: balance = debits - credits (debit-normal) + * - Liability, Equity & Revenue accounts: balance = credits - debits (credit-normal) * * @param Account $account - * @param string $date + * @param string $date ISO date string (inclusive upper bound). * - * @return int + * @return int Balance in smallest currency unit. */ public function getBalanceAtDate(Account $account, string $date): int { @@ -170,9 +248,47 @@ public function getBalanceAtDate(Account $account, string $date): int ->sum('amount'); if (in_array($account->type, ['asset', 'expense'])) { - return $debits - $credits; + return (int) ($debits - $credits); } - return $credits - $debits; + return (int) ($credits - $debits); + } + + /** + * Get a trial balance snapshot for a company. + * + * @param string $companyUuid + * @param string|null $asOfDate ISO date string; defaults to today. + * + * @return array + */ + public function getTrialBalance(string $companyUuid, ?string $asOfDate = null): array + { + $asOfDate = $asOfDate ?? now()->toDateString(); + + $accounts = Account::where('company_uuid', $companyUuid) + ->where('is_active', true) + ->get() + ->map(function (Account $account) use ($asOfDate) { + $balance = $this->getBalanceAtDate($account, $asOfDate); + + return [ + 'account' => $account, + 'balance' => $balance, + 'debit_total' => in_array($account->type, ['asset', 'expense']) ? max(0, $balance) : 0, + 'credit_total' => in_array($account->type, ['liability', 'equity', 'revenue']) ? max(0, $balance) : 0, + ]; + }); + + $debitTotal = $accounts->sum('debit_total'); + $creditTotal = $accounts->sum('credit_total'); + + return [ + 'accounts' => $accounts, + 'debit_total' => $debitTotal, + 'credit_total' => $creditTotal, + 'balanced' => $debitTotal === $creditTotal, + 'as_of_date' => $asOfDate, + ]; } } diff --git a/server/src/Services/WalletService.php b/server/src/Services/WalletService.php index 7a02867..d4e8ddf 100644 --- a/server/src/Services/WalletService.php +++ b/server/src/Services/WalletService.php @@ -53,8 +53,12 @@ public function getOrCreateWallet(Model $subject, string $currency = 'USD'): Wal /** * Deposit funds into a wallet. * + * Correct double-entry accounting treatment for a wallet deposit: + * DEBIT Cash / Source Account (asset increases — money received) + * CREDIT Wallet Liability (liability increases — we owe more to wallet holder) + * * @param Wallet $wallet - * @param int $amount + * @param int $amount Amount in smallest currency unit (e.g. cents) * @param string $description * @param array $options * @@ -67,20 +71,21 @@ public function deposit(Wallet $wallet, int $amount, string $description = '', a } return DB::transaction(function () use ($wallet, $amount, $description, $options) { - // Get or create the wallet liability account - $walletAccount = $this->getWalletAccount($wallet); + // Debit: Cash / source account (asset increases — money received) + $cashAccount = $options['source_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); - // Get the source account (e.g., cash or bank account) - $sourceAccount = $options['source_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); + // Credit: Wallet liability account (liability increases — we owe more to the wallet holder) + $walletAccount = $this->getWalletAccount($wallet); - // Create journal entry: Debit Wallet Liability, Credit Source Account + // DEBIT Cash, CREDIT Wallet Liability $this->ledgerService->createJournalEntry( - $walletAccount, - $sourceAccount, + $cashAccount, // debit — asset increases + $walletAccount, // credit — liability increases $amount, $description ?: "Deposit to wallet {$wallet->public_id}", array_merge($options, [ 'company_uuid' => $wallet->company_uuid, + 'currency' => $wallet->currency, 'type' => 'wallet_deposit', ]) ); @@ -96,8 +101,12 @@ public function deposit(Wallet $wallet, int $amount, string $description = '', a /** * Withdraw funds from a wallet. * + * Correct double-entry accounting treatment for a wallet withdrawal: + * DEBIT Wallet Liability (liability decreases — we owe less to wallet holder) + * CREDIT Cash / Dest Account (asset decreases — money paid out) + * * @param Wallet $wallet - * @param int $amount + * @param int $amount Amount in smallest currency unit (e.g. cents) * @param string $description * @param array $options * @@ -114,20 +123,21 @@ public function withdraw(Wallet $wallet, int $amount, string $description = '', } return DB::transaction(function () use ($wallet, $amount, $description, $options) { - // Get or create the wallet liability account + // Debit: Wallet liability account (liability decreases — we owe less to the wallet holder) $walletAccount = $this->getWalletAccount($wallet); - // Get the destination account (e.g., expense or cash account) - $destinationAccount = $options['destination_account'] ?? $this->getDefaultExpenseAccount($wallet->company_uuid); + // Credit: Cash / destination account (asset decreases — money paid out) + $cashAccount = $options['destination_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); - // Create journal entry: Debit Destination Account, Credit Wallet Liability + // DEBIT Wallet Liability, CREDIT Cash $this->ledgerService->createJournalEntry( - $destinationAccount, - $walletAccount, + $walletAccount, // debit — liability decreases + $cashAccount, // credit — asset decreases $amount, $description ?: "Withdrawal from wallet {$wallet->public_id}", array_merge($options, [ 'company_uuid' => $wallet->company_uuid, + 'currency' => $wallet->currency, 'type' => 'wallet_withdrawal', ]) ); @@ -143,9 +153,13 @@ public function withdraw(Wallet $wallet, int $amount, string $description = '', /** * Transfer funds between two wallets. * + * Correct double-entry accounting treatment for a wallet-to-wallet transfer: + * DEBIT From Wallet Liability (source liability decreases — we owe less to source holder) + * CREDIT To Wallet Liability (destination liability increases — we owe more to dest holder) + * * @param Wallet $fromWallet * @param Wallet $toWallet - * @param int $amount + * @param int $amount Amount in smallest currency unit (e.g. cents) * @param string $description * @param array $options * @@ -162,18 +176,21 @@ public function transfer(Wallet $fromWallet, Wallet $toWallet, int $amount, stri } return DB::transaction(function () use ($fromWallet, $toWallet, $amount, $description, $options) { - // Get wallet accounts + // Debit: From wallet liability (source liability decreases — we owe less to source holder) $fromAccount = $this->getWalletAccount($fromWallet); - $toAccount = $this->getWalletAccount($toWallet); - // Create journal entry: Debit To Wallet, Credit From Wallet + // Credit: To wallet liability (destination liability increases — we owe more to dest holder) + $toAccount = $this->getWalletAccount($toWallet); + + // DEBIT From Wallet Liability, CREDIT To Wallet Liability $journal = $this->ledgerService->createJournalEntry( - $toAccount, - $fromAccount, + $fromAccount, // debit — source liability decreases + $toAccount, // credit — destination liability increases $amount, - $description ?: "Transfer from {$fromWallet->public_id} to {$toWallet->public_id}", + $description ?: "Transfer from wallet {$fromWallet->public_id} to {$toWallet->public_id}", array_merge($options, [ 'company_uuid' => $fromWallet->company_uuid, + 'currency' => $fromWallet->currency, 'type' => 'wallet_transfer', ]) ); @@ -194,7 +211,10 @@ public function transfer(Wallet $fromWallet, Wallet $toWallet, int $amount, stri } /** - * Get or create the ledger account for a wallet. + * Get or create the ledger liability account for a wallet. + * + * Each wallet has its own dedicated liability account in the chart of accounts. + * This account represents the amount the company owes to the wallet holder. * * @param Wallet $wallet * @@ -218,7 +238,7 @@ protected function getWalletAccount(Wallet $wallet): Account } /** - * Get the default cash account. + * Get or create the default cash account for a company. * * @param string $companyUuid * @@ -240,26 +260,5 @@ protected function getDefaultCashAccount(string $companyUuid): Account ); } - /** - * Get the default expense account. - * - * @param string $companyUuid - * - * @return Account - */ - protected function getDefaultExpenseAccount(string $companyUuid): Account - { - return Account::firstOrCreate( - [ - 'company_uuid' => $companyUuid, - 'code' => 'EXPENSE-WALLET', - ], - [ - 'name' => 'Wallet Expenses', - 'type' => 'expense', - 'description' => 'Expenses from wallet withdrawals', - 'is_system_account' => true, - ] - ); - } } + diff --git a/server/src/routes.php b/server/src/routes.php index 79999a9..b0fb8df 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -4,12 +4,12 @@ /* |-------------------------------------------------------------------------- -| API Routes +| Ledger API Routes |-------------------------------------------------------------------------- | -| Here is where you can register API routes for your application. These -| routes are loaded by the RouteServiceProvider within a group which -| is assigned the "api" middleware group. Enjoy building your API! +| All routes are prefixed with the configured ledger prefix (default: 'ledger') +| and are protected by the 'fleetbase.protected' middleware which requires a +| valid Fleetbase session or API key. | */ @@ -17,17 +17,21 @@ function ($router) { /* |-------------------------------------------------------------------------- - | Internal Billing API Routes + | Internal Ledger API Routes |-------------------------------------------------------------------------- | - | Primary internal routes for console. + | These routes are consumed by the Fleetbase console frontend (Ember engine). + | They are protected and require an authenticated session. */ $router->prefix(config('ledger.api.routing.internal_prefix', 'int'))->group( function ($router) { $router->group( ['prefix' => 'v1', 'middleware' => ['fleetbase.protected']], function ($router) { - // Accounts + + // ------------------------------------------------------------ + // Accounts (Chart of Accounts) + // ------------------------------------------------------------ $router->get('accounts', 'Internal\v1\AccountController@query'); $router->get('accounts/{id}', 'Internal\v1\AccountController@find'); $router->post('accounts', 'Internal\v1\AccountController@create'); @@ -35,7 +39,20 @@ function ($router) { $router->delete('accounts/{id}', 'Internal\v1\AccountController@delete'); $router->post('accounts/{id}/recalculate-balance', 'Internal\v1\AccountController@recalculateBalance'); + // General ledger for a specific account (all journal entries for that account) + $router->get('accounts/{id}/ledger', 'Internal\v1\AccountController@generalLedger'); + + // ------------------------------------------------------------ + // Journal Entries + // ------------------------------------------------------------ + $router->get('journals', 'Internal\v1\JournalController@query'); + $router->get('journals/{id}', 'Internal\v1\JournalController@find'); + $router->post('journals', 'Internal\v1\JournalController@create'); + $router->delete('journals/{id}', 'Internal\v1\JournalController@delete'); + + // ------------------------------------------------------------ // Invoices + // ------------------------------------------------------------ $router->get('invoices', 'Internal\v1\InvoiceController@query'); $router->get('invoices/{id}', 'Internal\v1\InvoiceController@find'); $router->post('invoices', 'Internal\v1\InvoiceController@create'); @@ -44,8 +61,11 @@ function ($router) { $router->post('invoices/from-order', 'Internal\v1\InvoiceController@createFromOrder'); $router->post('invoices/{id}/record-payment', 'Internal\v1\InvoiceController@recordPayment'); $router->post('invoices/{id}/mark-as-sent', 'Internal\v1\InvoiceController@markAsSent'); + $router->post('invoices/{id}/send', 'Internal\v1\InvoiceController@send'); + // ------------------------------------------------------------ // Wallets + // ------------------------------------------------------------ $router->get('wallets', 'Internal\v1\WalletController@query'); $router->get('wallets/{id}', 'Internal\v1\WalletController@find'); $router->post('wallets', 'Internal\v1\WalletController@create'); @@ -55,9 +75,17 @@ function ($router) { $router->post('wallets/{id}/withdraw', 'Internal\v1\WalletController@withdraw'); $router->post('wallets/transfer', 'Internal\v1\WalletController@transfer'); - // Transactions (System-wide viewer) + // ------------------------------------------------------------ + // Transactions (read-only view of core-api Transaction records) + // ------------------------------------------------------------ $router->get('transactions', 'Internal\v1\TransactionController@query'); $router->get('transactions/{id}', 'Internal\v1\TransactionController@find'); + + // ------------------------------------------------------------ + // Reports & Financial Statements + // ------------------------------------------------------------ + // Trial balance — debit/credit totals across all accounts + $router->get('reports/trial-balance', 'Internal\v1\ReportController@trialBalance'); } ); } From 67412f06a86ff4c8a3c51536067919c1f5020deb Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sat, 28 Feb 2026 02:58:02 -0500 Subject: [PATCH 005/209] feat(payment-gateways): implement full payment gateway abstraction layer (M2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Overview Complete refactor and re-imagination of the payment gateway system as a first-class, interface-driven, extensible architecture. Replaces the ad-hoc Storefront gateway code with a clean, driver-based system that makes adding new payment gateways a 3-step process. ## M2.1 — Core Abstraction Layer - Add GatewayDriverInterface (Contracts/) — the contract every driver must implement Methods: purchase(), refund(), handleWebhook(), createPaymentMethod(), getCapabilities(), getConfigSchema(), initialize() - Add PurchaseRequest DTO — typed, immutable purchase request - Add RefundRequest DTO — typed, immutable refund request - Add GatewayResponse DTO — normalized response from any gateway Includes: status, successful, gatewayTransactionId, eventType, amount, currency, message, data, rawResponse, errorCode - Add AbstractGatewayDriver — base class with shared helpers (logInfo, logError, hasCapability, config, formatAmount) - Add WebhookSignatureException — thrown on HMAC/signature failures - Add Gateway model (ledger_gateways) — replaces storefront.gateways Features: encrypted:array config cast, HasPublicId, HasUuid, decryptedConfig(), getWebhookUrl(), capabilities JSON column - Add GatewayTransaction model (ledger_gateway_transactions) — new audit and idempotency log linking gateway events to the core transactions table Features: alreadyProcessed(), isProcessed(), markAsProcessed() - Add PaymentGatewayManager — extends Laravel Manager, resolves drivers by name, injects credentials, returns ready-to-use driver instances Registers: stripe, qpay, cash drivers Exposes: getDriverManifest() for frontend dynamic form rendering - Migration 000007: create ledger_gateways table - Migration 000008: create ledger_gateway_transactions table ## M2.2 — Stripe Driver - Full StripeDriver implementation using stripe/stripe-php SDK - purchase(): creates PaymentIntent with automatic_payment_methods - refund(): creates Stripe Refund via Refunds::create() - handleWebhook(): verifies Stripe-Signature header using constructEvent() Maps Stripe events to normalized GatewayResponse event types: payment_intent.succeeded → EVENT_PAYMENT_SUCCEEDED payment_intent.payment_failed → EVENT_PAYMENT_FAILED charge.refunded → EVENT_REFUND_PROCESSED - createPaymentMethod(): creates SetupIntent for card tokenization - getConfigSchema(): returns publishable_key, secret_key, webhook_secret fields - getCapabilities(): purchase, refund, webhooks, tokenization, setup_intents ## M2.3 — QPay Driver - Full QPayDriver implementation (refactored from Storefront QPay support class) - Retains all QPay business logic: token auth, invoice creation, deep links - purchase(): authenticates, creates QPay invoice, returns payment URL + deep links - refund(): calls QPay refund API with original transaction reference - handleWebhook(): verifies QPay callback signature, maps to normalized events - getConfigSchema(): username, password, invoice_code, merchant_id, terminal_id - getCapabilities(): purchase, refund, webhooks, redirect ## M2.4 — Cash Driver - CashDriver for cash on delivery and manual payment scenarios - purchase(): immediately marks as succeeded, generates local reference ID - refund(): records manual refund, no external API call - getConfigSchema(): label, instructions (operator-configurable display text) - getCapabilities(): purchase, refund (no webhooks needed) ## M2.5 — Webhook System - Add WebhookController (POST /ledger/webhooks/{driver}) Flow: identify gateway → verify signature → idempotency check → persist GatewayTransaction → dispatch normalized event → return 200 Always returns 200 to prevent gateway retries on internal errors Returns 400 only for signature verification failures - Add PaymentSucceeded event - Add PaymentFailed event - Add RefundProcessed event - Add HandleSuccessfulPayment listener (ShouldQueue, 3 retries, 30s backoff) Actions: mark invoice paid, create revenue journal entry, seal transaction - Add HandleFailedPayment listener (ShouldQueue) Actions: mark invoice overdue, seal transaction - Add HandleProcessedRefund listener (ShouldQueue) Actions: mark invoice refunded, create reversal journal entry, seal transaction ## M2.6 — PaymentService & GatewayController - Add PaymentService — single orchestration entry point for all payments charge(): resolve gateway → call driver → persist → dispatch event refund(): resolve gateway → call driver → persist → dispatch event createPaymentMethod(): tokenize card via driver getDriverManifest(): return driver list for frontend - Add GatewayController with full CRUD + payment operations: GET /ledger/int/v1/gateways → list all gateways POST /ledger/int/v1/gateways → create gateway GET /ledger/int/v1/gateways/{id} → get gateway PUT /ledger/int/v1/gateways/{id} → update gateway config DELETE /ledger/int/v1/gateways/{id} → delete gateway GET /ledger/int/v1/gateways/drivers → driver manifest (dynamic forms) POST /ledger/int/v1/gateways/{id}/charge → initiate payment POST /ledger/int/v1/gateways/{id}/refund → refund transaction POST /ledger/int/v1/gateways/{id}/setup-intent → tokenize card GET /ledger/int/v1/gateways/{id}/transactions → transaction history - Add Gateway API Resource (excludes credentials from responses) - Add POST /ledger/webhooks/{driver} (public, no auth) to routes.php ## M2.7 — Wiring & Dependencies - Update LedgerServiceProvider: register PaymentGatewayManager singleton, alias as 'ledger.gateway', register PaymentService, bind all 3 event- listener pairs via Event::listen() - Update composer.json: add stripe/stripe-php ^13.0, guzzlehttp/guzzle ^7.0 --- composer.json | 4 +- ...01_000007_create_ledger_gateways_table.php | 56 ++ ...eate_ledger_gateway_transactions_table.php | 72 +++ .../src/Contracts/GatewayDriverInterface.php | 134 ++++ server/src/DTO/GatewayResponse.php | 155 +++++ server/src/DTO/PurchaseRequest.php | 53 ++ server/src/DTO/RefundRequest.php | 32 + server/src/Events/PaymentFailed.php | 42 ++ server/src/Events/PaymentSucceeded.php | 45 ++ server/src/Events/RefundProcessed.php | 42 ++ .../Exceptions/WebhookSignatureException.php | 27 + server/src/Gateways/AbstractGatewayDriver.php | 146 +++++ server/src/Gateways/CashDriver.php | 137 +++++ server/src/Gateways/QPayDriver.php | 580 ++++++++++++++++++ server/src/Gateways/StripeDriver.php | 423 +++++++++++++ .../Internal/v1/GatewayController.php | 383 ++++++++++++ .../Http/Controllers/WebhookController.php | 162 +++++ server/src/Http/Resources/v1/Gateway.php | 41 ++ server/src/Listeners/HandleFailedPayment.php | 73 +++ .../src/Listeners/HandleProcessedRefund.php | 93 +++ .../src/Listeners/HandleSuccessfulPayment.php | 126 ++++ server/src/Models/Gateway.php | 193 ++++++ server/src/Models/GatewayTransaction.php | 175 ++++++ server/src/PaymentGatewayManager.php | 162 +++++ .../src/Providers/LedgerServiceProvider.php | 57 +- server/src/Services/PaymentService.php | 236 +++++++ server/src/routes.php | 38 ++ 27 files changed, 3681 insertions(+), 6 deletions(-) create mode 100644 server/migrations/2024_01_01_000007_create_ledger_gateways_table.php create mode 100644 server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php create mode 100644 server/src/Contracts/GatewayDriverInterface.php create mode 100644 server/src/DTO/GatewayResponse.php create mode 100644 server/src/DTO/PurchaseRequest.php create mode 100644 server/src/DTO/RefundRequest.php create mode 100644 server/src/Events/PaymentFailed.php create mode 100644 server/src/Events/PaymentSucceeded.php create mode 100644 server/src/Events/RefundProcessed.php create mode 100644 server/src/Exceptions/WebhookSignatureException.php create mode 100644 server/src/Gateways/AbstractGatewayDriver.php create mode 100644 server/src/Gateways/CashDriver.php create mode 100644 server/src/Gateways/QPayDriver.php create mode 100644 server/src/Gateways/StripeDriver.php create mode 100644 server/src/Http/Controllers/Internal/v1/GatewayController.php create mode 100644 server/src/Http/Controllers/WebhookController.php create mode 100644 server/src/Http/Resources/v1/Gateway.php create mode 100644 server/src/Listeners/HandleFailedPayment.php create mode 100644 server/src/Listeners/HandleProcessedRefund.php create mode 100644 server/src/Listeners/HandleSuccessfulPayment.php create mode 100644 server/src/Models/Gateway.php create mode 100644 server/src/Models/GatewayTransaction.php create mode 100644 server/src/PaymentGatewayManager.php create mode 100644 server/src/Services/PaymentService.php diff --git a/composer.json b/composer.json index a854615..13ede09 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,10 @@ "php": "^8.0", "fleetbase/core-api": "*", "fleetbase/fleetops-api": "*", + "guzzlehttp/guzzle": "^7.0", "php-http/guzzle7-adapter": "^1.0", - "psr/http-factory-implementation": "*" + "psr/http-factory-implementation": "*", + "stripe/stripe-php": "^13.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.34.1", diff --git a/server/migrations/2024_01_01_000007_create_ledger_gateways_table.php b/server/migrations/2024_01_01_000007_create_ledger_gateways_table.php new file mode 100644 index 0000000..13bc9d9 --- /dev/null +++ b/server/migrations/2024_01_01_000007_create_ledger_gateways_table.php @@ -0,0 +1,56 @@ +bigIncrements('id'); + $table->char('uuid', 36)->unique(); + $table->string('public_id', 191)->nullable()->unique()->index(); + $table->char('company_uuid', 36)->nullable()->index(); + $table->char('created_by_uuid', 36)->nullable()->index(); + + // Gateway identity + $table->string('name'); // User-defined name, e.g. "Main Stripe Account" + $table->string('driver'); // Driver code: 'stripe', 'qpay', 'cash' + $table->text('description')->nullable(); + + // Credentials — stored encrypted at the application layer + $table->text('config')->nullable(); + + // Cached capability list from the driver's getCapabilities() + $table->json('capabilities')->nullable(); + + // Operational flags + $table->boolean('is_sandbox')->default(false)->index(); + $table->string('status', 50)->default('active')->index(); // 'active', 'inactive' + + // URLs + $table->string('return_url')->nullable(); // Redirect URL after off-site payment + $table->string('webhook_url')->nullable(); // Registered webhook URL (informational) + + $table->softDeletes(); + $table->timestamps(); + + // Compound index for common lookups + $table->index(['company_uuid', 'driver', 'status']); + }); + } + + public function down(): void + { + Schema::dropIfExists('ledger_gateways'); + } +}; diff --git a/server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php b/server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php new file mode 100644 index 0000000..89955ec --- /dev/null +++ b/server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php @@ -0,0 +1,72 @@ +bigIncrements('id'); + $table->char('uuid', 36)->unique(); + $table->string('public_id', 191)->nullable()->unique()->index(); + $table->char('company_uuid', 36)->nullable()->index(); + + // Relations + $table->char('gateway_uuid', 36)->nullable()->index(); + $table->char('transaction_uuid', 36)->nullable()->index(); // Links to core-api transactions + + // Gateway reference — the gateway's own unique ID for this event + $table->string('gateway_reference_id')->nullable()->index(); + + // Transaction classification + $table->string('type', 50); // 'purchase', 'refund', 'webhook_event', 'setup_intent' + $table->string('event_type', 100)->nullable(); // Normalized: 'payment.succeeded', 'refund.processed' + + // Monetary values — stored as integers (smallest currency unit) + $table->unsignedBigInteger('amount')->nullable(); + $table->char('currency', 3)->nullable(); + + // Status + $table->string('status', 50)->default('pending')->index(); // 'pending', 'succeeded', 'failed', 'refunded' + $table->text('message')->nullable(); + + // Full raw response from the gateway for debugging + $table->json('raw_response')->nullable(); + + // Idempotency timestamp — set when the event has been fully processed + $table->timestamp('processed_at')->nullable(); + + $table->softDeletes(); + $table->timestamps(); + + // Idempotency index — prevents duplicate processing of the same gateway event + $table->unique(['gateway_reference_id', 'type'], 'unique_gateway_ref_type'); + + // Compound indexes for common queries + $table->index(['company_uuid', 'status']); + $table->index(['gateway_uuid', 'type', 'status']); + }); + } + + public function down(): void + { + Schema::dropIfExists('ledger_gateway_transactions'); + } +}; diff --git a/server/src/Contracts/GatewayDriverInterface.php b/server/src/Contracts/GatewayDriverInterface.php new file mode 100644 index 0000000..6e67e7e --- /dev/null +++ b/server/src/Contracts/GatewayDriverInterface.php @@ -0,0 +1,134 @@ +> + */ + public function getConfigSchema(): array; + + /** + * Initialize the driver with the persisted Gateway model configuration. + * + * Called automatically by the PaymentGatewayManager after resolving the driver. + * The config array contains the decrypted key-value pairs from the Gateway model. + * + * @param array $config Decrypted configuration from the Gateway model + * @param bool $sandbox Whether to operate in sandbox/test mode + * + * @return static + */ + public function initialize(array $config, bool $sandbox = false): static; + + /** + * Initiate a payment charge. + * + * @param PurchaseRequest $request The purchase request DTO + * + * @return GatewayResponse A standardized response object + */ + public function purchase(PurchaseRequest $request): GatewayResponse; + + /** + * Refund a previously captured transaction. + * + * @param RefundRequest $request The refund request DTO + * + * @return GatewayResponse A standardized response object + */ + public function refund(RefundRequest $request): GatewayResponse; + + /** + * Verify and parse an incoming webhook request from this gateway. + * + * This method MUST verify the webhook signature before processing. + * It returns a normalized GatewayResponse containing the event type + * and relevant data. The WebhookController handles idempotency and + * event dispatching after this method returns. + * + * @param Request $request The incoming HTTP request + * + * @return GatewayResponse A standardized response with event type and data + * + * @throws \Fleetbase\Ledger\Exceptions\WebhookSignatureException if signature is invalid + */ + public function handleWebhook(Request $request): GatewayResponse; + + /** + * Create a stored payment method (tokenize a card or bank account). + * + * Returns a GatewayResponse containing the token reference in + * $response->gatewayTransactionId. This token can be stored and + * used in future PurchaseRequest::$paymentMethodToken. + * + * This method is optional. The default implementation in AbstractGatewayDriver + * throws a RuntimeException. Only implement if 'tokenization' is in getCapabilities(). + * + * @param array $data Gateway-specific tokenization data + * + * @return GatewayResponse + */ + public function createPaymentMethod(array $data): GatewayResponse; +} diff --git a/server/src/DTO/GatewayResponse.php b/server/src/DTO/GatewayResponse.php new file mode 100644 index 0000000..ce76bfd --- /dev/null +++ b/server/src/DTO/GatewayResponse.php @@ -0,0 +1,155 @@ +successful; + } + + /** + * Convenience method to check if the operation failed. + */ + public function isFailed(): bool + { + return !$this->successful; + } + + /** + * Convenience method to check if the payment is pending (e.g., awaiting webhook confirmation). + */ + public function isPending(): bool + { + return $this->status === self::STATUS_PENDING; + } + + /** + * Create a successful response. + */ + public static function success( + string $gatewayTransactionId, + string $eventType = self::EVENT_PAYMENT_SUCCEEDED, + ?string $message = null, + ?int $amount = null, + ?string $currency = null, + array $rawResponse = [], + array $data = [] + ): self { + return new self( + successful: true, + gatewayTransactionId: $gatewayTransactionId, + status: self::STATUS_SUCCEEDED, + eventType: $eventType, + message: $message, + amount: $amount, + currency: $currency, + rawResponse: $rawResponse, + data: $data, + ); + } + + /** + * Create a pending response (payment initiated but not yet confirmed). + */ + public static function pending( + string $gatewayTransactionId, + string $eventType = self::EVENT_PAYMENT_PENDING, + ?string $message = null, + array $rawResponse = [], + array $data = [] + ): self { + return new self( + successful: true, + gatewayTransactionId: $gatewayTransactionId, + status: self::STATUS_PENDING, + eventType: $eventType, + message: $message, + rawResponse: $rawResponse, + data: $data, + ); + } + + /** + * Create a failed response. + */ + public static function failure( + string $gatewayTransactionId = '', + string $eventType = self::EVENT_PAYMENT_FAILED, + ?string $message = null, + ?string $errorCode = null, + array $rawResponse = [] + ): self { + return new self( + successful: false, + gatewayTransactionId: $gatewayTransactionId, + status: self::STATUS_FAILED, + eventType: $eventType, + message: $message, + errorCode: $errorCode, + rawResponse: $rawResponse, + ); + } +} diff --git a/server/src/DTO/PurchaseRequest.php b/server/src/DTO/PurchaseRequest.php new file mode 100644 index 0000000..bfbf1d0 --- /dev/null +++ b/server/src/DTO/PurchaseRequest.php @@ -0,0 +1,53 @@ +amount / (10 ** $decimalPlaces), $decimalPlaces); + } +} diff --git a/server/src/DTO/RefundRequest.php b/server/src/DTO/RefundRequest.php new file mode 100644 index 0000000..99f4bc8 --- /dev/null +++ b/server/src/DTO/RefundRequest.php @@ -0,0 +1,32 @@ + + */ + protected array $config = []; + + /** + * Whether this driver is operating in sandbox/test mode. + */ + protected bool $sandbox = false; + + /** + * Initialize the driver with configuration from the persisted Gateway model. + * + * @param array $config Decrypted key-value configuration + * @param bool $sandbox Whether to use sandbox/test mode + * + * @return static + */ + public function initialize(array $config, bool $sandbox = false): static + { + $this->config = $config; + $this->sandbox = $sandbox; + + return $this; + } + + /** + * Retrieve a configuration value by key. + * + * @param string $key The config key + * @param mixed $default Default value if key is not set + * + * @return mixed + */ + protected function config(string $key, mixed $default = null): mixed + { + return $this->config[$key] ?? $default; + } + + /** + * Check whether the driver is in sandbox mode. + */ + protected function isSandbox(): bool + { + return $this->sandbox; + } + + /** + * Log an error message prefixed with the gateway code. + * + * @param string $message The error message + * @param array $context Additional context for the log entry + */ + protected function logError(string $message, array $context = []): void + { + Log::channel('ledger')->error("[{$this->getCode()}] {$message}", $context); + } + + /** + * Log an info message prefixed with the gateway code. + * + * @param string $message The info message + * @param array $context Additional context for the log entry + */ + protected function logInfo(string $message, array $context = []): void + { + Log::channel('ledger')->info("[{$this->getCode()}] {$message}", $context); + } + + /** + * Default no-op implementation of createPaymentMethod. + * + * Drivers that support tokenization should override this method. + * Drivers that do not support tokenization will throw a RuntimeException + * if this method is called, which serves as a clear developer error signal. + * + * @param array $data Gateway-specific tokenization data + * + * @return GatewayResponse + * + * @throws \RuntimeException + */ + public function createPaymentMethod(array $data): GatewayResponse + { + throw new \RuntimeException( + sprintf( + 'Gateway [%s] does not support payment method tokenization. ' . + 'Check getCapabilities() before calling createPaymentMethod().', + $this->getCode() + ) + ); + } + + /** + * Default no-op implementation of handleWebhook. + * + * Drivers that support webhooks should override this method. + * + * @param Request $request The incoming HTTP request + * + * @return GatewayResponse + */ + public function handleWebhook(Request $request): GatewayResponse + { + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_UNKNOWN, + message: sprintf('Gateway [%s] does not support webhooks.', $this->getCode()), + ); + } + + /** + * Check if this driver has a specific capability. + * + * @param string $capability The capability to check (e.g., 'refund', 'tokenization') + * + * @return bool + */ + public function hasCapability(string $capability): bool + { + return in_array($capability, $this->getCapabilities(), true); + } +} diff --git a/server/src/Gateways/CashDriver.php b/server/src/Gateways/CashDriver.php new file mode 100644 index 0000000..2b1b0f4 --- /dev/null +++ b/server/src/Gateways/CashDriver.php @@ -0,0 +1,137 @@ + 'label', + 'label' => 'Display Label', + 'type' => 'text', + 'required' => false, + 'hint' => 'Optional label shown to customers, e.g. "Cash on Delivery" or "Pay at Counter".', + ], + [ + 'key' => 'instructions', + 'label' => 'Payment Instructions', + 'type' => 'textarea', + 'required' => false, + 'hint' => 'Instructions shown to customers after selecting this payment method.', + ], + ]; + } + + /** + * {@inheritdoc} + * + * Immediately marks the purchase as succeeded. + * No external API call is made. + */ + public function purchase(PurchaseRequest $request): GatewayResponse + { + // Generate a local reference ID for traceability + $referenceId = 'cash_' . Str::uuid()->toString(); + + $this->logInfo('Cash purchase recorded', [ + 'reference_id' => $referenceId, + 'amount' => $request->amount, + 'currency' => $request->currency, + 'description' => $request->description, + ]); + + return GatewayResponse::success( + gatewayTransactionId: $referenceId, + eventType: GatewayResponse::EVENT_PAYMENT_SUCCEEDED, + message: $this->config('instructions') ?? 'Cash payment recorded. Collect payment manually.', + amount: $request->amount, + currency: $request->currency, + data: [ + 'reference_id' => $referenceId, + 'label' => $this->config('label') ?? 'Cash / Manual', + ], + ); + } + + /** + * {@inheritdoc} + * + * Records a manual refund. No external API call is made. + */ + public function refund(RefundRequest $request): GatewayResponse + { + $refundReferenceId = 'cash_refund_' . Str::uuid()->toString(); + + $this->logInfo('Cash refund recorded', [ + 'original_reference_id' => $request->gatewayTransactionId, + 'refund_reference_id' => $refundReferenceId, + 'amount' => $request->amount, + 'reason' => $request->reason, + ]); + + return GatewayResponse::success( + gatewayTransactionId: $refundReferenceId, + eventType: GatewayResponse::EVENT_REFUND_PROCESSED, + message: 'Cash refund recorded. Return payment to customer manually.', + amount: $request->amount, + currency: $request->currency, + data: [ + 'original_reference_id' => $request->gatewayTransactionId, + 'refund_reference_id' => $refundReferenceId, + ], + ); + } +} diff --git a/server/src/Gateways/QPayDriver.php b/server/src/Gateways/QPayDriver.php new file mode 100644 index 0000000..cef2eb0 --- /dev/null +++ b/server/src/Gateways/QPayDriver.php @@ -0,0 +1,580 @@ + 'username', + 'label' => 'QPay Username', + 'type' => 'text', + 'required' => true, + 'hint' => 'Your QPay merchant username.', + ], + [ + 'key' => 'password', + 'label' => 'QPay Password', + 'type' => 'password', + 'required' => true, + 'hint' => 'Your QPay merchant password.', + ], + [ + 'key' => 'invoice_code', + 'label' => 'Invoice Code', + 'type' => 'text', + 'required' => true, + 'hint' => 'Your QPay invoice code from the merchant dashboard.', + ], + ]; + } + + /** + * {@inheritdoc} + * + * Initializes the Guzzle client with QPay credentials. + */ + public function initialize(array $config, bool $sandbox = false): static + { + parent::initialize($config, $sandbox); + + $baseUri = $sandbox ? self::HOST_SANDBOX : self::HOST_PRODUCTION; + + $this->client = new Client([ + 'base_uri' => $baseUri, + 'auth' => [ + $this->config('username'), + $this->config('password'), + ], + 'headers' => [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + ], + 'http_errors' => false, + ]); + + return $this; + } + + /** + * {@inheritdoc} + * + * Creates a QPay invoice and returns the payment deep-link URLs. + * + * QPay uses an invoice-based flow. The payment is not immediately confirmed — + * the response will have status 'pending'. The customer pays via the QPay app + * using the URLs in $response->data['urls']. Payment confirmation arrives via + * webhook callback or can be polled via checkPaymentStatus(). + */ + public function purchase(PurchaseRequest $request): GatewayResponse + { + try { + // Authenticate and get bearer token + $this->authenticate(); + + $invoiceCode = $this->config('invoice_code'); + $callbackUrl = $request->returnUrl ?? $this->buildCallbackUrl($request); + $senderInvoiceNo = $request->invoiceUuid + ? Str::substr($request->invoiceUuid, 0, 32) + : Str::uuid()->toString(); + + $params = [ + 'invoice_code' => $invoiceCode, + 'sender_invoice_no' => $senderInvoiceNo, + 'invoice_receiver_code' => 'terminal', + 'invoice_description' => $request->description, + 'amount' => $request->amount, + 'callback_url' => $callbackUrl, + ]; + + $response = $this->post('invoice', $params); + + if (!$response || !isset($response->invoice_id)) { + $this->logError('QPay invoice creation failed — no invoice_id in response', [ + 'response' => (array) $response, + ]); + + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: 'QPay invoice creation failed.', + rawResponse: (array) $response, + ); + } + + $this->logInfo('QPay invoice created', [ + 'invoice_id' => $response->invoice_id, + 'amount' => $request->amount, + ]); + + // Build payment URL list for the frontend + $urls = []; + if (isset($response->urls) && is_array($response->urls)) { + foreach ($response->urls as $urlEntry) { + $urls[] = [ + 'name' => $urlEntry->name ?? '', + 'description' => $urlEntry->description ?? '', + 'logo' => $urlEntry->logo ?? '', + 'link' => $urlEntry->link ?? '', + ]; + } + } + + return GatewayResponse::pending( + gatewayTransactionId: $response->invoice_id, + eventType: GatewayResponse::EVENT_PAYMENT_PENDING, + message: 'QPay invoice created. Awaiting customer payment.', + rawResponse: (array) $response, + data: [ + 'invoice_id' => $response->invoice_id, + 'qr_image' => $response->qr_image ?? null, + 'qr_text' => $response->qr_text ?? null, + 'urls' => $urls, + ], + ); + } catch (\Exception $e) { + $this->logError('QPay purchase exception', ['error' => $e->getMessage()]); + + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: $e->getMessage(), + rawResponse: ['error' => $e->getMessage()], + ); + } + } + + /** + * {@inheritdoc} + * + * Refunds a QPay payment by invoice ID. + */ + public function refund(RefundRequest $request): GatewayResponse + { + try { + $this->authenticate(); + + $params = [ + 'callback_url' => url('/ledger/webhooks/qpay'), + ]; + + $response = $this->delete( + 'payment/refund/' . $request->gatewayTransactionId, + $params + ); + + $successful = $response && !isset($response->error); + + $this->logInfo('QPay refund attempted', [ + 'invoice_id' => $request->gatewayTransactionId, + 'successful' => $successful, + ]); + + return new GatewayResponse( + successful: $successful, + gatewayTransactionId: $request->gatewayTransactionId, + status: $successful ? GatewayResponse::STATUS_REFUNDED : GatewayResponse::STATUS_FAILED, + eventType: $successful ? GatewayResponse::EVENT_REFUND_PROCESSED : GatewayResponse::EVENT_REFUND_FAILED, + message: $successful ? 'Refund processed.' : 'Refund failed.', + rawResponse: (array) $response, + ); + } catch (\Exception $e) { + $this->logError('QPay refund exception', [ + 'error' => $e->getMessage(), + 'invoice_id' => $request->gatewayTransactionId, + ]); + + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_REFUND_FAILED, + message: $e->getMessage(), + rawResponse: ['error' => $e->getMessage()], + ); + } + } + + /** + * {@inheritdoc} + * + * Handles QPay payment callback (webhook). + * + * QPay sends a POST callback with a payment_id when a payment is completed. + * We verify the payment by calling the payment check endpoint. + * + * QPay does not use HMAC signature verification — instead, we verify + * by re-querying the QPay API with the payment ID. + */ + public function handleWebhook(Request $request): GatewayResponse + { + $paymentId = $request->input('payment_id'); + $invoiceId = $request->input('qpay_payment_id') ?? $request->input('invoice_id'); + + if (!$paymentId && !$invoiceId) { + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_UNKNOWN, + message: 'QPay webhook received without payment_id or invoice_id.', + rawResponse: $request->all(), + ); + } + + try { + $this->authenticate(); + + // Verify payment by querying QPay API + $referenceId = $invoiceId ?? $paymentId; + $checkResult = $this->checkPaymentStatus($referenceId); + + if (!$checkResult) { + return GatewayResponse::failure( + gatewayTransactionId: $referenceId, + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: 'QPay payment verification failed.', + rawResponse: $request->all(), + ); + } + + $rows = $checkResult->rows ?? []; + $payment = count($rows) > 0 ? $rows[0] : null; + + if (!$payment) { + return GatewayResponse::failure( + gatewayTransactionId: $referenceId, + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: 'QPay payment not found.', + rawResponse: (array) $checkResult, + ); + } + + $paymentStatus = strtolower($payment->payment_status ?? ''); + $isSuccessful = in_array($paymentStatus, ['paid', 'success', 'complete'], true); + + $this->logInfo('QPay webhook processed', [ + 'invoice_id' => $referenceId, + 'payment_status' => $paymentStatus, + 'successful' => $isSuccessful, + ]); + + return new GatewayResponse( + successful: $isSuccessful, + gatewayTransactionId: $referenceId, + status: $isSuccessful ? GatewayResponse::STATUS_SUCCEEDED : GatewayResponse::STATUS_FAILED, + eventType: $isSuccessful ? GatewayResponse::EVENT_PAYMENT_SUCCEEDED : GatewayResponse::EVENT_PAYMENT_FAILED, + message: $isSuccessful ? 'QPay payment confirmed.' : 'QPay payment not confirmed.', + rawResponse: array_merge($request->all(), ['check_result' => (array) $checkResult]), + data: [ + 'invoice_id' => $referenceId, + 'payment_id' => $payment->payment_id ?? null, + 'payment_status' => $paymentStatus, + ], + ); + } catch (\Exception $e) { + $this->logError('QPay webhook exception', ['error' => $e->getMessage()]); + + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: $e->getMessage(), + rawResponse: array_merge($request->all(), ['error' => $e->getMessage()]), + ); + } + } + + // ------------------------------------------------------------------------- + // QPay API Methods + // ------------------------------------------------------------------------- + + /** + * Authenticate with QPay and set the bearer token on the client. + * + * @throws \RuntimeException if authentication fails + */ + public function authenticate(): void + { + if ($this->accessToken) { + return; // Already authenticated + } + + $response = $this->post('auth/token', []); + + if (!$response || !isset($response->access_token)) { + throw new \RuntimeException('QPay authentication failed: no access_token in response.'); + } + + $this->accessToken = $response->access_token; + + // Rebuild client with bearer token + $baseUri = $this->sandbox ? self::HOST_SANDBOX : self::HOST_PRODUCTION; + $this->client = new Client([ + 'base_uri' => $baseUri, + 'headers' => [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $this->accessToken, + ], + 'http_errors' => false, + ]); + } + + /** + * Check the payment status for a QPay invoice. + * + * @param string $invoiceId The QPay invoice ID + * + * @return object|null The payment check response + */ + public function checkPaymentStatus(string $invoiceId): ?object + { + $params = [ + 'object_type' => 'INVOICE', + 'object_id' => $invoiceId, + ]; + + return $this->post('payment/check', $params); + } + + /** + * Create a QPay eBarimt invoice (Mongolian electronic receipt). + * + * @param int $amount Amount in smallest currency unit + * @param string $invoiceCode QPay invoice code + * @param string $senderInvoiceNo Unique sender invoice number + * @param array $lines Invoice line items with classification codes + * @param array $invoiceReceiverData Receiver details + * @param string $taxType Tax type code (default: '1') + * @param string $callbackUrl Callback URL for payment notifications + * + * @return GatewayResponse + */ + public function createEbarimtInvoice( + int $amount, + string $invoiceCode, + string $senderInvoiceNo, + array $lines, + array $invoiceReceiverData = [], + string $taxType = '1', + string $callbackUrl = '' + ): GatewayResponse { + try { + $this->authenticate(); + + $params = array_filter([ + 'invoice_code' => $invoiceCode, + 'sender_invoice_no' => $senderInvoiceNo, + 'invoice_receiver_code' => 'terminal', + 'invoice_receiver_data' => $invoiceReceiverData, + 'invoice_description' => 'eBarimt Invoice', + 'amount' => $amount, + 'tax_type' => $taxType, + 'lines' => $lines, + 'callback_url' => $callbackUrl ?: url('/ledger/webhooks/qpay'), + ]); + + $response = $this->post('invoice', $params); + + if (!$response || !isset($response->invoice_id)) { + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: 'QPay eBarimt invoice creation failed.', + rawResponse: (array) $response, + ); + } + + return GatewayResponse::pending( + gatewayTransactionId: $response->invoice_id, + message: 'QPay eBarimt invoice created.', + rawResponse: (array) $response, + data: [ + 'invoice_id' => $response->invoice_id, + 'qr_image' => $response->qr_image ?? null, + 'qr_text' => $response->qr_text ?? null, + 'urls' => $response->urls ?? [], + ], + ); + } catch (\Exception $e) { + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: $e->getMessage(), + rawResponse: ['error' => $e->getMessage()], + ); + } + } + + // ------------------------------------------------------------------------- + // HTTP Helpers + // ------------------------------------------------------------------------- + + /** + * Make a POST request to the QPay API. + * + * @param string $path API endpoint path + * @param array $params Request body parameters + * + * @return object|null Decoded JSON response + */ + protected function post(string $path, array $params): ?object + { + try { + $response = $this->client->post($path, ['json' => $params]); + return json_decode($response->getBody()->getContents()); + } catch (GuzzleException $e) { + $this->logError("POST {$path} failed", ['error' => $e->getMessage()]); + return null; + } + } + + /** + * Make a GET request to the QPay API. + * + * @param string $path API endpoint path + * + * @return object|null Decoded JSON response + */ + protected function get(string $path): ?object + { + try { + $response = $this->client->get($path); + return json_decode($response->getBody()->getContents()); + } catch (GuzzleException $e) { + $this->logError("GET {$path} failed", ['error' => $e->getMessage()]); + return null; + } + } + + /** + * Make a DELETE request to the QPay API. + * + * @param string $path API endpoint path + * @param array $params Request body parameters + * + * @return object|null Decoded JSON response + */ + protected function delete(string $path, array $params = []): ?object + { + try { + $response = $this->client->delete($path, ['json' => $params]); + return json_decode($response->getBody()->getContents()); + } catch (GuzzleException $e) { + $this->logError("DELETE {$path} failed", ['error' => $e->getMessage()]); + return null; + } + } + + /** + * Build the default callback URL for QPay payment notifications. + * + * @param PurchaseRequest $request + * + * @return string + */ + private function buildCallbackUrl(PurchaseRequest $request): string + { + $base = url('/ledger/webhooks/qpay'); + + if ($request->invoiceUuid) { + return $base . '?invoice_uuid=' . $request->invoiceUuid; + } + + return $base; + } +} diff --git a/server/src/Gateways/StripeDriver.php b/server/src/Gateways/StripeDriver.php new file mode 100644 index 0000000..38d1e65 --- /dev/null +++ b/server/src/Gateways/StripeDriver.php @@ -0,0 +1,423 @@ + 'publishable_key', + 'label' => 'Publishable Key', + 'type' => 'text', + 'required' => true, + 'hint' => 'Starts with pk_live_ or pk_test_. Used on the frontend.', + ], + [ + 'key' => 'secret_key', + 'label' => 'Secret Key', + 'type' => 'password', + 'required' => true, + 'hint' => 'Starts with sk_live_ or sk_test_. Never expose this publicly.', + ], + [ + 'key' => 'webhook_secret', + 'label' => 'Webhook Signing Secret', + 'type' => 'password', + 'required' => false, + 'hint' => 'Starts with whsec_. Found in your Stripe Dashboard under Webhooks.', + ], + ]; + } + + /** + * {@inheritdoc} + * + * Initializes the Stripe SDK with the configured secret key. + */ + public function initialize(array $config, bool $sandbox = false): static + { + parent::initialize($config, $sandbox); + + $secretKey = $this->config('secret_key'); + if ($secretKey) { + Stripe::setApiKey($secretKey); + $this->client = new StripeClient($secretKey); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * Creates a Stripe PaymentIntent and confirms it. + * + * For client-side confirmation flows (e.g., Stripe Elements), the PaymentIntent + * is created and returned with status 'requires_confirmation'. The frontend + * then calls stripe.confirmPayment() using the client_secret from $response->data. + * + * For server-side confirmation (token billing), the PaymentIntent is confirmed + * immediately using the stored payment method token. + */ + public function purchase(PurchaseRequest $request): GatewayResponse + { + try { + $params = [ + 'amount' => $request->amount, + 'currency' => strtolower($request->currency), + 'description' => $request->description, + 'metadata' => array_merge($request->metadata, array_filter([ + 'invoice_uuid' => $request->invoiceUuid, + 'order_uuid' => $request->orderUuid, + ])), + ]; + + // If a payment method token is provided, confirm immediately (server-side) + if ($request->paymentMethodToken) { + $params['payment_method'] = $request->paymentMethodToken; + $params['confirm'] = true; + $params['return_url'] = $request->returnUrl ?? url('/'); + $params['off_session'] = true; + $params['error_on_requires_action'] = true; + } + + // Attach customer if provided + if ($request->customerId) { + $params['customer'] = $request->customerId; + } + + $paymentIntent = PaymentIntent::create($params); + + // Determine status + $status = $paymentIntent->status === 'succeeded' + ? GatewayResponse::STATUS_SUCCEEDED + : GatewayResponse::STATUS_PENDING; + $eventType = $paymentIntent->status === 'succeeded' + ? GatewayResponse::EVENT_PAYMENT_SUCCEEDED + : GatewayResponse::EVENT_PAYMENT_PENDING; + + $this->logInfo('PaymentIntent created', [ + 'id' => $paymentIntent->id, + 'status' => $paymentIntent->status, + 'amount' => $request->amount, + ]); + + return new GatewayResponse( + successful: true, + gatewayTransactionId: $paymentIntent->id, + status: $status, + eventType: $eventType, + message: 'PaymentIntent created successfully.', + amount: $paymentIntent->amount, + currency: strtoupper($paymentIntent->currency), + rawResponse: $paymentIntent->toArray(), + data: [ + 'client_secret' => $paymentIntent->client_secret, + 'payment_intent_id' => $paymentIntent->id, + 'status' => $paymentIntent->status, + 'publishable_key' => $this->config('publishable_key'), + ], + ); + } catch (ApiErrorException $e) { + $this->logError('PaymentIntent creation failed', [ + 'error' => $e->getMessage(), + 'code' => $e->getStripeCode(), + 'amount' => $request->amount, + ]); + + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: $e->getMessage(), + errorCode: $e->getStripeCode(), + rawResponse: ['error' => $e->getMessage()], + ); + } + } + + /** + * {@inheritdoc} + * + * Refunds a Stripe charge or PaymentIntent. + */ + public function refund(RefundRequest $request): GatewayResponse + { + try { + $params = [ + 'amount' => $request->amount, + ]; + + // Stripe accepts either a charge ID (ch_xxx) or a PaymentIntent ID (pi_xxx) + if (str_starts_with($request->gatewayTransactionId, 'pi_')) { + $params['payment_intent'] = $request->gatewayTransactionId; + } else { + $params['charge'] = $request->gatewayTransactionId; + } + + if ($request->reason) { + $params['reason'] = $request->reason; + } + + if (!empty($request->metadata)) { + $params['metadata'] = $request->metadata; + } + + $refund = Refund::create($params); + + $this->logInfo('Refund created', [ + 'id' => $refund->id, + 'status' => $refund->status, + 'gateway_transaction_id' => $request->gatewayTransactionId, + 'amount' => $request->amount, + ]); + + $successful = in_array($refund->status, ['succeeded', 'pending'], true); + + return new GatewayResponse( + successful: $successful, + gatewayTransactionId: $refund->id, + status: $successful ? GatewayResponse::STATUS_REFUNDED : GatewayResponse::STATUS_FAILED, + eventType: $successful ? GatewayResponse::EVENT_REFUND_PROCESSED : GatewayResponse::EVENT_REFUND_FAILED, + message: $successful ? 'Refund processed successfully.' : 'Refund failed.', + amount: $refund->amount, + currency: strtoupper($refund->currency), + rawResponse: $refund->toArray(), + ); + } catch (ApiErrorException $e) { + $this->logError('Refund failed', [ + 'error' => $e->getMessage(), + 'gateway_transaction_id' => $request->gatewayTransactionId, + ]); + + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_REFUND_FAILED, + message: $e->getMessage(), + errorCode: $e->getStripeCode(), + rawResponse: ['error' => $e->getMessage()], + ); + } + } + + /** + * {@inheritdoc} + * + * Verifies the Stripe-Signature header and parses the webhook event. + * Maps Stripe event types to normalized GatewayResponse event types. + * + * @throws WebhookSignatureException if the signature is invalid + */ + public function handleWebhook(Request $request): GatewayResponse + { + $webhookSecret = $this->config('webhook_secret'); + $payload = $request->getContent(); + $sigHeader = $request->header('Stripe-Signature'); + + // Verify signature if a webhook secret is configured + if ($webhookSecret) { + try { + $event = Webhook::constructEvent($payload, $sigHeader, $webhookSecret); + } catch (SignatureVerificationException $e) { + throw new WebhookSignatureException('stripe', $e->getMessage()); + } + } else { + // No webhook secret configured — parse without verification (not recommended for production) + $this->logError('Webhook received without signature verification. Configure webhook_secret.'); + $event = \Stripe\Event::constructFrom(json_decode($payload, true)); + } + + // Extract the primary object from the event + $object = $event->data->object; + + // Normalize the Stripe event type to our standard event types + [$normalizedEvent, $status] = $this->normalizeStripeEvent($event->type, $object); + + $gatewayTransactionId = $object->id ?? $event->id; + $amount = $object->amount ?? $object->amount_received ?? null; + $currency = isset($object->currency) ? strtoupper($object->currency) : null; + + $this->logInfo('Webhook received', [ + 'stripe_event' => $event->type, + 'normalized_event' => $normalizedEvent, + 'object_id' => $gatewayTransactionId, + ]); + + return new GatewayResponse( + successful: in_array($normalizedEvent, [ + GatewayResponse::EVENT_PAYMENT_SUCCEEDED, + GatewayResponse::EVENT_REFUND_PROCESSED, + GatewayResponse::EVENT_SETUP_SUCCEEDED, + ], true), + gatewayTransactionId: $gatewayTransactionId, + status: $status, + eventType: $normalizedEvent, + message: "Stripe event: {$event->type}", + amount: $amount, + currency: $currency, + rawResponse: json_decode($payload, true), + data: [ + 'stripe_event_id' => $event->id, + 'stripe_event_type' => $event->type, + 'object' => $object->toArray(), + ], + ); + } + + /** + * {@inheritdoc} + * + * Creates a Stripe SetupIntent for saving a payment method without charging. + * Returns the SetupIntent client_secret in $response->data for frontend confirmation. + */ + public function createPaymentMethod(array $data): GatewayResponse + { + try { + $params = array_filter([ + 'customer' => $data['customer_id'] ?? null, + 'payment_method_types' => ['card'], + 'usage' => 'off_session', + ]); + + $setupIntent = SetupIntent::create($params); + + $this->logInfo('SetupIntent created', ['id' => $setupIntent->id]); + + return GatewayResponse::success( + gatewayTransactionId: $setupIntent->id, + eventType: GatewayResponse::EVENT_SETUP_SUCCEEDED, + message: 'SetupIntent created. Use client_secret on the frontend.', + rawResponse: $setupIntent->toArray(), + data: [ + 'client_secret' => $setupIntent->client_secret, + 'setup_intent_id' => $setupIntent->id, + 'publishable_key' => $this->config('publishable_key'), + ], + ); + } catch (ApiErrorException $e) { + $this->logError('SetupIntent creation failed', ['error' => $e->getMessage()]); + + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: $e->getMessage(), + errorCode: $e->getStripeCode(), + rawResponse: ['error' => $e->getMessage()], + ); + } + } + + // ------------------------------------------------------------------------- + // Private Helpers + // ------------------------------------------------------------------------- + + /** + * Map a Stripe event type to a normalized event type and status. + * + * @param string $stripeEventType The raw Stripe event type (e.g., 'payment_intent.succeeded') + * @param mixed $object The Stripe event data object + * + * @return array{0: string, 1: string} [normalizedEventType, status] + */ + private function normalizeStripeEvent(string $stripeEventType, mixed $object): array + { + return match ($stripeEventType) { + 'payment_intent.succeeded' => [GatewayResponse::EVENT_PAYMENT_SUCCEEDED, GatewayResponse::STATUS_SUCCEEDED], + 'payment_intent.payment_failed' => [GatewayResponse::EVENT_PAYMENT_FAILED, GatewayResponse::STATUS_FAILED], + 'payment_intent.created', + 'payment_intent.processing' => [GatewayResponse::EVENT_PAYMENT_PENDING, GatewayResponse::STATUS_PENDING], + 'charge.refunded' => [GatewayResponse::EVENT_REFUND_PROCESSED, GatewayResponse::STATUS_REFUNDED], + 'charge.refund.updated' => $this->resolveRefundUpdate($object), + 'setup_intent.succeeded' => [GatewayResponse::EVENT_SETUP_SUCCEEDED, GatewayResponse::STATUS_SUCCEEDED], + 'charge.dispute.created' => [GatewayResponse::EVENT_CHARGEBACK, GatewayResponse::STATUS_FAILED], + default => [GatewayResponse::EVENT_UNKNOWN, GatewayResponse::STATUS_PENDING], + }; + } + + /** + * Resolve the normalized event for a refund update based on its status. + * + * @param mixed $object The Stripe refund object + * + * @return array{0: string, 1: string} + */ + private function resolveRefundUpdate(mixed $object): array + { + return match ($object->status ?? '') { + 'succeeded' => [GatewayResponse::EVENT_REFUND_PROCESSED, GatewayResponse::STATUS_REFUNDED], + 'failed' => [GatewayResponse::EVENT_REFUND_FAILED, GatewayResponse::STATUS_FAILED], + default => [GatewayResponse::EVENT_UNKNOWN, GatewayResponse::STATUS_PENDING], + }; + } +} diff --git a/server/src/Http/Controllers/Internal/v1/GatewayController.php b/server/src/Http/Controllers/Internal/v1/GatewayController.php new file mode 100644 index 0000000..93efd97 --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/GatewayController.php @@ -0,0 +1,383 @@ +has('driver')) { + $query->where('driver', $request->input('driver')); + } + + if ($request->has('status')) { + $query->where('status', $request->input('status')); + } + + $gateways = $query->orderBy('created_at', 'desc')->get(); + + return response()->json([ + 'status' => 'ok', + 'gateways' => GatewayResource::collection($gateways), + ]); + } + + /** + * Create a new payment gateway configuration. + * + * @param Request $request + * + * @return JsonResponse + */ + public function store(Request $request): JsonResponse + { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:191', + 'driver' => ['required', 'string', Rule::in(['stripe', 'qpay', 'cash'])], + 'config' => 'required|array', + 'is_sandbox' => 'boolean', + 'status' => ['string', Rule::in(['active', 'inactive'])], + 'return_url' => 'nullable|url', + ]); + + if ($validator->fails()) { + return response()->json([ + 'error' => 'Validation failed.', + 'details' => $validator->errors(), + ], 422); + } + + $companyUuid = session('company'); + $userUuid = session('user'); + + // Resolve capabilities from the driver manifest + $manifest = collect($this->paymentService->getDriverManifest()); + $driverInfo = $manifest->firstWhere('code', $request->input('driver')); + $capabilities = $driverInfo['capabilities'] ?? []; + + $gateway = Gateway::create([ + 'company_uuid' => $companyUuid, + 'created_by_uuid' => $userUuid, + 'name' => $request->input('name'), + 'driver' => $request->input('driver'), + 'description' => $request->input('description'), + 'config' => $request->input('config'), // Encrypted at rest by model cast + 'capabilities' => $capabilities, + 'is_sandbox' => $request->boolean('is_sandbox', false), + 'status' => $request->input('status', 'active'), + 'return_url' => $request->input('return_url'), + 'webhook_url' => url('/ledger/webhooks/' . $request->input('driver')), + ]); + + return response()->json([ + 'status' => 'ok', + 'gateway' => new GatewayResource($gateway), + ], 201); + } + + /** + * Get a single gateway by UUID or public_id. + * + * @param string $id + * + * @return JsonResponse + */ + public function show(string $id): JsonResponse + { + $gateway = Gateway::where('company_uuid', session('company')) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) + ->firstOrFail(); + + return response()->json([ + 'status' => 'ok', + 'gateway' => new GatewayResource($gateway), + ]); + } + + /** + * Update a gateway configuration. + * + * @param Request $request + * @param string $id + * + * @return JsonResponse + */ + public function update(Request $request, string $id): JsonResponse + { + $gateway = Gateway::where('company_uuid', session('company')) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) + ->firstOrFail(); + + $validator = Validator::make($request->all(), [ + 'name' => 'string|max:191', + 'config' => 'array', + 'is_sandbox' => 'boolean', + 'status' => ['string', Rule::in(['active', 'inactive'])], + 'return_url' => 'nullable|url', + ]); + + if ($validator->fails()) { + return response()->json([ + 'error' => 'Validation failed.', + 'details' => $validator->errors(), + ], 422); + } + + $updateData = array_filter([ + 'name' => $request->input('name'), + 'description' => $request->input('description'), + 'is_sandbox' => $request->has('is_sandbox') ? $request->boolean('is_sandbox') : null, + 'status' => $request->input('status'), + 'return_url' => $request->input('return_url'), + ], fn ($v) => $v !== null); + + // Only update config if explicitly provided (avoid overwriting credentials with null) + if ($request->has('config') && is_array($request->input('config'))) { + $updateData['config'] = array_merge( + $gateway->decryptedConfig(), + $request->input('config') + ); + } + + $gateway->update($updateData); + + return response()->json([ + 'status' => 'ok', + 'gateway' => new GatewayResource($gateway->fresh()), + ]); + } + + /** + * Delete a gateway configuration. + * + * @param string $id + * + * @return JsonResponse + */ + public function destroy(string $id): JsonResponse + { + $gateway = Gateway::where('company_uuid', session('company')) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) + ->firstOrFail(); + + $gateway->delete(); + + return response()->json(['status' => 'ok', 'message' => 'Gateway deleted.']); + } + + /** + * Return the full driver manifest. + * + * This endpoint is used by the frontend to dynamically render the + * "Add Gateway" configuration form. It returns each registered driver's + * code, name, capabilities, and config schema. + * + * @return JsonResponse + */ + public function drivers(): JsonResponse + { + return response()->json([ + 'status' => 'ok', + 'drivers' => $this->paymentService->getDriverManifest(), + ]); + } + + /** + * Initiate a payment charge through a gateway. + * + * @param Request $request + * @param string $id Gateway UUID or public_id + * + * @return JsonResponse + */ + public function charge(Request $request, string $id): JsonResponse + { + $validator = Validator::make($request->all(), [ + 'amount' => 'required|integer|min:1', + 'currency' => 'required|string|size:3', + 'description' => 'required|string|max:500', + ]); + + if ($validator->fails()) { + return response()->json([ + 'error' => 'Validation failed.', + 'details' => $validator->errors(), + ], 422); + } + + $purchaseRequest = new PurchaseRequest( + amount: $request->integer('amount'), + currency: strtoupper($request->input('currency')), + description: $request->input('description'), + paymentMethodToken: $request->input('payment_method_token'), + customerId: $request->input('customer_id'), + customerEmail: $request->input('customer_email'), + invoiceUuid: $request->input('invoice_uuid'), + orderUuid: $request->input('order_uuid'), + returnUrl: $request->input('return_url'), + cancelUrl: $request->input('cancel_url'), + metadata: $request->input('metadata', []), + ); + + $response = $this->paymentService->charge($id, $purchaseRequest); + + return response()->json([ + 'status' => $response->status, + 'successful' => $response->successful, + 'gateway_transaction_id' => $response->gatewayTransactionId, + 'message' => $response->message, + 'data' => $response->data, + ], $response->isSuccessful() ? 200 : 422); + } + + /** + * Refund a previously captured transaction. + * + * @param Request $request + * @param string $id Gateway UUID or public_id + * + * @return JsonResponse + */ + public function refund(Request $request, string $id): JsonResponse + { + $validator = Validator::make($request->all(), [ + 'gateway_transaction_id' => 'required|string', + 'amount' => 'required|integer|min:1', + 'currency' => 'required|string|size:3', + ]); + + if ($validator->fails()) { + return response()->json([ + 'error' => 'Validation failed.', + 'details' => $validator->errors(), + ], 422); + } + + $refundRequest = new RefundRequest( + gatewayTransactionId: $request->input('gateway_transaction_id'), + amount: $request->integer('amount'), + currency: strtoupper($request->input('currency')), + reason: $request->input('reason'), + invoiceUuid: $request->input('invoice_uuid'), + metadata: $request->input('metadata', []), + ); + + $response = $this->paymentService->refund($id, $refundRequest); + + return response()->json([ + 'status' => $response->status, + 'successful' => $response->successful, + 'gateway_transaction_id' => $response->gatewayTransactionId, + 'message' => $response->message, + ], $response->isSuccessful() ? 200 : 422); + } + + /** + * Create a setup intent for payment method tokenization (e.g., Stripe SetupIntent). + * + * @param Request $request + * @param string $id Gateway UUID or public_id + * + * @return JsonResponse + */ + public function setupIntent(Request $request, string $id): JsonResponse + { + $response = $this->paymentService->createPaymentMethod($id, $request->all()); + + return response()->json([ + 'status' => $response->status, + 'successful' => $response->successful, + 'message' => $response->message, + 'data' => $response->data, + ], $response->isSuccessful() ? 200 : 422); + } + + /** + * List gateway transactions for a specific gateway. + * + * @param Request $request + * @param string $id Gateway UUID or public_id + * + * @return JsonResponse + */ + public function transactions(Request $request, string $id): JsonResponse + { + $gateway = Gateway::where('company_uuid', session('company')) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) + ->firstOrFail(); + + $query = GatewayTransaction::where('gateway_uuid', $gateway->uuid); + + if ($request->has('type')) { + $query->where('type', $request->input('type')); + } + + if ($request->has('status')) { + $query->where('status', $request->input('status')); + } + + $transactions = $query->orderBy('created_at', 'desc') + ->paginate($request->integer('per_page', 25)); + + return response()->json($transactions); + } +} diff --git a/server/src/Http/Controllers/WebhookController.php b/server/src/Http/Controllers/WebhookController.php new file mode 100644 index 0000000..791060f --- /dev/null +++ b/server/src/Http/Controllers/WebhookController.php @@ -0,0 +1,162 @@ +input('company_uuid') + ?? $request->header('X-Company-UUID') + ?? null; + + // Find the active gateway for this driver + $gateway = Gateway::query() + ->when($companyUuid, fn ($q) => $q->where('company_uuid', $companyUuid)) + ->where('driver', $driver) + ->where('status', 'active') + ->first(); + + if (!$gateway) { + Log::channel('ledger')->warning("Webhook received for unknown/inactive driver: {$driver}", [ + 'company_uuid' => $companyUuid, + 'ip' => $request->ip(), + ]); + + // Return 200 to prevent retries for unconfigured gateways + return response()->json(['message' => 'Gateway not configured.'], 200); + } + + try { + // Resolve and initialize the driver + $driverInstance = $this->gatewayManager->driver($driver) + ->initialize($gateway->decryptedConfig(), $gateway->is_sandbox); + + // Delegate signature verification and event parsing to the driver + $response = $driverInstance->handleWebhook($request); + + } catch (WebhookSignatureException $e) { + Log::channel('ledger')->error("Webhook signature verification failed for [{$driver}].", [ + 'error' => $e->getMessage(), + 'gateway_id' => $gateway->uuid, + 'ip' => $request->ip(), + ]); + + // Return 400 for signature failures so the gateway knows something is wrong + return response()->json(['message' => 'Signature verification failed.'], 400); + + } catch (\Throwable $e) { + Log::channel('ledger')->error("Webhook driver exception for [{$driver}].", [ + 'error' => $e->getMessage(), + 'gateway_id' => $gateway->uuid, + ]); + + return response()->json(['message' => 'Webhook processing error.'], 200); + } + + // Idempotency check — skip if this exact event was already processed + $gatewayReferenceId = $response->gatewayTransactionId; + $eventType = $response->eventType; + + if ($gatewayReferenceId && GatewayTransaction::alreadyProcessed($gatewayReferenceId, 'webhook_event')) { + Log::channel('ledger')->info("Webhook already processed, skipping. [{$driver}]", [ + 'gateway_reference_id' => $gatewayReferenceId, + 'event_type' => $eventType, + ]); + + return response()->json(['message' => 'Already processed.'], 200); + } + + // Persist the gateway transaction record + $gatewayTransaction = GatewayTransaction::create([ + 'company_uuid' => $gateway->company_uuid, + 'gateway_uuid' => $gateway->uuid, + 'gateway_reference_id' => $gatewayReferenceId, + 'type' => 'webhook_event', + 'event_type' => $eventType, + 'amount' => $response->amount, + 'currency' => $response->currency, + 'status' => $response->status, + 'message' => $response->message, + 'raw_response' => $response->rawResponse, + ]); + + // Dispatch the appropriate normalized event + $this->dispatchEvent($response, $gateway, $gatewayTransaction); + + Log::channel('ledger')->info("Webhook received and queued for [{$driver}].", [ + 'gateway_reference_id' => $gatewayReferenceId, + 'event_type' => $eventType, + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + ]); + + return response()->json(['message' => 'Webhook received.'], 200); + } + + /** + * Dispatch the appropriate Laravel event based on the normalized event type. + * + * @param GatewayResponse $response + * @param Gateway $gateway + * @param GatewayTransaction $gatewayTransaction + */ + private function dispatchEvent( + GatewayResponse $response, + Gateway $gateway, + GatewayTransaction $gatewayTransaction + ): void { + match ($response->eventType) { + GatewayResponse::EVENT_PAYMENT_SUCCEEDED => PaymentSucceeded::dispatch($response, $gateway, $gatewayTransaction), + GatewayResponse::EVENT_PAYMENT_FAILED => PaymentFailed::dispatch($response, $gateway, $gatewayTransaction), + GatewayResponse::EVENT_REFUND_PROCESSED => RefundProcessed::dispatch($response, $gateway, $gatewayTransaction), + default => Log::channel('ledger')->info("Webhook event [{$response->eventType}] has no registered handler."), + }; + } +} diff --git a/server/src/Http/Resources/v1/Gateway.php b/server/src/Http/Resources/v1/Gateway.php new file mode 100644 index 0000000..3a6e6f2 --- /dev/null +++ b/server/src/Http/Resources/v1/Gateway.php @@ -0,0 +1,41 @@ + + */ + public function toArray($request): array + { + return [ + 'id' => $this->public_id, + 'uuid' => $this->uuid, + 'name' => $this->name, + 'driver' => $this->driver, + 'description' => $this->description, + 'capabilities' => $this->capabilities ?? [], + 'is_sandbox' => $this->is_sandbox, + 'status' => $this->status, + 'return_url' => $this->return_url, + 'webhook_url' => $this->getWebhookUrl(), + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/Listeners/HandleFailedPayment.php b/server/src/Listeners/HandleFailedPayment.php new file mode 100644 index 0000000..98dd8aa --- /dev/null +++ b/server/src/Listeners/HandleFailedPayment.php @@ -0,0 +1,73 @@ +response; + $gatewayTransaction = $event->gatewayTransaction; + $gateway = $event->gateway; + + if ($gatewayTransaction->isProcessed()) { + return; + } + + try { + // Update invoice status to 'overdue' if it was 'pending' + $invoiceUuid = data_get($response->rawResponse, 'metadata.invoice_uuid'); + + if ($invoiceUuid) { + Invoice::where('uuid', $invoiceUuid) + ->orWhere('public_id', $invoiceUuid) + ->where('status', 'pending') + ->update(['status' => 'overdue']); + } + + $gatewayTransaction->markAsProcessed(); + + Log::channel('ledger')->warning('Payment failed processed.', [ + 'gateway' => $gateway->driver, + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + 'error_code' => $response->errorCode, + 'message' => $response->message, + ]); + } catch (\Throwable $e) { + Log::channel('ledger')->error('HandleFailedPayment: failed.', [ + 'error' => $e->getMessage(), + ]); + throw $e; + } + } +} diff --git a/server/src/Listeners/HandleProcessedRefund.php b/server/src/Listeners/HandleProcessedRefund.php new file mode 100644 index 0000000..d1f2189 --- /dev/null +++ b/server/src/Listeners/HandleProcessedRefund.php @@ -0,0 +1,93 @@ +response; + $gatewayTransaction = $event->gatewayTransaction; + $gateway = $event->gateway; + + if ($gatewayTransaction->isProcessed()) { + return; + } + + try { + // Mark invoice as refunded + $invoiceUuid = data_get($response->rawResponse, 'metadata.invoice_uuid'); + + if ($invoiceUuid) { + Invoice::where('uuid', $invoiceUuid) + ->orWhere('public_id', $invoiceUuid) + ->update(['status' => 'refunded']); + } + + // Create a reversal journal entry + if ($response->amount && $response->currency) { + $this->ledgerService->createJournalEntry( + type: 'refund', + amount: $response->amount, + currency: $response->currency, + description: sprintf( + 'Refund issued via %s — Ref: %s', + $gateway->name, + $response->gatewayTransactionId + ), + metadata: [ + 'gateway_driver' => $gateway->driver, + 'gateway_transaction_id' => $response->gatewayTransactionId, + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + 'invoice_uuid' => $invoiceUuid, + ], + ); + } + + $gatewayTransaction->markAsProcessed(); + + Log::channel('ledger')->info('Refund processed.', [ + 'gateway' => $gateway->driver, + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + ]); + } catch (\Throwable $e) { + Log::channel('ledger')->error('HandleProcessedRefund: failed.', [ + 'error' => $e->getMessage(), + ]); + throw $e; + } + } +} diff --git a/server/src/Listeners/HandleSuccessfulPayment.php b/server/src/Listeners/HandleSuccessfulPayment.php new file mode 100644 index 0000000..36a66fb --- /dev/null +++ b/server/src/Listeners/HandleSuccessfulPayment.php @@ -0,0 +1,126 @@ +response; + $gatewayTransaction = $event->gatewayTransaction; + $gateway = $event->gateway; + + // Guard: do not process if already handled (idempotency) + if ($gatewayTransaction->isProcessed()) { + Log::channel('ledger')->info('HandleSuccessfulPayment: already processed, skipping.', [ + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + ]); + return; + } + + try { + // 1. Mark the related invoice as paid if we have an invoice reference + $invoiceUuid = $gatewayTransaction->raw_response['metadata']['invoice_uuid'] + ?? data_get($response->data, 'invoice_uuid') + ?? null; + + if ($invoiceUuid) { + $invoice = Invoice::where('uuid', $invoiceUuid) + ->orWhere('public_id', $invoiceUuid) + ->first(); + + if ($invoice && $invoice->status !== 'paid') { + $invoice->update([ + 'status' => 'paid', + 'paid_at' => now(), + ]); + + Log::channel('ledger')->info('Invoice marked as paid.', [ + 'invoice_uuid' => $invoice->uuid, + 'gateway' => $gateway->driver, + ]); + } + } + + // 2. Create a revenue journal entry + if ($response->amount && $response->currency) { + $this->ledgerService->createJournalEntry( + type: 'revenue', + amount: $response->amount, + currency: $response->currency, + description: sprintf( + 'Payment received via %s — Ref: %s', + $gateway->name, + $response->gatewayTransactionId + ), + metadata: [ + 'gateway_driver' => $gateway->driver, + 'gateway_transaction_id' => $response->gatewayTransactionId, + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + 'invoice_uuid' => $invoiceUuid, + ], + ); + } + + // 3. Seal the gateway transaction as processed + $gatewayTransaction->markAsProcessed(); + + Log::channel('ledger')->info('HandleSuccessfulPayment: completed.', [ + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + 'gateway_reference_id' => $response->gatewayTransactionId, + ]); + } catch (\Throwable $e) { + Log::channel('ledger')->error('HandleSuccessfulPayment: failed.', [ + 'error' => $e->getMessage(), + 'gateway_transaction_uuid' => $gatewayTransaction->uuid, + ]); + + // Re-throw so the queue retries + throw $e; + } + } +} diff --git a/server/src/Models/Gateway.php b/server/src/Models/Gateway.php new file mode 100644 index 0000000..e240ae7 --- /dev/null +++ b/server/src/Models/Gateway.php @@ -0,0 +1,193 @@ + 'encrypted:array', + 'capabilities' => 'array', + 'is_sandbox' => 'boolean', + ]; + + /** + * The attributes that should be appended to the model's array form. + */ + protected $appends = ['public_id']; + + /** + * The attributes that should be hidden for serialization. + * The config (credentials) are never exposed via the API. + */ + protected $hidden = ['config']; + + /** + * The attributes that should be visible for serialization. + */ + protected $visible = [ + 'uuid', + 'public_id', + 'company_uuid', + 'name', + 'driver', + 'description', + 'capabilities', + 'is_sandbox', + 'status', + 'return_url', + 'webhook_url', + 'created_at', + 'updated_at', + ]; + + // ------------------------------------------------------------------------- + // Relationships + // ------------------------------------------------------------------------- + + /** + * The gateway transactions associated with this gateway. + */ + public function transactions() + { + return $this->hasMany(GatewayTransaction::class, 'gateway_uuid', 'uuid'); + } + + // ------------------------------------------------------------------------- + // Accessors & Helpers + // ------------------------------------------------------------------------- + + /** + * Return the decrypted configuration array. + * This is used internally by the PaymentGatewayManager to initialize drivers. + * + * @return array + */ + public function decryptedConfig(): array + { + return $this->config ?? []; + } + + /** + * Check if this gateway has a specific capability. + * + * @param string $capability + * + * @return bool + */ + public function hasCapability(string $capability): bool + { + return in_array($capability, $this->capabilities ?? [], true); + } + + /** + * Check if this gateway is active. + * + * @return bool + */ + public function isActive(): bool + { + return $this->status === 'active'; + } + + /** + * Scope to only active gateways. + */ + public function scopeActive($query) + { + return $query->where('status', 'active'); + } + + /** + * Scope to filter by driver code. + */ + public function scopeForDriver($query, string $driver) + { + return $query->where('driver', $driver); + } + + /** + * Scope to filter by company. + */ + public function scopeForCompany($query, string $companyUuid) + { + return $query->where('company_uuid', $companyUuid); + } + + /** + * Generate the webhook URL for this gateway. + * This is the URL that should be registered in the gateway's dashboard. + * + * @return string + */ + public function getWebhookUrl(): string + { + return url('/ledger/webhooks/' . $this->driver); + } +} diff --git a/server/src/Models/GatewayTransaction.php b/server/src/Models/GatewayTransaction.php new file mode 100644 index 0000000..e8b0f14 --- /dev/null +++ b/server/src/Models/GatewayTransaction.php @@ -0,0 +1,175 @@ + 'array', + 'amount' => 'integer', + 'processed_at' => 'datetime', + ]; + + /** + * The attributes that should be appended to the model's array form. + */ + protected $appends = ['public_id']; + + // ------------------------------------------------------------------------- + // Relationships + // ------------------------------------------------------------------------- + + /** + * The gateway this transaction belongs to. + */ + public function gateway() + { + return $this->belongsTo(Gateway::class, 'gateway_uuid', 'uuid'); + } + + /** + * The core-api Transaction record linked to this gateway transaction. + */ + public function transaction() + { + return $this->belongsTo(\Fleetbase\Models\Transaction::class, 'transaction_uuid', 'uuid'); + } + + // ------------------------------------------------------------------------- + // Scopes + // ------------------------------------------------------------------------- + + /** + * Scope to find a transaction by gateway reference ID (idempotency check). + */ + public function scopeForGatewayReference($query, string $referenceId) + { + return $query->where('gateway_reference_id', $referenceId); + } + + /** + * Scope to filter by type. + */ + public function scopeOfType($query, string $type) + { + return $query->where('type', $type); + } + + /** + * Scope to filter by status. + */ + public function scopeWithStatus($query, string $status) + { + return $query->where('status', $status); + } + + // ------------------------------------------------------------------------- + // Helpers + // ------------------------------------------------------------------------- + + /** + * Check if this transaction has already been processed. + * Used for idempotency in webhook handling. + * + * @return bool + */ + public function isProcessed(): bool + { + return $this->processed_at !== null; + } + + /** + * Mark this transaction as processed. + * + * @return bool + */ + public function markAsProcessed(): bool + { + return $this->update(['processed_at' => now()]); + } + + /** + * Check if a gateway reference ID has already been processed (static idempotency check). + * + * @param string $gatewayReferenceId The gateway's own transaction ID + * @param string $type The transaction type (e.g., 'webhook_event') + * + * @return bool + */ + public static function alreadyProcessed(string $gatewayReferenceId, string $type = 'webhook_event'): bool + { + return static::where('gateway_reference_id', $gatewayReferenceId) + ->where('type', $type) + ->whereNotNull('processed_at') + ->exists(); + } +} diff --git a/server/src/PaymentGatewayManager.php b/server/src/PaymentGatewayManager.php new file mode 100644 index 0000000..f41fc18 --- /dev/null +++ b/server/src/PaymentGatewayManager.php @@ -0,0 +1,162 @@ +gateway('stripe'); + * $driver = $manager->gateway($gatewayUuid); + * + * // Use the driver: + * $response = $driver->purchase($purchaseRequest); + * + * Third-party extensions can register new drivers via the extend() method + * in their service provider: + * + * $manager->extend('paypal', function ($app) { + * return $app->make(\MyCompany\PaypalDriver::class); + * }); + * + * @package Fleetbase\Ledger + */ +class PaymentGatewayManager extends Manager +{ + /** + * Resolve and initialize a gateway driver from a persisted Gateway model. + * + * Accepts either a Gateway UUID, a public_id (e.g., 'gateway_abc123'), + * or a driver code (e.g., 'stripe'). The resolved driver is initialized + * with the decrypted configuration from the Gateway model. + * + * @param string $gatewayIdentifier UUID, public_id, or driver code + * + * @return GatewayDriverInterface + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException if no active gateway is found + */ + public function gateway(string $gatewayIdentifier): GatewayDriverInterface + { + $companyUuid = session('company'); + + $gateway = Gateway::query() + ->when($companyUuid, fn ($q) => $q->where('company_uuid', $companyUuid)) + ->where(function ($q) use ($gatewayIdentifier) { + $q->where('uuid', $gatewayIdentifier) + ->orWhere('public_id', $gatewayIdentifier) + ->orWhere('driver', $gatewayIdentifier); + }) + ->where('status', 'active') + ->firstOrFail(); + + return $this->driver($gateway->driver) + ->initialize($gateway->decryptedConfig(), $gateway->is_sandbox); + } + + /** + * Resolve a driver by code without loading from the database. + * Useful for webhook handling where the gateway is identified by URL segment. + * + * @param string $driverCode The driver code (e.g., 'stripe', 'qpay') + * + * @return GatewayDriverInterface + */ + public function driverForWebhook(string $driverCode, string $companyUuid): GatewayDriverInterface + { + $gateway = Gateway::query() + ->where('company_uuid', $companyUuid) + ->where('driver', $driverCode) + ->where('status', 'active') + ->firstOrFail(); + + return $this->driver($gateway->driver) + ->initialize($gateway->decryptedConfig(), $gateway->is_sandbox); + } + + /** + * Return a list of all registered driver codes. + * Used by the /drivers endpoint to populate the gateway configuration UI. + * + * @return string[] + */ + public function getRegisteredDriverCodes(): array + { + return ['stripe', 'qpay', 'cash']; + } + + /** + * Return a list of all registered drivers with their metadata. + * Used by the frontend to render the "Add Gateway" form dynamically. + * + * @return array + */ + public function getDriverManifest(): array + { + $manifest = []; + + foreach ($this->getRegisteredDriverCodes() as $code) { + try { + $driver = $this->driver($code); + $manifest[] = [ + 'code' => $driver->getCode(), + 'name' => $driver->getName(), + 'capabilities' => $driver->getCapabilities(), + 'config_schema' => $driver->getConfigSchema(), + ]; + } catch (\Exception $e) { + // Skip drivers that fail to instantiate + } + } + + return $manifest; + } + + /** + * Return the default driver code. + */ + public function getDefaultDriver(): string + { + return config('ledger.default_gateway', 'cash'); + } + + // ------------------------------------------------------------------------- + // Driver Factory Methods + // ------------------------------------------------------------------------- + + /** + * Create the Stripe driver instance. + */ + protected function createStripeDriver(): StripeDriver + { + return $this->container->make(StripeDriver::class); + } + + /** + * Create the QPay driver instance. + */ + protected function createQpayDriver(): QPayDriver + { + return $this->container->make(QPayDriver::class); + } + + /** + * Create the Cash driver instance. + */ + protected function createCashDriver(): CashDriver + { + return $this->container->make(CashDriver::class); + } +} diff --git a/server/src/Providers/LedgerServiceProvider.php b/server/src/Providers/LedgerServiceProvider.php index 5680213..dfe9388 100644 --- a/server/src/Providers/LedgerServiceProvider.php +++ b/server/src/Providers/LedgerServiceProvider.php @@ -2,14 +2,29 @@ namespace Fleetbase\Ledger\Providers; +use Fleetbase\Ledger\Events\PaymentFailed; +use Fleetbase\Ledger\Events\PaymentSucceeded; +use Fleetbase\Ledger\Events\RefundProcessed; +use Fleetbase\Ledger\Listeners\HandleFailedPayment; +use Fleetbase\Ledger\Listeners\HandleProcessedRefund; +use Fleetbase\Ledger\Listeners\HandleSuccessfulPayment; +use Fleetbase\Ledger\PaymentGatewayManager; +use Fleetbase\Ledger\Services\InvoiceService; +use Fleetbase\Ledger\Services\LedgerService; +use Fleetbase\Ledger\Services\PaymentService; +use Fleetbase\Ledger\Services\WalletService; use Fleetbase\Providers\CoreServiceProvider; +use Illuminate\Support\Facades\Event; if (!class_exists(CoreServiceProvider::class)) { throw new \Exception('Ledger cannot be loaded without `fleetbase/core-api` installed!'); } /** - * Ledger extension service provider. + * LedgerServiceProvider + * + * Registers all Ledger services, the payment gateway manager, + * event-listener bindings, and bootstraps routes and migrations. */ class LedgerServiceProvider extends CoreServiceProvider { @@ -39,10 +54,24 @@ public function register() { $this->app->register(CoreServiceProvider::class); - // Register services - $this->app->singleton(\Fleetbase\Ledger\Services\LedgerService::class); - $this->app->singleton(\Fleetbase\Ledger\Services\WalletService::class); - $this->app->singleton(\Fleetbase\Ledger\Services\InvoiceService::class); + // Core accounting services + $this->app->singleton(LedgerService::class); + $this->app->singleton(WalletService::class); + $this->app->singleton(InvoiceService::class); + + // Payment gateway system + // The PaymentGatewayManager is bound as a singleton and also aliased + // as 'ledger.gateway' for convenient facade-style access. + $this->app->singleton(PaymentGatewayManager::class, function ($app) { + return new PaymentGatewayManager($app); + }); + + $this->app->alias(PaymentGatewayManager::class, 'ledger.gateway'); + + // PaymentService depends on PaymentGatewayManager + $this->app->singleton(PaymentService::class, function ($app) { + return new PaymentService($app->make(PaymentGatewayManager::class)); + }); } /** @@ -58,5 +87,23 @@ public function boot() $this->registerExpansionsFrom(__DIR__ . '/../Expansions'); $this->loadRoutesFrom(__DIR__ . '/../routes.php'); $this->loadMigrationsFrom(__DIR__ . '/../../migrations'); + + // Register event-listener bindings for the payment gateway system + $this->registerPaymentEvents(); + } + + /** + * Register all payment-related event-listener pairs. + * + * All listeners implement ShouldQueue and will be processed + * asynchronously by the queue worker. + * + * @return void + */ + private function registerPaymentEvents(): void + { + Event::listen(PaymentSucceeded::class, HandleSuccessfulPayment::class); + Event::listen(PaymentFailed::class, HandleFailedPayment::class); + Event::listen(RefundProcessed::class, HandleProcessedRefund::class); } } diff --git a/server/src/Services/PaymentService.php b/server/src/Services/PaymentService.php new file mode 100644 index 0000000..d337f34 --- /dev/null +++ b/server/src/Services/PaymentService.php @@ -0,0 +1,236 @@ +charge($gatewayUuid, $purchaseRequest); + * + * // Refund a transaction + * $response = $service->refund($gatewayUuid, $refundRequest); + * + * // Tokenize a payment method + * $response = $service->createPaymentMethod($gatewayUuid, $data); + * + * @package Fleetbase\Ledger\Services + */ +class PaymentService +{ + public function __construct( + protected PaymentGatewayManager $gatewayManager, + ) { + } + + /** + * Initiate a payment charge through the specified gateway. + * + * This method: + * 1. Resolves and initializes the gateway driver + * 2. Calls driver->purchase() + * 3. Persists the GatewayTransaction record + * 4. Dispatches PaymentSucceeded or PaymentFailed event + * + * @param string $gatewayIdentifier UUID, public_id, or driver code + * @param PurchaseRequest $request The purchase request DTO + * + * @return GatewayResponse + */ + public function charge(string $gatewayIdentifier, PurchaseRequest $request): GatewayResponse + { + $gateway = $this->resolveGatewayModel($gatewayIdentifier); + $driver = $this->gatewayManager->driver($gateway->driver) + ->initialize($gateway->decryptedConfig(), $gateway->is_sandbox); + + $response = $driver->purchase($request); + + $gatewayTransaction = $this->persistTransaction( + gateway: $gateway, + response: $response, + type: 'purchase', + invoiceUuid: $request->invoiceUuid, + ); + + // Dispatch event for immediate successes (e.g., Cash driver, confirmed Stripe PaymentIntent) + if ($response->isSuccessful() && $response->status === GatewayResponse::STATUS_SUCCEEDED) { + PaymentSucceeded::dispatch($response, $gateway, $gatewayTransaction); + } elseif ($response->isFailed()) { + PaymentFailed::dispatch($response, $gateway, $gatewayTransaction); + } + // Pending responses (e.g., QPay, unconfirmed Stripe) are handled via webhook + + return $response; + } + + /** + * Refund a previously captured transaction. + * + * @param string $gatewayIdentifier UUID, public_id, or driver code + * @param RefundRequest $request The refund request DTO + * + * @return GatewayResponse + */ + public function refund(string $gatewayIdentifier, RefundRequest $request): GatewayResponse + { + $gateway = $this->resolveGatewayModel($gatewayIdentifier); + $driver = $this->gatewayManager->driver($gateway->driver) + ->initialize($gateway->decryptedConfig(), $gateway->is_sandbox); + + $response = $driver->refund($request); + + $gatewayTransaction = $this->persistTransaction( + gateway: $gateway, + response: $response, + type: 'refund', + invoiceUuid: $request->invoiceUuid, + ); + + if ($response->isSuccessful()) { + RefundProcessed::dispatch($response, $gateway, $gatewayTransaction); + } + + return $response; + } + + /** + * Create a stored payment method (tokenize a card). + * + * @param string $gatewayIdentifier UUID, public_id, or driver code + * @param array $data Gateway-specific tokenization data + * + * @return GatewayResponse + */ + public function createPaymentMethod(string $gatewayIdentifier, array $data): GatewayResponse + { + $gateway = $this->resolveGatewayModel($gatewayIdentifier); + $driver = $this->gatewayManager->driver($gateway->driver) + ->initialize($gateway->decryptedConfig(), $gateway->is_sandbox); + + if (!$driver->hasCapability('tokenization')) { + return GatewayResponse::failure( + eventType: GatewayResponse::EVENT_PAYMENT_FAILED, + message: "Gateway [{$gateway->driver}] does not support payment method tokenization.", + ); + } + + $response = $driver->createPaymentMethod($data); + + $this->persistTransaction( + gateway: $gateway, + response: $response, + type: 'setup_intent', + ); + + return $response; + } + + /** + * Return the full driver manifest for the /drivers endpoint. + * Used by the frontend to render the "Add Gateway" configuration form. + * + * @return array + */ + public function getDriverManifest(): array + { + return $this->gatewayManager->getDriverManifest(); + } + + // ------------------------------------------------------------------------- + // Private Helpers + // ------------------------------------------------------------------------- + + /** + * Resolve the Gateway model from an identifier. + * + * @param string $identifier UUID, public_id, or driver code + * + * @return Gateway + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + private function resolveGatewayModel(string $identifier): Gateway + { + $companyUuid = session('company'); + + return Gateway::query() + ->when($companyUuid, fn ($q) => $q->where('company_uuid', $companyUuid)) + ->where(function ($q) use ($identifier) { + $q->where('uuid', $identifier) + ->orWhere('public_id', $identifier) + ->orWhere('driver', $identifier); + }) + ->where('status', 'active') + ->firstOrFail(); + } + + /** + * Persist a GatewayTransaction record for audit and idempotency. + * + * @param Gateway $gateway + * @param GatewayResponse $response + * @param string $type Transaction type: 'purchase', 'refund', 'setup_intent' + * @param string|null $invoiceUuid Optional invoice UUID for linking + * + * @return GatewayTransaction + */ + private function persistTransaction( + Gateway $gateway, + GatewayResponse $response, + string $type, + ?string $invoiceUuid = null, + ): GatewayTransaction { + try { + return GatewayTransaction::create([ + 'company_uuid' => $gateway->company_uuid, + 'gateway_uuid' => $gateway->uuid, + 'gateway_reference_id' => $response->gatewayTransactionId, + 'type' => $type, + 'event_type' => $response->eventType, + 'amount' => $response->amount, + 'currency' => $response->currency, + 'status' => $response->status, + 'message' => $response->message, + 'raw_response' => array_merge( + $response->rawResponse, + array_filter(['invoice_uuid' => $invoiceUuid]) + ), + ]); + } catch (\Throwable $e) { + // Log but don't fail the payment — the charge already went through + Log::channel('ledger')->error('Failed to persist GatewayTransaction.', [ + 'error' => $e->getMessage(), + 'gateway_reference_id' => $response->gatewayTransactionId, + 'type' => $type, + ]); + + // Return a minimal unsaved instance so callers don't need null checks + return new GatewayTransaction([ + 'gateway_uuid' => $gateway->uuid, + 'gateway_reference_id' => $response->gatewayTransactionId, + 'type' => $type, + 'status' => $response->status, + ]); + } + } +} diff --git a/server/src/routes.php b/server/src/routes.php index b0fb8df..585e033 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -15,6 +15,22 @@ Route::prefix(config('ledger.api.routing.prefix', 'ledger'))->namespace('Fleetbase\Ledger\Http\Controllers')->group( function ($router) { + + /* + |-------------------------------------------------------------------------- + | Webhook Routes (Public — No Auth Required) + |-------------------------------------------------------------------------- + | + | These routes receive inbound webhook callbacks from payment gateways. + | They must be publicly accessible (no auth middleware) but each driver + | performs its own signature verification internally. + | + | Route: POST /ledger/webhooks/{driver} + | Example: POST /ledger/webhooks/stripe + | POST /ledger/webhooks/qpay + */ + $router->post('webhooks/{driver}', 'WebhookController@handle'); + /* |-------------------------------------------------------------------------- | Internal Ledger API Routes @@ -81,6 +97,28 @@ function ($router) { $router->get('transactions', 'Internal\v1\TransactionController@query'); $router->get('transactions/{id}', 'Internal\v1\TransactionController@find'); + // ------------------------------------------------------------ + // Payment Gateways + // ------------------------------------------------------------ + // Driver manifest — returns all available drivers with config schemas + // Must be registered BEFORE the {id} route to avoid route conflicts + $router->get('gateways/drivers', 'Internal\v1\GatewayController@drivers'); + + // Gateway CRUD + $router->get('gateways', 'Internal\v1\GatewayController@index'); + $router->post('gateways', 'Internal\v1\GatewayController@store'); + $router->get('gateways/{id}', 'Internal\v1\GatewayController@show'); + $router->put('gateways/{id}', 'Internal\v1\GatewayController@update'); + $router->delete('gateways/{id}', 'Internal\v1\GatewayController@destroy'); + + // Gateway payment operations + $router->post('gateways/{id}/charge', 'Internal\v1\GatewayController@charge'); + $router->post('gateways/{id}/refund', 'Internal\v1\GatewayController@refund'); + $router->post('gateways/{id}/setup-intent', 'Internal\v1\GatewayController@setupIntent'); + + // Gateway transaction history + $router->get('gateways/{id}/transactions', 'Internal\v1\GatewayController@transactions'); + // ------------------------------------------------------------ // Reports & Financial Statements // ------------------------------------------------------------ From a87b3a41a3abdc514865ff18b23a9d712baff3fb Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sat, 28 Feb 2026 03:11:19 -0500 Subject: [PATCH 006/209] =?UTF-8?q?feat(wallet):=20Milestone=203=20?= =?UTF-8?q?=E2=80=94=20complete=20wallet=20system=20for=20drivers=20and=20?= =?UTF-8?q?customers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Stripe SDK - Fix stripe/stripe-php version to ^17.0 in composer.json - Update StripeDriver to use StripeClient instance methods (v17 API) - paymentIntents->create(), refunds->create(), setupIntents->create() - Remove static Stripe::setApiKey() call (deprecated in v17) ## M3.1 — WalletTransaction model + migration - New model: WalletTransaction with full type/direction/status constants - Types: deposit, withdrawal, transfer_in, transfer_out, payout, fee, refund, adjustment, earning - Directions: credit, debit - Statuses: pending, completed, failed, reversed - Polymorphic 'subject' relationship (driver/customer/order/invoice) - Scopes: credits(), debits(), completed(), ofType() - Helpers: isCredit(), isDebit(), isCompleted(), getFormattedAmountAttribute() - New migration: ledger_wallet_transactions with composite indexes for common query patterns (wallet+type, wallet+direction, wallet+status, wallet+date) ## M3.2 — Wallet model enriched - Added transactions(), completedTransactions(), credits(), debits() HasMany relationships - Added getTypeAttribute() — infers 'driver'/'customer'/'company' from subject_type - Added getFormattedBalanceAttribute() — cents to decimal string - Added canDebit() / canCredit() guards (frozen wallets accept credits, not debits) - Added close() state transition - Added credit()/debit() low-level balance methods with atomic increment/decrement - Added Wallet::forSubject() static factory (findOrCreate by subject) - Added STATUS_ACTIVE/FROZEN/CLOSED constants - Added 'type' and 'formatted_balance' to $appends ## M3.3 — WalletService fully enriched - deposit() now creates WalletTransaction audit record + uses wallet->credit() - withdraw() now creates WalletTransaction audit record + uses wallet->debit() - transfer() now creates paired WalletTransaction records (transfer_in + transfer_out) - New: topUp() — charges a gateway via PaymentService, credits wallet on sync success - New: creditEarnings() — credits driver earnings with TYPE_EARNING transaction - New: processPayout() — debits driver wallet with TYPE_PAYOUT transaction - New: provisionBatch() — bulk wallet provisioning for existing drivers/customers - New: recalculateBalance() — reconciliation utility from transaction history - Lazy PaymentService resolution to avoid circular dependency ## M3.4 — WalletController fully enriched - Constructor injection of WalletService - deposit()/withdraw() now return {wallet, transaction} JSON (not just wallet) - transfer() now returns {from_wallet, to_wallet, from_transaction, to_transaction} - New: topUp() endpoint — POST /wallets/{id}/topup - New: payout() endpoint — POST /wallets/{id}/payout - New: getTransactions() — GET /wallets/{id}/transactions with full filtering - New: freeze() — POST /wallets/{id}/freeze - New: unfreeze() — POST /wallets/{id}/unfreeze - New: recalculate() — POST /wallets/{id}/recalculate (reconciliation) - Private resolveWallet() helper for DRY wallet lookup ## M3.5 — Public API (Customer/Driver facing) - New controller: Api/v1/WalletApiController - GET /ledger/v1/wallet — get own wallet (auto-provisions) - GET /ledger/v1/wallet/balance — get balance + formatted_balance - GET /ledger/v1/wallet/transactions — paginated transaction history - POST /ledger/v1/wallet/topup — top up via gateway - New resource: Http/Resources/v1/WalletTransaction (safe public serialization) - Wallet resource enriched with 'type' and 'formatted_balance' fields ## M3.6 — Routes updated - Added all new internal wallet routes (topup, payout, freeze, unfreeze, recalculate, transactions) - Added public API route group (/ledger/v1/...) with fleetbase.api middleware - Added /ledger/int/v1/wallet-transactions standalone query endpoint - Added /ledger/int/v1/reports/wallet-summary endpoint - New: WalletTransactionController (standalone cross-wallet query + find) - New: ReportController::walletSummary() — wallet counts, period stats, top driver wallets --- composer.json | 2 +- ...reate_ledger_wallet_transactions_table.php | 81 +++ server/src/Gateways/StripeDriver.php | 13 +- .../Api/v1/WalletApiController.php | 182 ++++++ .../Internal/v1/ReportController.php | 107 ++++ .../Internal/v1/WalletController.php | 415 +++++++++---- .../v1/WalletTransactionController.php | 62 ++ server/src/Http/Resources/v1/Wallet.php | 10 +- .../Http/Resources/v1/WalletTransaction.php | 52 ++ server/src/Models/Wallet.php | 288 +++++++-- server/src/Models/WalletTransaction.php | 236 +++++++ server/src/Services/WalletService.php | 576 +++++++++++++++--- server/src/routes.php | 54 +- 13 files changed, 1816 insertions(+), 262 deletions(-) create mode 100644 server/migrations/2024_01_01_000009_create_ledger_wallet_transactions_table.php create mode 100644 server/src/Http/Controllers/Api/v1/WalletApiController.php create mode 100644 server/src/Http/Controllers/Internal/v1/WalletTransactionController.php create mode 100644 server/src/Http/Resources/v1/WalletTransaction.php create mode 100644 server/src/Models/WalletTransaction.php diff --git a/composer.json b/composer.json index 13ede09..fa07200 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "guzzlehttp/guzzle": "^7.0", "php-http/guzzle7-adapter": "^1.0", "psr/http-factory-implementation": "*", - "stripe/stripe-php": "^13.0" + "stripe/stripe-php": "^17.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.34.1", diff --git a/server/migrations/2024_01_01_000009_create_ledger_wallet_transactions_table.php b/server/migrations/2024_01_01_000009_create_ledger_wallet_transactions_table.php new file mode 100644 index 0000000..c37332b --- /dev/null +++ b/server/migrations/2024_01_01_000009_create_ledger_wallet_transactions_table.php @@ -0,0 +1,81 @@ +bigIncrements('id'); + $table->string('uuid', 191)->nullable()->unique(); + $table->string('public_id', 191)->nullable()->unique(); + + // Ownership + $table->string('company_uuid', 191)->nullable()->index(); + + // Parent wallet + $table->string('wallet_uuid', 191)->nullable()->index(); + + // Optional link to a gateway transaction that triggered this wallet movement + $table->string('gateway_transaction_uuid', 191)->nullable()->index(); + + // Transaction classification + $table->string('type', 64)->default('deposit') + ->comment('deposit, withdrawal, transfer_in, transfer_out, payout, fee, refund, adjustment, earning'); + $table->string('direction', 16)->default('credit') + ->comment('credit (money in) or debit (money out)'); + $table->string('status', 32)->default('completed') + ->comment('pending, completed, failed, reversed'); + + // Monetary values — stored as integers (smallest currency unit, e.g., cents) + $table->unsignedBigInteger('amount')->default(0) + ->comment('Transaction amount in smallest currency unit (e.g., cents)'); + $table->bigInteger('balance_after')->default(0) + ->comment('Wallet balance immediately after this transaction (can be negative for overdraft)'); + $table->string('currency', 3)->default('USD'); + + // Description and external reference + $table->string('description', 500)->nullable(); + $table->string('reference', 191)->nullable()->index() + ->comment('External reference: gateway transaction ID, order public_id, invoice public_id, etc.'); + + // Polymorphic subject (driver, customer, order, invoice, etc.) + // Uses 'subject' naming convention per Fleetbase standards + $table->string('subject_uuid', 191)->nullable()->index(); + $table->string('subject_type', 191)->nullable(); + + // Flexible metadata (JSON) + $table->json('meta')->nullable(); + + // Soft deletes and timestamps + $table->softDeletes(); + $table->timestamps(); + + // Composite indexes for common query patterns + $table->index(['wallet_uuid', 'type']); + $table->index(['wallet_uuid', 'direction']); + $table->index(['wallet_uuid', 'status']); + $table->index(['wallet_uuid', 'created_at']); + $table->index(['company_uuid', 'created_at']); + }); + } + + public function down(): void + { + Schema::dropIfExists('ledger_wallet_transactions'); + } +}; diff --git a/server/src/Gateways/StripeDriver.php b/server/src/Gateways/StripeDriver.php index 38d1e65..8efc5eb 100644 --- a/server/src/Gateways/StripeDriver.php +++ b/server/src/Gateways/StripeDriver.php @@ -9,10 +9,6 @@ use Illuminate\Http\Request; use Stripe\Exception\ApiErrorException; use Stripe\Exception\SignatureVerificationException; -use Stripe\PaymentIntent; -use Stripe\Refund; -use Stripe\SetupIntent; -use Stripe\Stripe; use Stripe\StripeClient; use Stripe\Webhook; @@ -115,7 +111,6 @@ public function initialize(array $config, bool $sandbox = false): static $secretKey = $this->config('secret_key'); if ($secretKey) { - Stripe::setApiKey($secretKey); $this->client = new StripeClient($secretKey); } @@ -161,7 +156,7 @@ public function purchase(PurchaseRequest $request): GatewayResponse $params['customer'] = $request->customerId; } - $paymentIntent = PaymentIntent::create($params); + $paymentIntent = $this->client->paymentIntents->create($params); // Determine status $status = $paymentIntent->status === 'succeeded' @@ -236,7 +231,7 @@ public function refund(RefundRequest $request): GatewayResponse $params['metadata'] = $request->metadata; } - $refund = Refund::create($params); + $refund = $this->client->refunds->create($params); $this->logInfo('Refund created', [ 'id' => $refund->id, @@ -296,7 +291,7 @@ public function handleWebhook(Request $request): GatewayResponse } else { // No webhook secret configured — parse without verification (not recommended for production) $this->logError('Webhook received without signature verification. Configure webhook_secret.'); - $event = \Stripe\Event::constructFrom(json_decode($payload, true)); + $event = \Stripe\Event::constructFrom(json_decode($payload, true) ?? []); } // Extract the primary object from the event @@ -351,7 +346,7 @@ public function createPaymentMethod(array $data): GatewayResponse 'usage' => 'off_session', ]); - $setupIntent = SetupIntent::create($params); + $setupIntent = $this->client->setupIntents->create($params); $this->logInfo('SetupIntent created', ['id' => $setupIntent->id]); diff --git a/server/src/Http/Controllers/Api/v1/WalletApiController.php b/server/src/Http/Controllers/Api/v1/WalletApiController.php new file mode 100644 index 0000000..fd2107c --- /dev/null +++ b/server/src/Http/Controllers/Api/v1/WalletApiController.php @@ -0,0 +1,182 @@ +walletService = $walletService; + } + + /** + * Get the authenticated subject's wallet. + * + * Automatically provisions a wallet if one does not yet exist. + * + * GET /api/v1/ledger/wallet + */ + public function getWallet(Request $request): WalletResource + { + $subject = $this->resolveSubject($request); + $wallet = $this->walletService->getOrCreateWallet($subject, $request->input('currency', 'USD')); + + return new WalletResource($wallet); + } + + /** + * Get the wallet balance for the authenticated subject. + * + * GET /api/v1/ledger/wallet/balance + * + * Returns: + * - balance (int) Balance in smallest currency unit (cents) + * - formatted_balance (string) Human-readable balance (e.g., "10.50") + * - currency (string) ISO 4217 currency code + * - status (string) Wallet status + */ + public function getBalance(Request $request): JsonResponse + { + $subject = $this->resolveSubject($request); + $wallet = $this->walletService->getOrCreateWallet($subject, $request->input('currency', 'USD')); + + return response()->json([ + 'balance' => $wallet->balance, + 'formatted_balance' => $wallet->formatted_balance, + 'currency' => $wallet->currency, + 'status' => $wallet->status, + ]); + } + + /** + * Get the transaction history for the authenticated subject's wallet. + * + * GET /api/v1/ledger/wallet/transactions + * + * Supports filtering by: type, direction, status, date_from, date_to + * Supports pagination via limit/page. + */ + public function getTransactions(Request $request): AnonymousResourceCollection + { + $subject = $this->resolveSubject($request); + $wallet = $this->walletService->getOrCreateWallet($subject); + + $transactions = WalletTransaction::where('wallet_uuid', $wallet->uuid) + ->when($request->filled('type'), fn ($q) => $q->where('type', $request->input('type'))) + ->when($request->filled('direction'), fn ($q) => $q->where('direction', $request->input('direction'))) + ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) + ->when($request->filled('date_from'), fn ($q) => $q->whereDate('created_at', '>=', $request->input('date_from'))) + ->when($request->filled('date_to'), fn ($q) => $q->whereDate('created_at', '<=', $request->input('date_to'))) + ->orderBy('created_at', 'desc') + ->paginate($request->input('limit', 25)); + + return WalletTransactionResource::collection($transactions); + } + + /** + * Top up the authenticated subject's wallet via a payment gateway. + * + * POST /api/v1/ledger/wallet/topup + * + * Request body: + * - gateway (string, required) Gateway public_id or UUID + * - amount (int, required) Amount in cents + * - payment_method_token (string) Stripe pm_xxx token + * - customer_id (string) Gateway customer ID + * - description (string) + */ + public function topUp(Request $request): JsonResponse + { + $request->validate([ + 'gateway' => 'required|string', + 'amount' => 'required|integer|min:100', + 'payment_method_token' => 'nullable|string', + 'customer_id' => 'nullable|string', + 'description' => 'nullable|string|max:500', + ]); + + $subject = $this->resolveSubject($request); + $wallet = $this->walletService->getOrCreateWallet($subject); + + try { + $result = $this->walletService->topUp( + wallet: $wallet, + amount: $request->integer('amount'), + gatewayUuid: $request->input('gateway'), + paymentData: $request->only(['payment_method_token', 'customer_id']), + description: $request->input('description', 'Wallet top-up') + ); + + $response = [ + 'wallet' => new WalletResource($result['wallet']), + 'gateway_response' => [ + 'status' => $result['gateway_response']->status, + 'event_type' => $result['gateway_response']->eventType, + 'gateway_reference_id' => $result['gateway_response']->gatewayTransactionId, + 'data' => $result['gateway_response']->data, + ], + ]; + + if ($result['transaction']) { + $response['transaction'] = new WalletTransactionResource($result['transaction']); + } + + return response()->json($response); + } catch (\Exception $e) { + return response()->json(['error' => $e->getMessage()], 422); + } + } + + // ========================================================================= + // Private Helpers + // ========================================================================= + + /** + * Resolve the authenticated subject from the request. + * + * In Fleetbase, API requests carry a consumer (driver or customer) identified + * by their API key. This method resolves the underlying model. + * + * Falls back to the authenticated user if no consumer is present. + * + * @throws \Illuminate\Auth\AuthenticationException + */ + protected function resolveSubject(Request $request): \Illuminate\Database\Eloquent\Model + { + // Prefer the API consumer (driver/customer) if available + if ($request->has('_consumer') && $request->get('_consumer')) { + return $request->get('_consumer'); + } + + // Fall back to the authenticated user + $user = $request->user(); + if (!$user) { + abort(401, 'Unauthenticated.'); + } + + return $user; + } +} diff --git a/server/src/Http/Controllers/Internal/v1/ReportController.php b/server/src/Http/Controllers/Internal/v1/ReportController.php index f1cefee..7cad0ce 100644 --- a/server/src/Http/Controllers/Internal/v1/ReportController.php +++ b/server/src/Http/Controllers/Internal/v1/ReportController.php @@ -3,9 +3,12 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Ledger\Models\Wallet; +use Fleetbase\Ledger\Models\WalletTransaction; use Fleetbase\Ledger\Services\LedgerService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class ReportController extends Controller { @@ -53,4 +56,108 @@ public function trialBalance(Request $request): JsonResponse return response()->json($trialBalance); } + + /** + * Generate a wallet summary report for the authenticated company. + * + * Returns aggregate statistics across all wallets: + * - Total wallets by type (driver, customer, company) + * - Total balance by currency + * - Total credits and debits in a given period + * - Top earners (drivers by earnings) + * - Recent transactions + * + * Query parameters: + * - date_from (string, optional) ISO date string; defaults to start of current month. + * - date_to (string, optional) ISO date string; defaults to today. + * + * @param Request $request + * + * @return JsonResponse + */ + public function walletSummary(Request $request): JsonResponse + { + $request->validate([ + 'date_from' => 'nullable|date', + 'date_to' => 'nullable|date', + ]); + + $companyUuid = session('company'); + $dateFrom = $request->input('date_from', now()->startOfMonth()->toDateString()); + $dateTo = $request->input('date_to', now()->toDateString()); + + // Total wallets grouped by inferred type + $walletCounts = Wallet::where('company_uuid', $companyUuid) + ->select('subject_type', DB::raw('count(*) as count'), DB::raw('sum(balance) as total_balance'), 'currency') + ->groupBy('subject_type', 'currency') + ->get() + ->map(function ($row) { + $type = strtolower(class_basename($row->subject_type ?? '')); + return [ + 'type' => match (true) { + str_contains($type, 'driver') => 'driver', + str_contains($type, 'customer') => 'customer', + str_contains($type, 'company') => 'company', + default => $type, + }, + 'count' => (int) $row->count, + 'total_balance' => (int) $row->total_balance, + 'currency' => $row->currency, + ]; + }); + + // Period credits and debits + $periodStats = WalletTransaction::where('company_uuid', $companyUuid) + ->where('status', WalletTransaction::STATUS_COMPLETED) + ->whereBetween(DB::raw('DATE(created_at)'), [$dateFrom, $dateTo]) + ->select( + 'direction', + 'currency', + DB::raw('count(*) as count'), + DB::raw('sum(amount) as total') + ) + ->groupBy('direction', 'currency') + ->get() + ->groupBy('currency') + ->map(function ($rows) { + $result = ['credits' => 0, 'debits' => 0, 'credit_count' => 0, 'debit_count' => 0]; + foreach ($rows as $row) { + if ($row->direction === WalletTransaction::DIRECTION_CREDIT) { + $result['credits'] = (int) $row->total; + $result['credit_count'] = (int) $row->count; + } else { + $result['debits'] = (int) $row->total; + $result['debit_count'] = (int) $row->count; + } + } + return $result; + }); + + // Top 10 driver wallets by balance + $topDriverWallets = Wallet::where('company_uuid', $companyUuid) + ->where('subject_type', 'like', '%Driver%') + ->with('subject') + ->orderBy('balance', 'desc') + ->limit(10) + ->get() + ->map(fn ($w) => [ + 'wallet_public_id' => $w->public_id, + 'balance' => $w->balance, + 'formatted_balance' => $w->formatted_balance, + 'currency' => $w->currency, + 'subject' => $w->subject ? [ + 'name' => $w->subject->name ?? $w->subject->public_id ?? $w->subject->uuid, + ] : null, + ]); + + return response()->json([ + 'period' => [ + 'from' => $dateFrom, + 'to' => $dateTo, + ], + 'wallet_counts' => $walletCounts, + 'period_stats' => $periodStats, + 'top_driver_wallets' => $topDriverWallets, + ]); + } } diff --git a/server/src/Http/Controllers/Internal/v1/WalletController.php b/server/src/Http/Controllers/Internal/v1/WalletController.php index b45b1dd..bbf9e61 100644 --- a/server/src/Http/Controllers/Internal/v1/WalletController.php +++ b/server/src/Http/Controllers/Internal/v1/WalletController.php @@ -4,44 +4,70 @@ use Fleetbase\Http\Controllers\Controller; use Fleetbase\Ledger\Http\Resources\v1\Wallet as WalletResource; +use Fleetbase\Ledger\Http\Resources\v1\WalletTransaction as WalletTransactionResource; use Fleetbase\Ledger\Models\Wallet; +use Fleetbase\Ledger\Models\WalletTransaction; use Fleetbase\Ledger\Services\WalletService; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; - +use Illuminate\Http\Resources\Json\AnonymousResourceCollection; + +/** + * WalletController + * + * Handles all internal (authenticated) wallet operations for the Ledger extension. + * + * All monetary amounts in requests and responses are in the smallest currency + * unit (cents) unless otherwise noted. + * + * @package Fleetbase\Ledger\Http\Controllers\Internal\v1 + */ class WalletController extends Controller { /** * The resource to query. - * - * @var string */ public $resource = 'wallet'; /** * The model to query. - * - * @var \Fleetbase\Ledger\Models\Wallet */ public $model = Wallet::class; /** - * Query for wallets. + * The WalletService instance. + */ + protected WalletService $walletService; + + public function __construct(WalletService $walletService) + { + $this->walletService = $walletService; + } + + // ========================================================================= + // CRUD + // ========================================================================= + + /** + * Query wallets for the authenticated company. * - * @return \Illuminate\Http\Response + * Supports filtering by: status, subject_type, search (public_id) + * Supports sorting by any column. */ - public function query(Request $request) + public function query(Request $request): AnonymousResourceCollection { $results = Wallet::where('company_uuid', session('company')) ->with(['subject']) - ->when($request->filled('status'), function ($query) use ($request) { - $query->where('status', $request->input('status')); - }) - ->when($request->filled('subject_type'), function ($query) use ($request) { - $query->where('subject_type', $request->input('subject_type')); + ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) + ->when($request->filled('subject_type'), fn ($q) => $q->where('subject_type', $request->input('subject_type'))) + ->when($request->filled('type'), function ($q) use ($request) { + // Filter by inferred type (driver/customer/company) via subject_type LIKE + $type = $request->input('type'); + $q->where('subject_type', 'like', "%{$type}%"); }) - ->when($request->filled('search'), function ($query) use ($request) { + ->when($request->filled('search'), function ($q) use ($request) { $search = $request->input('search'); - $query->where('public_id', 'like', "%{$search}%"); + $q->where('public_id', 'like', "%{$search}%"); }) ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) ->paginate($request->input('limit', 15)); @@ -50,28 +76,22 @@ public function query(Request $request) } /** - * Find a single wallet. - * - * @return \Illuminate\Http\Response + * Find a single wallet by UUID or public_id. */ - public function find($id, Request $request) + public function find(string $id, Request $request): WalletResource { $wallet = Wallet::where('company_uuid', session('company')) ->with(['subject']) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) ->firstOrFail(); return new WalletResource($wallet); } /** - * Create a new wallet. - * - * @return \Illuminate\Http\Response + * Create a new wallet for a subject. */ - public function create(Request $request) + public function create(Request $request): WalletResource { $request->validate([ 'subject_uuid' => 'required|string', @@ -83,26 +103,20 @@ public function create(Request $request) 'company_uuid' => session('company'), 'subject_uuid' => $request->input('subject_uuid'), 'subject_type' => $request->input('subject_type'), - 'currency' => $request->input('currency', 'USD'), + 'currency' => strtoupper($request->input('currency', 'USD')), 'balance' => 0, - 'status' => 'active', + 'status' => Wallet::STATUS_ACTIVE, ]); return new WalletResource($wallet->load('subject')); } /** - * Update a wallet. - * - * @return \Illuminate\Http\Response + * Update wallet metadata (status only — balance changes go through dedicated endpoints). */ - public function update($id, Request $request) + public function update(string $id, Request $request): WalletResource { - $wallet = Wallet::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); + $wallet = $this->resolveWallet($id); $request->validate([ 'status' => 'sometimes|in:active,frozen,closed', @@ -110,126 +124,309 @@ public function update($id, Request $request) $wallet->update($request->only(['status'])); - return new WalletResource($wallet); + return new WalletResource($wallet->fresh('subject')); } /** - * Delete a wallet. - * - * @return \Illuminate\Http\Response + * Delete a wallet. Only allowed if balance is zero. */ - public function delete($id, Request $request) + public function delete(string $id, Request $request): JsonResponse { - $wallet = Wallet::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); + $wallet = $this->resolveWallet($id); - if ($wallet->balance != 0) { - return response()->json(['error' => 'Cannot delete wallet with non-zero balance'], 400); + if ($wallet->balance !== 0) { + return response()->json([ + 'error' => "Cannot delete wallet [{$wallet->public_id}] with non-zero balance ({$wallet->balance} {$wallet->currency}).", + ], 422); } $wallet->delete(); - return response()->json(['status' => 'ok']); + return response()->json(['status' => 'ok', 'message' => 'Wallet deleted successfully.']); } + // ========================================================================= + // Balance Operations + // ========================================================================= + /** - * Deposit funds into a wallet. + * Manually deposit funds into a wallet (operator action). * - * @return \Illuminate\Http\Response + * Request body: + * - amount (int, required) Amount in cents + * - description (string) + * - reference (string) Optional external reference */ - public function deposit($id, Request $request) + public function deposit(string $id, Request $request): JsonResponse { $request->validate([ 'amount' => 'required|integer|min:1', - 'description' => 'nullable|string', + 'description' => 'nullable|string|max:500', + 'reference' => 'nullable|string|max:191', ]); - $wallet = Wallet::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); + $wallet = $this->resolveWallet($id); + + try { + $transaction = $this->walletService->deposit( + wallet: $wallet, + amount: $request->integer('amount'), + description: $request->input('description', ''), + type: WalletTransaction::TYPE_DEPOSIT, + options: ['reference' => $request->input('reference')] + ); + + return response()->json([ + 'wallet' => new WalletResource($wallet->fresh()), + 'transaction' => new WalletTransactionResource($transaction), + ]); + } catch (\Exception $e) { + return response()->json(['error' => $e->getMessage()], 422); + } + } - $walletService = app(WalletService::class); - $wallet = $walletService->deposit( - $wallet, - $request->input('amount'), - $request->input('description', '') - ); + /** + * Manually withdraw funds from a wallet (operator action). + * + * Request body: + * - amount (int, required) Amount in cents + * - description (string) + * - reference (string) Optional external reference + */ + public function withdraw(string $id, Request $request): JsonResponse + { + $request->validate([ + 'amount' => 'required|integer|min:1', + 'description' => 'nullable|string|max:500', + 'reference' => 'nullable|string|max:191', + ]); - return new WalletResource($wallet); + $wallet = $this->resolveWallet($id); + + try { + $transaction = $this->walletService->withdraw( + wallet: $wallet, + amount: $request->integer('amount'), + description: $request->input('description', ''), + type: WalletTransaction::TYPE_WITHDRAWAL, + options: ['reference' => $request->input('reference')] + ); + + return response()->json([ + 'wallet' => new WalletResource($wallet->fresh()), + 'transaction' => new WalletTransactionResource($transaction), + ]); + } catch (\Exception $e) { + return response()->json(['error' => $e->getMessage()], 422); + } } /** - * Withdraw funds from a wallet. + * Transfer funds between two wallets. * - * @return \Illuminate\Http\Response + * Request body: + * - from_wallet (string, required) UUID or public_id of source wallet + * - to_wallet (string, required) UUID or public_id of destination wallet + * - amount (int, required) Amount in cents + * - description (string) */ - public function withdraw($id, Request $request) + public function transfer(Request $request): JsonResponse { $request->validate([ + 'from_wallet' => 'required|string', + 'to_wallet' => 'required|string', 'amount' => 'required|integer|min:1', - 'description' => 'nullable|string', + 'description' => 'nullable|string|max:500', ]); - $wallet = Wallet::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); + $fromWallet = $this->resolveWallet($request->input('from_wallet')); + $toWallet = $this->resolveWallet($request->input('to_wallet')); + + try { + $result = $this->walletService->transfer( + fromWallet: $fromWallet, + toWallet: $toWallet, + amount: $request->integer('amount'), + description: $request->input('description', '') + ); + + return response()->json([ + 'from_wallet' => new WalletResource($fromWallet->fresh()), + 'to_wallet' => new WalletResource($toWallet->fresh()), + 'from_transaction' => new WalletTransactionResource($result['from']), + 'to_transaction' => new WalletTransactionResource($result['to']), + ]); + } catch (\Exception $e) { + return response()->json(['error' => $e->getMessage()], 422); + } + } - $walletService = app(WalletService::class); - $wallet = $walletService->withdraw( - $wallet, - $request->input('amount'), - $request->input('description', '') - ); + /** + * Top up a wallet by charging a payment gateway. + * + * Request body: + * - gateway (string, required) Gateway UUID or public_id + * - amount (int, required) Amount in cents + * - description (string) + * - payment_method_token (string) Stripe payment method token (pm_xxx) + * - customer_id (string) Gateway customer ID + * - customer_email (string) + */ + public function topUp(string $id, Request $request): JsonResponse + { + $request->validate([ + 'gateway' => 'required|string', + 'amount' => 'required|integer|min:1', + 'description' => 'nullable|string|max:500', + 'payment_method_token' => 'nullable|string', + 'customer_id' => 'nullable|string', + 'customer_email' => 'nullable|email', + ]); - return new WalletResource($wallet); + $wallet = $this->resolveWallet($id); + + try { + $result = $this->walletService->topUp( + wallet: $wallet, + amount: $request->integer('amount'), + gatewayUuid: $request->input('gateway'), + paymentData: $request->only(['payment_method_token', 'customer_id', 'customer_email']), + description: $request->input('description', '') + ); + + $response = [ + 'wallet' => new WalletResource($result['wallet']), + 'gateway_response' => $result['gateway_response'], + ]; + + if ($result['transaction']) { + $response['transaction'] = new WalletTransactionResource($result['transaction']); + } + + return response()->json($response); + } catch (\Exception $e) { + return response()->json(['error' => $e->getMessage()], 422); + } } /** - * Transfer funds between wallets. + * Process a payout from a wallet (driver earnings withdrawal). * - * @return \Illuminate\Http\Response + * Request body: + * - amount (int, required) Amount in cents + * - description (string) + * - reference (string) Optional external reference (bank transfer ID, etc.) */ - public function transfer(Request $request) + public function payout(string $id, Request $request): JsonResponse { $request->validate([ - 'from_wallet' => 'required|string', - 'to_wallet' => 'required|string', 'amount' => 'required|integer|min:1', - 'description' => 'nullable|string', + 'description' => 'nullable|string|max:500', + 'reference' => 'nullable|string|max:191', ]); - $fromWallet = Wallet::where('company_uuid', session('company')) - ->where(function ($query) use ($request) { - $id = $request->input('from_wallet'); - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); + $wallet = $this->resolveWallet($id); + + try { + $transaction = $this->walletService->withdraw( + wallet: $wallet, + amount: $request->integer('amount'), + description: $request->input('description', 'Driver payout'), + type: WalletTransaction::TYPE_PAYOUT, + options: ['reference' => $request->input('reference')] + ); + + return response()->json([ + 'wallet' => new WalletResource($wallet->fresh()), + 'transaction' => new WalletTransactionResource($transaction), + ]); + } catch (\Exception $e) { + return response()->json(['error' => $e->getMessage()], 422); + } + } - $toWallet = Wallet::where('company_uuid', session('company')) - ->where(function ($query) use ($request) { - $id = $request->input('to_wallet'); - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); + // ========================================================================= + // Transaction History + // ========================================================================= - $walletService = app(WalletService::class); - $result = $walletService->transfer( - $fromWallet, - $toWallet, - $request->input('amount'), - $request->input('description', '') - ); + /** + * Get the transaction history for a wallet. + * + * Supports filtering by: type, direction, status, date_from, date_to + * Supports pagination via limit/page. + */ + public function getTransactions(string $id, Request $request): AnonymousResourceCollection + { + $wallet = $this->resolveWallet($id); + + $transactions = WalletTransaction::where('wallet_uuid', $wallet->uuid) + ->when($request->filled('type'), fn ($q) => $q->where('type', $request->input('type'))) + ->when($request->filled('direction'), fn ($q) => $q->where('direction', $request->input('direction'))) + ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) + ->when($request->filled('date_from'), fn ($q) => $q->whereDate('created_at', '>=', $request->input('date_from'))) + ->when($request->filled('date_to'), fn ($q) => $q->whereDate('created_at', '<=', $request->input('date_to'))) + ->orderBy('created_at', 'desc') + ->paginate($request->input('limit', 25)); + + return WalletTransactionResource::collection($transactions); + } + + // ========================================================================= + // State Management + // ========================================================================= + + /** + * Freeze a wallet. Debits are blocked; credits are still accepted. + */ + public function freeze(string $id, Request $request): WalletResource + { + $wallet = $this->resolveWallet($id); + $wallet->freeze(); + + return new WalletResource($wallet->fresh()); + } + + /** + * Unfreeze (activate) a wallet. + */ + public function unfreeze(string $id, Request $request): WalletResource + { + $wallet = $this->resolveWallet($id); + $wallet->activate(); + + return new WalletResource($wallet->fresh()); + } + + /** + * Recalculate and correct a wallet's balance from its transaction history. + * This is a reconciliation utility for operators. + */ + public function recalculate(string $id, Request $request): JsonResponse + { + $wallet = $this->resolveWallet($id); + + $oldBalance = $wallet->balance; + $newBalance = $this->walletService->recalculateBalance($wallet); return response()->json([ - 'from_wallet' => new WalletResource($result['from_wallet']), - 'to_wallet' => new WalletResource($result['to_wallet']), + 'wallet' => new WalletResource($wallet->fresh()), + 'old_balance' => $oldBalance, + 'new_balance' => $newBalance, + 'corrected' => $oldBalance !== $newBalance, ]); } + + // ========================================================================= + // Private Helpers + // ========================================================================= + + /** + * Resolve a wallet by UUID or public_id, scoped to the authenticated company. + */ + protected function resolveWallet(string $id): Wallet + { + return Wallet::where('company_uuid', session('company')) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) + ->firstOrFail(); + } } diff --git a/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php b/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php new file mode 100644 index 0000000..a406297 --- /dev/null +++ b/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php @@ -0,0 +1,62 @@ +with(['wallet', 'subject']) + ->when($request->filled('wallet'), fn ($q) => $q->where('wallet_uuid', $request->input('wallet'))) + ->when($request->filled('type'), fn ($q) => $q->where('type', $request->input('type'))) + ->when($request->filled('direction'), fn ($q) => $q->where('direction', $request->input('direction'))) + ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) + ->when($request->filled('date_from'), fn ($q) => $q->whereDate('created_at', '>=', $request->input('date_from'))) + ->when($request->filled('date_to'), fn ($q) => $q->whereDate('created_at', '<=', $request->input('date_to'))) + ->when($request->filled('search'), function ($q) use ($request) { + $search = $request->input('search'); + $q->where(function ($inner) use ($search) { + $inner->where('public_id', 'like', "%{$search}%") + ->orWhere('description', 'like', "%{$search}%") + ->orWhere('reference', 'like', "%{$search}%"); + }); + }) + ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) + ->paginate($request->input('limit', 25)); + + return WalletTransactionResource::collection($results); + } + + /** + * Find a single wallet transaction by UUID or public_id. + */ + public function find(string $id, Request $request): WalletTransactionResource + { + $transaction = WalletTransaction::where('company_uuid', session('company')) + ->with(['wallet', 'subject']) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) + ->firstOrFail(); + + return new WalletTransactionResource($transaction); + } +} diff --git a/server/src/Http/Resources/v1/Wallet.php b/server/src/Http/Resources/v1/Wallet.php index 3cc6845..222bd6a 100644 --- a/server/src/Http/Resources/v1/Wallet.php +++ b/server/src/Http/Resources/v1/Wallet.php @@ -24,10 +24,12 @@ public function toArray($request) 'subject_uuid' => $this->subject_uuid, 'subject_type' => $this->subject_type, 'subject' => $this->whenLoaded('subject'), - 'balance' => $this->balance, - 'currency' => $this->currency, - 'status' => $this->status, - 'meta' => $this->meta, + 'type' => $this->type, + 'balance' => $this->balance, + 'formatted_balance' => $this->formatted_balance, + 'currency' => $this->currency, + 'status' => $this->status, + 'meta' => $this->meta, 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; diff --git a/server/src/Http/Resources/v1/WalletTransaction.php b/server/src/Http/Resources/v1/WalletTransaction.php new file mode 100644 index 0000000..b6e6ed6 --- /dev/null +++ b/server/src/Http/Resources/v1/WalletTransaction.php @@ -0,0 +1,52 @@ + $this->when(Http::isInternalRequest(), $this->id, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->public_id, + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), + 'wallet_uuid' => $this->when(Http::isInternalRequest(), $this->wallet_uuid), + 'wallet' => $this->whenLoaded('wallet'), + 'type' => $this->type, + 'direction' => $this->direction, + 'status' => $this->status, + 'amount' => $this->amount, + 'formatted_amount' => $this->formatted_amount, + 'balance_after' => $this->balance_after, + 'currency' => $this->currency, + 'description' => $this->description, + 'reference' => $this->reference, + 'subject_uuid' => $this->when(Http::isInternalRequest(), $this->subject_uuid), + 'subject_type' => $this->when(Http::isInternalRequest(), $this->subject_type), + 'subject' => $this->whenLoaded('subject'), + 'meta' => $this->meta, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/Models/Wallet.php b/server/src/Models/Wallet.php index f47e6e3..3ff4a3f 100644 --- a/server/src/Models/Wallet.php +++ b/server/src/Models/Wallet.php @@ -11,9 +11,41 @@ use Fleetbase\Traits\HasUuid; use Fleetbase\Traits\Searchable; use Fleetbase\Traits\TracksApiCredential; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Wallet + * + * Represents a digital wallet belonging to any subject in the Fleetbase system. + * Wallets are polymorphic — they can belong to a Driver, Customer, or Company. + * + * Balance is always stored as an integer in the smallest currency unit (cents). + * Every balance change MUST produce a corresponding WalletTransaction record. + * + * Wallet types (inferred from subject_type): + * - driver : Earnings wallet for FleetOps drivers + * - customer : Prepaid credit wallet for Storefront customers + * - company : Company operating wallet (e.g., for payouts) + * + * Statuses: + * - active : Normal operation + * - frozen : No debits allowed (credits still accepted) + * - closed : No operations allowed + * + * @property string $uuid + * @property string $public_id + * @property string $company_uuid + * @property string $subject_uuid + * @property string $subject_type + * @property int $balance Balance in smallest currency unit (cents) + * @property string $currency + * @property string $status 'active', 'frozen', 'closed' + * @property array $meta + * + * @package Fleetbase\Ledger\Models + */ class Wallet extends Model { use HasUuid; @@ -26,29 +58,21 @@ class Wallet extends Model /** * The database table used by the model. - * - * @var string */ protected $table = 'ledger_wallets'; /** * The type of public Id to generate. - * - * @var string */ protected $publicIdType = 'wallet'; /** * The attributes that can be queried. - * - * @var array */ protected $searchableColumns = ['public_id']; /** * The attributes that are mass assignable. - * - * @var array */ protected $fillable = [ '_key', @@ -66,8 +90,6 @@ class Wallet extends Model /** * The attributes that should be cast to native types. - * - * @var array */ protected $casts = [ 'balance' => 'integer', @@ -77,77 +99,265 @@ class Wallet extends Model /** * Dynamic attributes that are appended to object. - * - * @var array */ - protected $appends = []; + protected $appends = ['public_id', 'type', 'formatted_balance']; - /** - * The attributes excluded from the model's JSON form. - * - * @var array - */ - protected $hidden = []; + // ------------------------------------------------------------------------- + // Status Constants + // ------------------------------------------------------------------------- + + public const STATUS_ACTIVE = 'active'; + public const STATUS_FROZEN = 'frozen'; + public const STATUS_CLOSED = 'closed'; + + // ------------------------------------------------------------------------- + // Relationships + // ------------------------------------------------------------------------- /** * The subject (owner) of this wallet. + * Uses 'subject' naming convention per Fleetbase standards. + * + * Can be: Driver, Customer, Company, or any other polymorphic subject. */ public function subject(): MorphTo { return $this->morphTo(__FUNCTION__, 'subject_type', 'subject_uuid')->withoutGlobalScopes(); } + /** + * All transactions on this wallet. + */ + public function transactions(): HasMany + { + return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') + ->orderBy('created_at', 'desc'); + } + + /** + * Completed transactions only. + */ + public function completedTransactions(): HasMany + { + return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') + ->where('status', WalletTransaction::STATUS_COMPLETED) + ->orderBy('created_at', 'desc'); + } + + /** + * Credit transactions only (money in). + */ + public function credits(): HasMany + { + return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') + ->where('direction', WalletTransaction::DIRECTION_CREDIT) + ->where('status', WalletTransaction::STATUS_COMPLETED); + } + + /** + * Debit transactions only (money out). + */ + public function debits(): HasMany + { + return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') + ->where('direction', WalletTransaction::DIRECTION_DEBIT) + ->where('status', WalletTransaction::STATUS_COMPLETED); + } + + // ------------------------------------------------------------------------- + // Computed Attributes + // ------------------------------------------------------------------------- + + /** + * Infer the wallet type from the subject_type. + * Returns 'driver', 'customer', 'company', or 'unknown'. + */ + public function getTypeAttribute(): string + { + if (!$this->subject_type) { + return 'unknown'; + } + + $type = strtolower(class_basename($this->subject_type)); + + return match (true) { + str_contains($type, 'driver') => 'driver', + str_contains($type, 'customer') => 'customer', + str_contains($type, 'company') => 'company', + str_contains($type, 'user') => 'user', + default => $type, + }; + } + + /** + * Get the balance formatted as a decimal string. + * e.g., 1050 cents → "10.50" + */ + public function getFormattedBalanceAttribute(): string + { + return number_format($this->balance / 100, 2); + } + + // ------------------------------------------------------------------------- + // Status Helpers + // ------------------------------------------------------------------------- + /** * Check if the wallet is active. - * - * @return bool */ public function isActive(): bool { - return $this->status === 'active'; + return $this->status === self::STATUS_ACTIVE; } /** * Check if the wallet is frozen. - * - * @return bool */ public function isFrozen(): bool { - return $this->status === 'frozen'; + return $this->status === self::STATUS_FROZEN; } /** - * Check if the wallet has sufficient balance. - * - * @param int $amount + * Check if the wallet is closed. + */ + public function isClosed(): bool + { + return $this->status === self::STATUS_CLOSED; + } + + /** + * Check if the wallet can accept debits (withdrawals, transfers out). + * Frozen wallets can still receive credits. + */ + public function canDebit(): bool + { + return $this->status === self::STATUS_ACTIVE; + } + + /** + * Check if the wallet can accept credits (deposits, transfers in). + */ + public function canCredit(): bool + { + return in_array($this->status, [self::STATUS_ACTIVE, self::STATUS_FROZEN], true); + } + + /** + * Check if the wallet has sufficient balance for a given amount. * - * @return bool + * @param int $amount Amount in smallest currency unit (cents) */ public function hasSufficientBalance(int $amount): bool { return $this->balance >= $amount; } + // ------------------------------------------------------------------------- + // State Transitions + // ------------------------------------------------------------------------- + /** - * Freeze the wallet. - * - * @return void + * Freeze the wallet. Debits are blocked; credits are still accepted. */ public function freeze(): void { - $this->status = 'frozen'; - $this->save(); + $this->update(['status' => self::STATUS_FROZEN]); } /** - * Activate the wallet. - * - * @return void + * Activate (unfreeze) the wallet. */ public function activate(): void { - $this->status = 'active'; - $this->save(); + $this->update(['status' => self::STATUS_ACTIVE]); + } + + /** + * Close the wallet. No operations are allowed. + */ + public function close(): void + { + $this->update(['status' => self::STATUS_CLOSED]); + } + + // ------------------------------------------------------------------------- + // Balance Operations (low-level — use WalletService for full lifecycle) + // ------------------------------------------------------------------------- + + /** + * Credit the wallet balance by the given amount and return the new balance. + * This method ONLY updates the balance column. Callers MUST also create + * a WalletTransaction record to maintain the audit trail. + * + * @param int $amount Amount in smallest currency unit (cents) + * + * @return int New balance + */ + public function credit(int $amount): int + { + $this->increment('balance', $amount); + $this->refresh(); + + return $this->balance; + } + + /** + * Debit the wallet balance by the given amount and return the new balance. + * This method ONLY updates the balance column. Callers MUST also create + * a WalletTransaction record to maintain the audit trail. + * + * @param int $amount Amount in smallest currency unit (cents) + * + * @throws \RuntimeException if the wallet has insufficient balance + * + * @return int New balance + */ + public function debit(int $amount): int + { + if (!$this->hasSufficientBalance($amount)) { + throw new \RuntimeException( + "Insufficient wallet balance. Available: {$this->balance}, Required: {$amount}." + ); + } + + $this->decrement('balance', $amount); + $this->refresh(); + + return $this->balance; + } + + // ------------------------------------------------------------------------- + // Static Factories + // ------------------------------------------------------------------------- + + /** + * Find or create a wallet for a given subject. + * + * @param string $subjectUuid + * @param string $subjectType Fully-qualified class name + * @param string $companyUuid + * @param string $currency + * + * @return static + */ + public static function forSubject( + string $subjectUuid, + string $subjectType, + string $companyUuid, + string $currency = 'USD' + ): static { + return static::firstOrCreate( + [ + 'subject_uuid' => $subjectUuid, + 'subject_type' => $subjectType, + ], + [ + 'company_uuid' => $companyUuid, + 'balance' => 0, + 'currency' => $currency, + 'status' => self::STATUS_ACTIVE, + ] + ); } } diff --git a/server/src/Models/WalletTransaction.php b/server/src/Models/WalletTransaction.php new file mode 100644 index 0000000..80fb137 --- /dev/null +++ b/server/src/Models/WalletTransaction.php @@ -0,0 +1,236 @@ + 'integer', + 'balance_after' => 'integer', + 'meta' => 'array', + ]; + + /** + * The attributes that should be appended. + */ + protected $appends = ['public_id']; + + // ------------------------------------------------------------------------- + // Transaction Type Constants + // ------------------------------------------------------------------------- + + public const TYPE_DEPOSIT = 'deposit'; + public const TYPE_WITHDRAWAL = 'withdrawal'; + public const TYPE_TRANSFER_IN = 'transfer_in'; + public const TYPE_TRANSFER_OUT = 'transfer_out'; + public const TYPE_PAYOUT = 'payout'; + public const TYPE_FEE = 'fee'; + public const TYPE_REFUND = 'refund'; + public const TYPE_ADJUSTMENT = 'adjustment'; + public const TYPE_EARNING = 'earning'; + + // ------------------------------------------------------------------------- + // Direction Constants + // ------------------------------------------------------------------------- + + public const DIRECTION_CREDIT = 'credit'; + public const DIRECTION_DEBIT = 'debit'; + + // ------------------------------------------------------------------------- + // Status Constants + // ------------------------------------------------------------------------- + + public const STATUS_PENDING = 'pending'; + public const STATUS_COMPLETED = 'completed'; + public const STATUS_FAILED = 'failed'; + public const STATUS_REVERSED = 'reversed'; + + // ------------------------------------------------------------------------- + // Relationships + // ------------------------------------------------------------------------- + + /** + * The wallet this transaction belongs to. + */ + public function wallet(): BelongsTo + { + return $this->belongsTo(Wallet::class, 'wallet_uuid', 'uuid'); + } + + /** + * The gateway transaction that triggered this wallet transaction (if any). + */ + public function gatewayTransaction(): BelongsTo + { + return $this->belongsTo(GatewayTransaction::class, 'gateway_transaction_uuid', 'uuid'); + } + + /** + * Polymorphic subject — the entity this transaction relates to. + * Uses the 'subject' naming convention per Fleetbase standards. + * + * Can be: Driver, Customer, Order, Invoice, etc. + */ + public function subject(): MorphTo + { + return $this->morphTo(__FUNCTION__, 'subject_type', 'subject_uuid'); + } + + // ------------------------------------------------------------------------- + // Scopes + // ------------------------------------------------------------------------- + + /** + * Scope to credits only. + */ + public function scopeCredits($query) + { + return $query->where('direction', self::DIRECTION_CREDIT); + } + + /** + * Scope to debits only. + */ + public function scopeDebits($query) + { + return $query->where('direction', self::DIRECTION_DEBIT); + } + + /** + * Scope to completed transactions only. + */ + public function scopeCompleted($query) + { + return $query->where('status', self::STATUS_COMPLETED); + } + + /** + * Scope to a specific type. + */ + public function scopeOfType($query, string $type) + { + return $query->where('type', $type); + } + + // ------------------------------------------------------------------------- + // Helpers + // ------------------------------------------------------------------------- + + /** + * Get the amount formatted as a decimal string. + * e.g., 1050 cents → "10.50" + */ + public function getFormattedAmountAttribute(): string + { + return number_format($this->amount / 100, 2); + } + + /** + * Whether this transaction is a credit (money in). + */ + public function isCredit(): bool + { + return $this->direction === self::DIRECTION_CREDIT; + } + + /** + * Whether this transaction is a debit (money out). + */ + public function isDebit(): bool + { + return $this->direction === self::DIRECTION_DEBIT; + } + + /** + * Whether this transaction has completed. + */ + public function isCompleted(): bool + { + return $this->status === self::STATUS_COMPLETED; + } +} diff --git a/server/src/Services/WalletService.php b/server/src/Services/WalletService.php index d4e8ddf..574aff8 100644 --- a/server/src/Services/WalletService.php +++ b/server/src/Services/WalletService.php @@ -2,85 +2,134 @@ namespace Fleetbase\Ledger\Services; +use Fleetbase\Ledger\DTO\PurchaseRequest; use Fleetbase\Ledger\Models\Account; use Fleetbase\Ledger\Models\Wallet; +use Fleetbase\Ledger\Models\WalletTransaction; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +/** + * WalletService + * + * Manages all wallet lifecycle operations for the Ledger extension. + * + * This service is the single entry point for all wallet operations. + * Every balance change MUST go through this service to ensure: + * 1. Correct double-entry journal entries are created + * 2. WalletTransaction audit records are persisted + * 3. Wallet balance is updated atomically within a DB transaction + * + * Monetary values are always in the smallest currency unit (cents). + * + * @package Fleetbase\Ledger\Services + */ class WalletService { /** * The ledger service instance. - * - * @var LedgerService */ protected LedgerService $ledgerService; /** - * Create a new WalletService instance. - * - * @param LedgerService $ledgerService + * The payment service instance (lazy-resolved to avoid circular deps). */ + protected ?PaymentService $paymentService = null; + public function __construct(LedgerService $ledgerService) { $this->ledgerService = $ledgerService; } + // ========================================================================= + // Provisioning + // ========================================================================= + /** - * Get or create a wallet for a subject. + * Get or create a wallet for any subject (driver, customer, company, etc.). * - * @param Model $subject - * @param string $currency + * This is the primary auto-provisioning method. Call this whenever you need + * a wallet for a subject and don't know if one exists yet. + * + * @param Model $subject Any Eloquent model with a uuid and company_uuid + * @param string $currency ISO 4217 currency code (default: USD) * * @return Wallet */ public function getOrCreateWallet(Model $subject, string $currency = 'USD'): Wallet { - return Wallet::firstOrCreate( - [ - 'subject_uuid' => $subject->uuid, - 'subject_type' => get_class($subject), - ], - [ - 'company_uuid' => $subject->company_uuid ?? session('company'), - 'currency' => $currency, - 'balance' => 0, - 'status' => 'active', - ] + return Wallet::forSubject( + subjectUuid: $subject->uuid, + subjectType: get_class($subject), + companyUuid: $subject->company_uuid ?? session('company'), + currency: $currency, ); } /** - * Deposit funds into a wallet. + * Provision wallets for a batch of subjects. + * Useful for seeding wallets for all existing drivers or customers. + * + * @param iterable $subjects Collection of Eloquent models + * @param string $currency + * + * @return array + */ + public function provisionBatch(iterable $subjects, string $currency = 'USD'): array + { + $wallets = []; + foreach ($subjects as $subject) { + $wallets[] = $this->getOrCreateWallet($subject, $currency); + } + + return $wallets; + } + + // ========================================================================= + // Deposit + // ========================================================================= + + /** + * Deposit funds into a wallet from an internal source (e.g., manual credit, earning). * - * Correct double-entry accounting treatment for a wallet deposit: + * Double-entry accounting: * DEBIT Cash / Source Account (asset increases — money received) * CREDIT Wallet Liability (liability increases — we owe more to wallet holder) * - * @param Wallet $wallet - * @param int $amount Amount in smallest currency unit (e.g. cents) - * @param string $description - * @param array $options + * @param Wallet $wallet + * @param int $amount Amount in smallest currency unit (cents) + * @param string $description + * @param string $type WalletTransaction type (default: 'deposit') + * @param array $options Optional: source_account, reference, subject, meta, gateway_transaction_uuid * - * @return Wallet + * @return WalletTransaction + * + * @throws \Exception if wallet is not active or cannot credit */ - public function deposit(Wallet $wallet, int $amount, string $description = '', array $options = []): Wallet - { - if (!$wallet->isActive()) { - throw new \Exception('Wallet is not active'); + public function deposit( + Wallet $wallet, + int $amount, + string $description = '', + string $type = WalletTransaction::TYPE_DEPOSIT, + array $options = [] + ): WalletTransaction { + if (!$wallet->canCredit()) { + throw new \Exception("Wallet [{$wallet->public_id}] cannot accept credits (status: {$wallet->status})."); } - return DB::transaction(function () use ($wallet, $amount, $description, $options) { - // Debit: Cash / source account (asset increases — money received) - $cashAccount = $options['source_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); + if ($amount <= 0) { + throw new \InvalidArgumentException('Deposit amount must be greater than zero.'); + } - // Credit: Wallet liability account (liability increases — we owe more to the wallet holder) + return DB::transaction(function () use ($wallet, $amount, $description, $type, $options) { + // Double-entry: DEBIT Cash, CREDIT Wallet Liability + $cashAccount = $options['source_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); $walletAccount = $this->getWalletAccount($wallet); - // DEBIT Cash, CREDIT Wallet Liability $this->ledgerService->createJournalEntry( - $cashAccount, // debit — asset increases - $walletAccount, // credit — liability increases + $cashAccount, + $walletAccount, $amount, $description ?: "Deposit to wallet {$wallet->public_id}", array_merge($options, [ @@ -91,48 +140,88 @@ public function deposit(Wallet $wallet, int $amount, string $description = '', a ); // Update wallet balance - $wallet->balance += $amount; - $wallet->save(); + $newBalance = $wallet->credit($amount); + + // Create WalletTransaction audit record + $transaction = WalletTransaction::create([ + 'company_uuid' => $wallet->company_uuid, + 'wallet_uuid' => $wallet->uuid, + 'gateway_transaction_uuid' => $options['gateway_transaction_uuid'] ?? null, + 'type' => $type, + 'direction' => WalletTransaction::DIRECTION_CREDIT, + 'status' => WalletTransaction::STATUS_COMPLETED, + 'amount' => $amount, + 'balance_after' => $newBalance, + 'currency' => $wallet->currency, + 'description' => $description ?: "Deposit to wallet {$wallet->public_id}", + 'reference' => $options['reference'] ?? null, + 'subject_uuid' => $options['subject_uuid'] ?? null, + 'subject_type' => $options['subject_type'] ?? null, + 'meta' => $options['meta'] ?? null, + ]); - return $wallet; + Log::channel('ledger')->info("Wallet deposit completed.", [ + 'wallet_uuid' => $wallet->uuid, + 'amount' => $amount, + 'new_balance' => $newBalance, + 'transaction_id' => $transaction->public_id, + ]); + + return $transaction; }); } + // ========================================================================= + // Withdrawal + // ========================================================================= + /** - * Withdraw funds from a wallet. + * Withdraw funds from a wallet to an external destination. * - * Correct double-entry accounting treatment for a wallet withdrawal: + * Double-entry accounting: * DEBIT Wallet Liability (liability decreases — we owe less to wallet holder) * CREDIT Cash / Dest Account (asset decreases — money paid out) * - * @param Wallet $wallet - * @param int $amount Amount in smallest currency unit (e.g. cents) - * @param string $description - * @param array $options + * @param Wallet $wallet + * @param int $amount Amount in smallest currency unit (cents) + * @param string $description + * @param string $type WalletTransaction type (default: 'withdrawal') + * @param array $options Optional: destination_account, reference, subject, meta * - * @return Wallet + * @return WalletTransaction + * + * @throws \Exception if wallet cannot debit or has insufficient balance */ - public function withdraw(Wallet $wallet, int $amount, string $description = '', array $options = []): Wallet - { - if (!$wallet->isActive()) { - throw new \Exception('Wallet is not active'); + public function withdraw( + Wallet $wallet, + int $amount, + string $description = '', + string $type = WalletTransaction::TYPE_WITHDRAWAL, + array $options = [] + ): WalletTransaction { + if (!$wallet->canDebit()) { + throw new \Exception("Wallet [{$wallet->public_id}] cannot be debited (status: {$wallet->status})."); } if (!$wallet->hasSufficientBalance($amount)) { - throw new \Exception('Insufficient wallet balance'); + throw new \Exception( + "Insufficient balance in wallet [{$wallet->public_id}]. " . + "Available: {$wallet->balance}, Required: {$amount}." + ); } - return DB::transaction(function () use ($wallet, $amount, $description, $options) { - // Debit: Wallet liability account (liability decreases — we owe less to the wallet holder) - $walletAccount = $this->getWalletAccount($wallet); + if ($amount <= 0) { + throw new \InvalidArgumentException('Withdrawal amount must be greater than zero.'); + } - // Credit: Cash / destination account (asset decreases — money paid out) - $cashAccount = $options['destination_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); + return DB::transaction(function () use ($wallet, $amount, $description, $type, $options) { + // Double-entry: DEBIT Wallet Liability, CREDIT Cash + $walletAccount = $this->getWalletAccount($wallet); + $cashAccount = $options['destination_account'] ?? $this->getDefaultCashAccount($wallet->company_uuid); - // DEBIT Wallet Liability, CREDIT Cash $this->ledgerService->createJournalEntry( - $walletAccount, // debit — liability decreases - $cashAccount, // credit — asset decreases + $walletAccount, + $cashAccount, $amount, $description ?: "Withdrawal from wallet {$wallet->public_id}", array_merge($options, [ @@ -143,51 +232,96 @@ public function withdraw(Wallet $wallet, int $amount, string $description = '', ); // Update wallet balance - $wallet->balance -= $amount; - $wallet->save(); + $newBalance = $wallet->debit($amount); - return $wallet; + // Create WalletTransaction audit record + $transaction = WalletTransaction::create([ + 'company_uuid' => $wallet->company_uuid, + 'wallet_uuid' => $wallet->uuid, + 'gateway_transaction_uuid' => $options['gateway_transaction_uuid'] ?? null, + 'type' => $type, + 'direction' => WalletTransaction::DIRECTION_DEBIT, + 'status' => WalletTransaction::STATUS_COMPLETED, + 'amount' => $amount, + 'balance_after' => $newBalance, + 'currency' => $wallet->currency, + 'description' => $description ?: "Withdrawal from wallet {$wallet->public_id}", + 'reference' => $options['reference'] ?? null, + 'subject_uuid' => $options['subject_uuid'] ?? null, + 'subject_type' => $options['subject_type'] ?? null, + 'meta' => $options['meta'] ?? null, + ]); + + Log::channel('ledger')->info("Wallet withdrawal completed.", [ + 'wallet_uuid' => $wallet->uuid, + 'amount' => $amount, + 'new_balance' => $newBalance, + 'transaction_id' => $transaction->public_id, + ]); + + return $transaction; }); } + // ========================================================================= + // Transfer + // ========================================================================= + /** - * Transfer funds between two wallets. + * Transfer funds between two wallets within the system. * - * Correct double-entry accounting treatment for a wallet-to-wallet transfer: + * Double-entry accounting: * DEBIT From Wallet Liability (source liability decreases — we owe less to source holder) * CREDIT To Wallet Liability (destination liability increases — we owe more to dest holder) * * @param Wallet $fromWallet * @param Wallet $toWallet - * @param int $amount Amount in smallest currency unit (e.g. cents) + * @param int $amount Amount in smallest currency unit (cents) * @param string $description * @param array $options * - * @return array + * @return array{from: WalletTransaction, to: WalletTransaction} + * + * @throws \Exception if either wallet cannot operate or source has insufficient balance */ - public function transfer(Wallet $fromWallet, Wallet $toWallet, int $amount, string $description = '', array $options = []): array - { - if (!$fromWallet->isActive() || !$toWallet->isActive()) { - throw new \Exception('One or both wallets are not active'); + public function transfer( + Wallet $fromWallet, + Wallet $toWallet, + int $amount, + string $description = '', + array $options = [] + ): array { + if (!$fromWallet->canDebit()) { + throw new \Exception("Source wallet [{$fromWallet->public_id}] cannot be debited."); + } + + if (!$toWallet->canCredit()) { + throw new \Exception("Destination wallet [{$toWallet->public_id}] cannot accept credits."); } if (!$fromWallet->hasSufficientBalance($amount)) { - throw new \Exception('Insufficient balance in source wallet'); + throw new \Exception( + "Insufficient balance in source wallet [{$fromWallet->public_id}]. " . + "Available: {$fromWallet->balance}, Required: {$amount}." + ); + } + + if ($amount <= 0) { + throw new \InvalidArgumentException('Transfer amount must be greater than zero.'); } return DB::transaction(function () use ($fromWallet, $toWallet, $amount, $description, $options) { - // Debit: From wallet liability (source liability decreases — we owe less to source holder) - $fromAccount = $this->getWalletAccount($fromWallet); + $desc = $description ?: "Transfer from {$fromWallet->public_id} to {$toWallet->public_id}"; - // Credit: To wallet liability (destination liability increases — we owe more to dest holder) - $toAccount = $this->getWalletAccount($toWallet); + // Double-entry: DEBIT From Wallet Liability, CREDIT To Wallet Liability + $fromAccount = $this->getWalletAccount($fromWallet); + $toAccount = $this->getWalletAccount($toWallet); - // DEBIT From Wallet Liability, CREDIT To Wallet Liability - $journal = $this->ledgerService->createJournalEntry( - $fromAccount, // debit — source liability decreases - $toAccount, // credit — destination liability increases + $this->ledgerService->createJournalEntry( + $fromAccount, + $toAccount, $amount, - $description ?: "Transfer from wallet {$fromWallet->public_id} to {$toWallet->public_id}", + $desc, array_merge($options, [ 'company_uuid' => $fromWallet->company_uuid, 'currency' => $fromWallet->currency, @@ -195,30 +329,269 @@ public function transfer(Wallet $fromWallet, Wallet $toWallet, int $amount, stri ]) ); - // Update wallet balances - $fromWallet->balance -= $amount; - $fromWallet->save(); + // Update balances + $fromNewBalance = $fromWallet->debit($amount); + $toNewBalance = $toWallet->credit($amount); + + // Create WalletTransaction records for both sides + $reference = $options['reference'] ?? null; + + $fromTransaction = WalletTransaction::create([ + 'company_uuid' => $fromWallet->company_uuid, + 'wallet_uuid' => $fromWallet->uuid, + 'type' => WalletTransaction::TYPE_TRANSFER_OUT, + 'direction' => WalletTransaction::DIRECTION_DEBIT, + 'status' => WalletTransaction::STATUS_COMPLETED, + 'amount' => $amount, + 'balance_after' => $fromNewBalance, + 'currency' => $fromWallet->currency, + 'description' => $desc, + 'reference' => $reference, + 'meta' => array_merge($options['meta'] ?? [], [ + 'to_wallet_uuid' => $toWallet->uuid, + 'to_wallet_public_id' => $toWallet->public_id, + ]), + ]); + + $toTransaction = WalletTransaction::create([ + 'company_uuid' => $toWallet->company_uuid, + 'wallet_uuid' => $toWallet->uuid, + 'type' => WalletTransaction::TYPE_TRANSFER_IN, + 'direction' => WalletTransaction::DIRECTION_CREDIT, + 'status' => WalletTransaction::STATUS_COMPLETED, + 'amount' => $amount, + 'balance_after' => $toNewBalance, + 'currency' => $toWallet->currency, + 'description' => $desc, + 'reference' => $reference, + 'meta' => array_merge($options['meta'] ?? [], [ + 'from_wallet_uuid' => $fromWallet->uuid, + 'from_wallet_public_id' => $fromWallet->public_id, + ]), + ]); - $toWallet->balance += $amount; - $toWallet->save(); + Log::channel('ledger')->info("Wallet transfer completed.", [ + 'from_wallet' => $fromWallet->uuid, + 'to_wallet' => $toWallet->uuid, + 'amount' => $amount, + ]); return [ - 'from_wallet' => $fromWallet, - 'to_wallet' => $toWallet, - 'journal' => $journal, + 'from' => $fromTransaction, + 'to' => $toTransaction, ]; }); } + // ========================================================================= + // Top-Up via Payment Gateway + // ========================================================================= + /** - * Get or create the ledger liability account for a wallet. + * Top up a wallet by charging a payment gateway. * - * Each wallet has its own dedicated liability account in the chart of accounts. - * This account represents the amount the company owes to the wallet holder. + * This method: + * 1. Initiates a charge via the PaymentService + * 2. On success, deposits the amount into the wallet + * 3. Links the GatewayTransaction to the WalletTransaction + * + * For asynchronous gateways (QPay), the wallet is credited when the + * PaymentSucceeded event fires via the HandleSuccessfulPayment listener. + * For synchronous gateways (Stripe confirmed, Cash), the wallet is + * credited immediately. * * @param Wallet $wallet + * @param int $amount Amount in smallest currency unit (cents) + * @param string $gatewayUuid UUID or public_id of the gateway to charge + * @param array $paymentData Payment data (payment_method_token, customer_id, etc.) + * @param string $description * - * @return Account + * @return array{wallet: Wallet, transaction: WalletTransaction|null, gateway_response: GatewayResponse} + */ + public function topUp( + Wallet $wallet, + int $amount, + string $gatewayUuid, + array $paymentData = [], + string $description = '' + ): array { + $paymentService = $this->resolvePaymentService(); + + $purchaseRequest = new PurchaseRequest( + amount: $amount, + currency: $wallet->currency, + description: $description ?: "Wallet top-up: {$wallet->public_id}", + paymentMethodToken: $paymentData['payment_method_token'] ?? null, + customerId: $paymentData['customer_id'] ?? null, + customerEmail: $paymentData['customer_email'] ?? null, + metadata: array_merge($paymentData['metadata'] ?? [], [ + 'wallet_uuid' => $wallet->uuid, + 'wallet_public_id' => $wallet->public_id, + ]), + ); + + $gatewayResponse = $paymentService->charge($gatewayUuid, $purchaseRequest); + + $walletTransaction = null; + + // For synchronous success (Stripe confirmed, Cash), credit immediately + if ($gatewayResponse->isSuccessful() && $gatewayResponse->status === \Fleetbase\Ledger\DTO\GatewayResponse::STATUS_SUCCEEDED) { + // Find the persisted GatewayTransaction + $gatewayTransaction = \Fleetbase\Ledger\Models\GatewayTransaction::where( + 'gateway_reference_id', $gatewayResponse->gatewayTransactionId + )->latest()->first(); + + $walletTransaction = $this->deposit( + wallet: $wallet, + amount: $amount, + description: $description ?: "Top-up via payment gateway", + type: WalletTransaction::TYPE_DEPOSIT, + options: [ + 'reference' => $gatewayResponse->gatewayTransactionId, + 'gateway_transaction_uuid' => $gatewayTransaction?->uuid, + 'meta' => [ + 'gateway_uuid' => $gatewayUuid, + 'gateway_transaction_id' => $gatewayResponse->gatewayTransactionId, + ], + ] + ); + } + + return [ + 'wallet' => $wallet->fresh(), + 'transaction' => $walletTransaction, + 'gateway_response' => $gatewayResponse, + ]; + } + + // ========================================================================= + // Driver Earnings & Payouts + // ========================================================================= + + /** + * Credit earnings to a driver's wallet after order completion. + * + * This is the primary method for paying drivers. It credits the driver's + * wallet and creates an "earning" WalletTransaction record. + * + * Double-entry accounting: + * DEBIT Driver Earnings Payable (expense — we owe the driver) + * CREDIT Wallet Liability (liability — the driver's wallet balance) + * + * @param Model $driver The driver model (must have uuid and company_uuid) + * @param int $amount Amount in smallest currency unit (cents) + * @param string $currency + * @param string $description + * @param array $options Optional: reference (order_uuid), meta + * + * @return WalletTransaction + */ + public function creditEarnings( + Model $driver, + int $amount, + string $currency = 'USD', + string $description = '', + array $options = [] + ): WalletTransaction { + $wallet = $this->getOrCreateWallet($driver, $currency); + + return $this->deposit( + wallet: $wallet, + amount: $amount, + description: $description ?: "Earnings credited", + type: WalletTransaction::TYPE_EARNING, + options: array_merge($options, [ + 'subject_uuid' => $driver->uuid, + 'subject_type' => get_class($driver), + ]) + ); + } + + /** + * Process a payout from a driver's wallet to an external destination. + * + * This represents the driver requesting to withdraw their earnings + * to a bank account or external payment method. + * + * @param Model $driver The driver model + * @param int $amount Amount in smallest currency unit (cents) + * @param string $description + * @param array $options Optional: reference, meta, destination_account + * + * @return WalletTransaction + * + * @throws \Exception if wallet has insufficient balance + */ + public function processPayout( + Model $driver, + int $amount, + string $description = '', + array $options = [] + ): WalletTransaction { + $wallet = $this->getOrCreateWallet($driver, $options['currency'] ?? 'USD'); + + return $this->withdraw( + wallet: $wallet, + amount: $amount, + description: $description ?: "Driver payout", + type: WalletTransaction::TYPE_PAYOUT, + options: array_merge($options, [ + 'subject_uuid' => $driver->uuid, + 'subject_type' => get_class($driver), + ]) + ); + } + + // ========================================================================= + // Balance Recalculation + // ========================================================================= + + /** + * Recalculate and correct a wallet's balance from its transaction history. + * + * This is a reconciliation utility. The authoritative balance is always + * the sum of completed credit transactions minus completed debit transactions. + * + * @param Wallet $wallet + * + * @return int The corrected balance + */ + public function recalculateBalance(Wallet $wallet): int + { + $credits = WalletTransaction::where('wallet_uuid', $wallet->uuid) + ->where('direction', WalletTransaction::DIRECTION_CREDIT) + ->where('status', WalletTransaction::STATUS_COMPLETED) + ->sum('amount'); + + $debits = WalletTransaction::where('wallet_uuid', $wallet->uuid) + ->where('direction', WalletTransaction::DIRECTION_DEBIT) + ->where('status', WalletTransaction::STATUS_COMPLETED) + ->sum('amount'); + + $correctBalance = (int) ($credits - $debits); + + if ($wallet->balance !== $correctBalance) { + Log::channel('ledger')->warning("Wallet balance mismatch corrected.", [ + 'wallet_uuid' => $wallet->uuid, + 'recorded_balance' => $wallet->balance, + 'correct_balance' => $correctBalance, + ]); + + $wallet->update(['balance' => $correctBalance]); + } + + return $correctBalance; + } + + // ========================================================================= + // Private Helpers + // ========================================================================= + + /** + * Get or create the ledger liability account for a specific wallet. + * + * Each wallet has its own dedicated liability account in the chart of accounts. + * This account represents the amount the company owes to the wallet holder. */ protected function getWalletAccount(Wallet $wallet): Account { @@ -239,10 +612,6 @@ protected function getWalletAccount(Wallet $wallet): Account /** * Get or create the default cash account for a company. - * - * @param string $companyUuid - * - * @return Account */ protected function getDefaultCashAccount(string $companyUuid): Account { @@ -260,5 +629,16 @@ protected function getDefaultCashAccount(string $companyUuid): Account ); } -} + /** + * Lazily resolve the PaymentService to avoid circular dependency + * (PaymentService → WalletService → PaymentService). + */ + protected function resolvePaymentService(): PaymentService + { + if (!$this->paymentService) { + $this->paymentService = app(PaymentService::class); + } + return $this->paymentService; + } +} diff --git a/server/src/routes.php b/server/src/routes.php index 585e033..fe608a4 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -31,6 +31,38 @@ function ($router) { */ $router->post('webhooks/{driver}', 'WebhookController@handle'); + /* + |-------------------------------------------------------------------------- + | Public API Routes (Authenticated via API Key — Customer / Driver facing) + |-------------------------------------------------------------------------- + | + | These routes are accessible to Fleetbase API consumers (customers, drivers) + | authenticated via their API key. Each consumer can only access their own wallet. + | + | Prefix: /ledger/v1/... + */ + $router->prefix(config('ledger.api.routing.version_prefix', 'v1'))->group( + function ($router) { + $router->group( + ['middleware' => ['fleetbase.api']], + function ($router) { + + // ------------------------------------------------------------ + // Wallet — Public (Customer / Driver) + // ------------------------------------------------------------ + // GET /ledger/v1/wallet — Get own wallet (auto-provisions if needed) + // GET /ledger/v1/wallet/balance — Get own wallet balance + // GET /ledger/v1/wallet/transactions — Get own wallet transaction history + // POST /ledger/v1/wallet/topup — Top up own wallet via payment gateway + $router->get('wallet', 'Api\v1\WalletApiController@getWallet'); + $router->get('wallet/balance', 'Api\v1\WalletApiController@getBalance'); + $router->get('wallet/transactions', 'Api\v1\WalletApiController@getTransactions'); + $router->post('wallet/topup', 'Api\v1\WalletApiController@topUp'); + } + ); + } + ); + /* |-------------------------------------------------------------------------- | Internal Ledger API Routes @@ -80,16 +112,34 @@ function ($router) { $router->post('invoices/{id}/send', 'Internal\v1\InvoiceController@send'); // ------------------------------------------------------------ - // Wallets + // Wallets — Internal (Operator / Admin) // ------------------------------------------------------------ $router->get('wallets', 'Internal\v1\WalletController@query'); $router->get('wallets/{id}', 'Internal\v1\WalletController@find'); $router->post('wallets', 'Internal\v1\WalletController@create'); $router->put('wallets/{id}', 'Internal\v1\WalletController@update'); $router->delete('wallets/{id}', 'Internal\v1\WalletController@delete'); + + // Balance operations $router->post('wallets/{id}/deposit', 'Internal\v1\WalletController@deposit'); $router->post('wallets/{id}/withdraw', 'Internal\v1\WalletController@withdraw'); $router->post('wallets/transfer', 'Internal\v1\WalletController@transfer'); + $router->post('wallets/{id}/topup', 'Internal\v1\WalletController@topUp'); + $router->post('wallets/{id}/payout', 'Internal\v1\WalletController@payout'); + + // State management + $router->post('wallets/{id}/freeze', 'Internal\v1\WalletController@freeze'); + $router->post('wallets/{id}/unfreeze', 'Internal\v1\WalletController@unfreeze'); + $router->post('wallets/{id}/recalculate', 'Internal\v1\WalletController@recalculate'); + + // Transaction history for a specific wallet + $router->get('wallets/{id}/transactions', 'Internal\v1\WalletController@getTransactions'); + + // ------------------------------------------------------------ + // Wallet Transactions — Internal (standalone query endpoint) + // ------------------------------------------------------------ + $router->get('wallet-transactions', 'Internal\v1\WalletTransactionController@query'); + $router->get('wallet-transactions/{id}', 'Internal\v1\WalletTransactionController@find'); // ------------------------------------------------------------ // Transactions (read-only view of core-api Transaction records) @@ -122,8 +172,8 @@ function ($router) { // ------------------------------------------------------------ // Reports & Financial Statements // ------------------------------------------------------------ - // Trial balance — debit/credit totals across all accounts $router->get('reports/trial-balance', 'Internal\v1\ReportController@trialBalance'); + $router->get('reports/wallet-summary', 'Internal\v1\ReportController@walletSummary'); } ); } From b5b63ccb8319a3171d82c74d55ae8db182378123 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sat, 28 Feb 2026 03:18:05 -0500 Subject: [PATCH 007/209] =?UTF-8?q?feat(reports):=20implement=20Milestone?= =?UTF-8?q?=204=20=E2=80=94=20full=20financial=20reporting=20suite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M4.1 — LedgerService: new financial statement methods - getBalanceSheet(): generates Balance Sheet (Assets = Liabilities + Equity) with per-account rows, section totals, and equation verification - getIncomeStatement(): generates P&L for a period using journal activity (not running balances), with revenue/expense line items and net income - getCashFlowSummary(): derives cash flows from WalletTransactions grouped into Operating / Financing / Investing activities; cross-validates against journal Cash account (code 1000) opening/closing balance - getArAging(): buckets outstanding invoices by days overdue into 5 buckets: current, 1-30, 31-60, 61-90, 90+; includes per-invoice detail rows - getDashboardMetrics(): comprehensive KPI set with period-over-period comparison (% change), outstanding AR, wallet totals by currency, daily revenue trend, invoice status counts, and last 10 journal entries - computeNetFlow(): internal helper for cash flow direction calculation - percentageChange(): internal helper for period-over-period KPI deltas - Refactored getBalanceAtDate() to use Account::TYPE_* constants - Refactored getTrialBalance() to use Account::TYPE_* constants + orderBy code M4.2 — ReportController: full suite of report endpoints - dashboard() GET /ledger/int/v1/reports/dashboard - trialBalance() GET /ledger/int/v1/reports/trial-balance - balanceSheet() GET /ledger/int/v1/reports/balance-sheet - incomeStatement() GET /ledger/int/v1/reports/income-statement - cashFlow() GET /ledger/int/v1/reports/cash-flow - arAging() GET /ledger/int/v1/reports/ar-aging - walletSummary() GET /ledger/int/v1/reports/wallet-summary All endpoints validate date inputs and return structured JSON with status/data envelope M4.3 — routes.php: added 5 new report routes - reports/dashboard - reports/balance-sheet - reports/income-statement - reports/cash-flow - reports/ar-aging --- .../Internal/v1/ReportController.php | 325 ++++++++- server/src/Services/LedgerService.php | 648 ++++++++++++++++-- server/src/routes.php | 18 + 3 files changed, 900 insertions(+), 91 deletions(-) diff --git a/server/src/Http/Controllers/Internal/v1/ReportController.php b/server/src/Http/Controllers/Internal/v1/ReportController.php index 7cad0ce..64b8e59 100644 --- a/server/src/Http/Controllers/Internal/v1/ReportController.php +++ b/server/src/Http/Controllers/Internal/v1/ReportController.php @@ -10,6 +10,25 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; +/** + * ReportController + * + * Provides all financial reporting endpoints for the Ledger module. + * + * Available reports: + * - Dashboard Metrics — KPIs, revenue trend, recent journals + * - Trial Balance — All accounts with debit/credit totals + * - Balance Sheet — Assets = Liabilities + Equity + * - Income Statement — Revenue - Expenses = Net Income (P&L) + * - Cash Flow Summary — Operating / Financing / Investing activities + * - AR Aging — Outstanding invoices bucketed by days overdue + * - Wallet Summary — Wallet counts, balances, and top wallets + * + * All monetary values are returned in the smallest currency unit (cents). + * All date parameters accept ISO 8601 date strings (YYYY-MM-DD). + * + * @package Fleetbase\Ledger\Http\Controllers\Internal\v1 + */ class ReportController extends Controller { /** @@ -29,16 +48,70 @@ public function __construct(LedgerService $ledgerService) $this->ledgerService = $ledgerService; } + // ========================================================================= + // Dashboard + // ========================================================================= + + /** + * GET /ledger/int/v1/reports/dashboard + * + * Returns a comprehensive set of KPIs and metrics for the Ledger overview page. + * + * Query parameters: + * - start_date (string, optional) Period start date (YYYY-MM-DD); defaults to start of current month. + * - end_date (string, optional) Period end date (YYYY-MM-DD); defaults to today. + * + * Response includes: + * - period Current and previous period dates + * - kpis total_revenue, total_expenses, net_income (each with current/previous/change_pct), + * outstanding_ar (total + overdue), wallet_totals (by currency) + * - invoice_counts Counts grouped by status + * - revenue_trend Daily revenue breakdown for the period + * - recent_journals Last 10 journal entries + * + * @param Request $request + * + * @return JsonResponse + */ + public function dashboard(Request $request): JsonResponse + { + $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date', + ]); + + $companyUuid = session('company'); + $startDate = $request->input('start_date'); + $endDate = $request->input('end_date'); + + $metrics = $this->ledgerService->getDashboardMetrics($companyUuid, $startDate, $endDate); + + return response()->json([ + 'status' => 'ok', + 'data' => $metrics, + ]); + } + + // ========================================================================= + // Trial Balance + // ========================================================================= + /** - * Generate a trial balance report for the authenticated company. + * GET /ledger/int/v1/reports/trial-balance * - * The trial balance lists every active account with its debit and credit - * totals as of a given date. The sum of all debit-normal balances must - * equal the sum of all credit-normal balances for the books to be balanced. + * Returns a trial balance snapshot listing all active accounts with their + * debit/credit balances as of a given date. * * Query parameters: * - as_of_date (string, optional) ISO date string; defaults to today. * + * Response includes: + * - accounts Array of account rows with debit_total and credit_total + * - debit_total Sum of all debit-normal balances + * - credit_total Sum of all credit-normal balances + * - balanced Boolean — true if debit_total === credit_total + * - as_of_date The date used for the snapshot + * * @param Request $request * * @return JsonResponse @@ -52,24 +125,216 @@ public function trialBalance(Request $request): JsonResponse $companyUuid = session('company'); $asOfDate = $request->input('as_of_date'); - $trialBalance = $this->ledgerService->getTrialBalance($companyUuid, $asOfDate); + $report = $this->ledgerService->getTrialBalance($companyUuid, $asOfDate); - return response()->json($trialBalance); + return response()->json([ + 'status' => 'ok', + 'data' => $report, + ]); } + // ========================================================================= + // Balance Sheet + // ========================================================================= + /** - * Generate a wallet summary report for the authenticated company. + * GET /ledger/int/v1/reports/balance-sheet + * + * Returns a Balance Sheet (Statement of Financial Position) as of a given date. * - * Returns aggregate statistics across all wallets: - * - Total wallets by type (driver, customer, company) - * - Total balance by currency - * - Total credits and debits in a given period - * - Top earners (drivers by earnings) - * - Recent transactions + * Verifies the fundamental accounting equation: + * Assets = Liabilities + Equity * * Query parameters: - * - date_from (string, optional) ISO date string; defaults to start of current month. - * - date_to (string, optional) ISO date string; defaults to today. + * - as_of_date (string, optional) ISO date string; defaults to today. + * + * Response includes: + * - assets Array of asset account rows + * - liabilities Array of liability account rows + * - equity Array of equity account rows + * - total_assets Sum of all asset balances + * - total_liabilities Sum of all liability balances + * - total_equity Sum of all equity balances + * - total_liabilities_and_equity total_liabilities + total_equity + * - balanced Boolean — true if equation holds + * - as_of_date The date used for the snapshot + * + * @param Request $request + * + * @return JsonResponse + */ + public function balanceSheet(Request $request): JsonResponse + { + $request->validate([ + 'as_of_date' => 'nullable|date', + ]); + + $companyUuid = session('company'); + $asOfDate = $request->input('as_of_date'); + + $report = $this->ledgerService->getBalanceSheet($companyUuid, $asOfDate); + + return response()->json([ + 'status' => 'ok', + 'data' => $report, + ]); + } + + // ========================================================================= + // Income Statement (P&L) + // ========================================================================= + + /** + * GET /ledger/int/v1/reports/income-statement + * + * Returns an Income Statement (Profit & Loss) for a given period. + * + * Query parameters: + * - start_date (string, optional) Period start date; defaults to start of current month. + * - end_date (string, optional) Period end date; defaults to today. + * + * Response includes: + * - period from / to dates + * - revenues Array of revenue account rows with period balance + * - expenses Array of expense account rows with period balance + * - total_revenue Sum of all revenue balances + * - total_expenses Sum of all expense balances + * - net_income total_revenue - total_expenses + * - profitable Boolean — true if net_income >= 0 + * + * @param Request $request + * + * @return JsonResponse + */ + public function incomeStatement(Request $request): JsonResponse + { + $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date', + ]); + + $companyUuid = session('company'); + $startDate = $request->input('start_date'); + $endDate = $request->input('end_date'); + + $report = $this->ledgerService->getIncomeStatement($companyUuid, $startDate, $endDate); + + return response()->json([ + 'status' => 'ok', + 'data' => $report, + ]); + } + + // ========================================================================= + // Cash Flow Summary + // ========================================================================= + + /** + * GET /ledger/int/v1/reports/cash-flow + * + * Returns a Cash Flow Summary for a given period, derived from wallet transactions + * and cross-validated against the journal Cash account (code 1000). + * + * Query parameters: + * - start_date (string, optional) Period start date; defaults to start of current month. + * - end_date (string, optional) Period end date; defaults to today. + * + * Response includes: + * - period from / to dates + * - operating_activities items[] + net_flow + * - financing_activities items[] + net_flow + * - investing_activities items[] + net_flow + * - net_cash_change Sum of all three net flows + * - cash_account opening_balance, closing_balance, net_change (from journals) + * + * @param Request $request + * + * @return JsonResponse + */ + public function cashFlow(Request $request): JsonResponse + { + $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date', + ]); + + $companyUuid = session('company'); + $startDate = $request->input('start_date'); + $endDate = $request->input('end_date'); + + $report = $this->ledgerService->getCashFlowSummary($companyUuid, $startDate, $endDate); + + return response()->json([ + 'status' => 'ok', + 'data' => $report, + ]); + } + + // ========================================================================= + // AR Aging + // ========================================================================= + + /** + * GET /ledger/int/v1/reports/ar-aging + * + * Returns an Accounts Receivable Aging report bucketing all outstanding + * invoices by how many days past due they are as of a given date. + * + * Buckets: + * - current (not yet due or due today) + * - 1_30 (1–30 days overdue) + * - 31_60 (31–60 days overdue) + * - 61_90 (61–90 days overdue) + * - over_90 (90+ days overdue) + * + * Query parameters: + * - as_of_date (string, optional) ISO date string; defaults to today. + * + * Response includes: + * - as_of_date The date used for the snapshot + * - buckets Object keyed by bucket name, each with label, days_range, invoices[], total + * - grand_total Sum of all outstanding balances + * - total_invoices Count of all outstanding invoices + * + * @param Request $request + * + * @return JsonResponse + */ + public function arAging(Request $request): JsonResponse + { + $request->validate([ + 'as_of_date' => 'nullable|date', + ]); + + $companyUuid = session('company'); + $asOfDate = $request->input('as_of_date'); + + $report = $this->ledgerService->getArAging($companyUuid, $asOfDate); + + return response()->json([ + 'status' => 'ok', + 'data' => $report, + ]); + } + + // ========================================================================= + // Wallet Summary + // ========================================================================= + + /** + * GET /ledger/int/v1/reports/wallet-summary + * + * Returns a summary of all wallets in the system. + * + * Query parameters: + * - date_from (string, optional) Period start for transaction aggregation; defaults to start of current month. + * - date_to (string, optional) Period end; defaults to today. + * + * Response includes: + * - period Period from/to dates + * - wallet_counts Wallet counts grouped by owner type with total balances + * - period_stats Credits and debits for the period grouped by currency + * - top_driver_wallets Top 10 driver wallets by balance * * @param Request $request * @@ -86,13 +351,14 @@ public function walletSummary(Request $request): JsonResponse $dateFrom = $request->input('date_from', now()->startOfMonth()->toDateString()); $dateTo = $request->input('date_to', now()->toDateString()); - // Total wallets grouped by inferred type + // Total wallets grouped by inferred owner type $walletCounts = Wallet::where('company_uuid', $companyUuid) ->select('subject_type', DB::raw('count(*) as count'), DB::raw('sum(balance) as total_balance'), 'currency') ->groupBy('subject_type', 'currency') ->get() ->map(function ($row) { $type = strtolower(class_basename($row->subject_type ?? '')); + return [ 'type' => match (true) { str_contains($type, 'driver') => 'driver', @@ -123,8 +389,8 @@ public function walletSummary(Request $request): JsonResponse $result = ['credits' => 0, 'debits' => 0, 'credit_count' => 0, 'debit_count' => 0]; foreach ($rows as $row) { if ($row->direction === WalletTransaction::DIRECTION_CREDIT) { - $result['credits'] = (int) $row->total; - $result['credit_count'] = (int) $row->count; + $result['credits'] = (int) $row->total; + $result['credit_count'] = (int) $row->count; } else { $result['debits'] = (int) $row->total; $result['debit_count'] = (int) $row->count; @@ -141,23 +407,26 @@ public function walletSummary(Request $request): JsonResponse ->limit(10) ->get() ->map(fn ($w) => [ - 'wallet_public_id' => $w->public_id, - 'balance' => $w->balance, + 'wallet_public_id' => $w->public_id, + 'balance' => $w->balance, 'formatted_balance' => $w->formatted_balance, - 'currency' => $w->currency, - 'subject' => $w->subject ? [ + 'currency' => $w->currency, + 'subject' => $w->subject ? [ 'name' => $w->subject->name ?? $w->subject->public_id ?? $w->subject->uuid, ] : null, ]); return response()->json([ - 'period' => [ - 'from' => $dateFrom, - 'to' => $dateTo, + 'status' => 'ok', + 'data' => [ + 'period' => [ + 'from' => $dateFrom, + 'to' => $dateTo, + ], + 'wallet_counts' => $walletCounts, + 'period_stats' => $periodStats, + 'top_driver_wallets' => $topDriverWallets, ], - 'wallet_counts' => $walletCounts, - 'period_stats' => $periodStats, - 'top_driver_wallets' => $topDriverWallets, ]); } } diff --git a/server/src/Services/LedgerService.php b/server/src/Services/LedgerService.php index aff2224..a9efd9b 100644 --- a/server/src/Services/LedgerService.php +++ b/server/src/Services/LedgerService.php @@ -3,18 +3,46 @@ namespace Fleetbase\Ledger\Services; use Fleetbase\Ledger\Models\Account; +use Fleetbase\Ledger\Models\Invoice; use Fleetbase\Ledger\Models\Journal; +use Fleetbase\Ledger\Models\Wallet; +use Fleetbase\Ledger\Models\WalletTransaction; use Fleetbase\Models\Transaction; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; +/** + * LedgerService + * + * Core double-entry bookkeeping engine for the Ledger extension. + * + * Responsibilities: + * - Creating and managing journal entries (double-entry bookkeeping) + * - Providing account balance calculations + * - Generating financial statements: + * - Trial Balance + * - Balance Sheet (Assets = Liabilities + Equity) + * - Income Statement (Revenue - Expenses = Net Income) + * - Cash Flow Summary + * - Accounts Receivable Aging + * - Providing dashboard metrics + * + * All monetary values are stored and returned in the smallest currency unit (cents). + * + * @package Fleetbase\Ledger\Services + */ class LedgerService { + // ========================================================================= + // Journal Entry Creation + // ========================================================================= + /** * Create a double-entry journal entry and the corresponding core Transaction record. * * Every financial movement in Ledger is represented as a pair of records: - * 1. A `Transaction` (core-api primitive) - the canonical, auditable money-movement record. - * 2. A `Journal` (Ledger model) - the double-entry bookkeeping entry that links the + * 1. A `Transaction` (core-api primitive) — the canonical, auditable money-movement record. + * 2. A `Journal` (Ledger model) — the double-entry bookkeeping entry that links the * debit and credit accounts to that transaction. * * All monetary amounts are stored in the smallest currency unit (e.g. cents for USD). @@ -54,9 +82,7 @@ public function createJournalEntry( $status = $options['status'] ?? 'completed'; $meta = $options['meta'] ?? []; - // Build the Transaction payload, populating every relevant field from the - // core-api Transaction model so the record is fully queryable from the - // standard transactions API without needing Ledger-specific queries. + // Build the Transaction payload $transactionPayload = [ 'company_uuid' => $companyUuid, 'amount' => $amount, @@ -67,23 +93,18 @@ public function createJournalEntry( 'meta' => $meta, ]; - // Attach optional contextual fields when provided if (!empty($options['transaction_id'])) { $transactionPayload['gateway_transaction_id'] = $options['transaction_id']; } - if (!empty($options['subject_uuid'])) { $transactionPayload['subject_uuid'] = $options['subject_uuid']; } - if (!empty($options['subject_type'])) { $transactionPayload['subject_type'] = $options['subject_type']; } - if (!empty($options['gateway_uuid'])) { $transactionPayload['gateway_uuid'] = $options['gateway_uuid']; } - if (!empty($options['notes'])) { $transactionPayload['notes'] = $options['notes']; } @@ -91,7 +112,7 @@ public function createJournalEntry( // Create the canonical Transaction record in core-api $transaction = Transaction::create($transactionPayload); - // Create the double-entry Journal record linking debit and credit accounts + // Create the double-entry Journal record $journal = Journal::create([ 'company_uuid' => $companyUuid, 'transaction_uuid' => $transaction->uuid, @@ -114,14 +135,6 @@ public function createJournalEntry( /** * Transfer funds between two accounts. - * - * @param Account $fromAccount Account to debit (source). - * @param Account $toAccount Account to credit (destination). - * @param int $amount Amount in smallest currency unit. - * @param string $description - * @param array $options - * - * @return Journal */ public function transfer( Account $fromAccount, @@ -142,15 +155,8 @@ public function transfer( /** * Record revenue received. * - * Correct treatment: DEBIT Asset (cash/AR increases), CREDIT Revenue (revenue increases). - * - * @param Account $assetAccount The asset account receiving the funds (debit). - * @param Account $revenueAccount The revenue account being recognised (credit). - * @param int $amount - * @param string $description - * @param array $options - * - * @return Journal + * DEBIT Asset (cash/AR increases) + * CREDIT Revenue (revenue increases) */ public function recordRevenue( Account $assetAccount, @@ -171,15 +177,8 @@ public function recordRevenue( /** * Record an expense incurred. * - * Correct treatment: DEBIT Expense (expense increases), CREDIT Asset (cash/AP decreases). - * - * @param Account $expenseAccount The expense account being charged (debit). - * @param Account $assetAccount The asset account being reduced (credit). - * @param int $amount - * @param string $description - * @param array $options - * - * @return Journal + * DEBIT Expense (expense increases) + * CREDIT Asset (cash/AP decreases) */ public function recordExpense( Account $expenseAccount, @@ -197,27 +196,24 @@ public function recordExpense( ); } + // ========================================================================= + // Account Balance + // ========================================================================= + /** - * Get all journal entries for a specific account (the general ledger view). - * - * @param Account $account - * @param string|null $startDate ISO date string (inclusive lower bound). - * @param string|null $endDate ISO date string (inclusive upper bound). - * - * @return \Illuminate\Support\Collection + * Get all journal entries for a specific account (general ledger view). */ - public function getGeneralLedger(Account $account, ?string $startDate = null, ?string $endDate = null) + public function getGeneralLedger(Account $account, ?string $startDate = null, ?string $endDate = null): Collection { $query = Journal::with(['transaction', 'debitAccount', 'creditAccount']) ->where(function ($q) use ($account) { $q->where('debit_account_uuid', $account->uuid) - ->orWhere('credit_account_uuid', $account->uuid); + ->orWhere('credit_account_uuid', $account->uuid); }); if ($startDate) { $query->where('date', '>=', $startDate); } - if ($endDate) { $query->where('date', '<=', $endDate); } @@ -228,18 +224,13 @@ public function getGeneralLedger(Account $account, ?string $startDate = null, ?s /** * Calculate the balance for an account at (or up to) a specific date. * - * Uses the standard accounting normal balance rules: - * - Asset & Expense accounts: balance = debits - credits (debit-normal) - * - Liability, Equity & Revenue accounts: balance = credits - debits (credit-normal) - * - * @param Account $account - * @param string $date ISO date string (inclusive upper bound). - * - * @return int Balance in smallest currency unit. + * Normal balance rules: + * - Asset & Expense: balance = debits - credits (debit-normal) + * - Liability, Equity & Revenue: balance = credits - debits (credit-normal) */ public function getBalanceAtDate(Account $account, string $date): int { - $debits = Journal::where('debit_account_uuid', $account->uuid) + $debits = Journal::where('debit_account_uuid', $account->uuid) ->where('date', '<=', $date) ->sum('amount'); @@ -247,15 +238,23 @@ public function getBalanceAtDate(Account $account, string $date): int ->where('date', '<=', $date) ->sum('amount'); - if (in_array($account->type, ['asset', 'expense'])) { + if (in_array($account->type, [Account::TYPE_ASSET, Account::TYPE_EXPENSE])) { return (int) ($debits - $credits); } return (int) ($credits - $debits); } + // ========================================================================= + // Trial Balance + // ========================================================================= + /** - * Get a trial balance snapshot for a company. + * Generate a trial balance for a company. + * + * Lists every active account with its debit/credit balance as of a given date. + * The sum of all debit-normal balances must equal the sum of all credit-normal + * balances for the books to be in balance. * * @param string $companyUuid * @param string|null $asOfDate ISO date string; defaults to today. @@ -268,15 +267,17 @@ public function getTrialBalance(string $companyUuid, ?string $asOfDate = null): $accounts = Account::where('company_uuid', $companyUuid) ->where('is_active', true) + ->orderBy('code') ->get() ->map(function (Account $account) use ($asOfDate) { - $balance = $this->getBalanceAtDate($account, $asOfDate); + $balance = $this->getBalanceAtDate($account, $asOfDate); + $isDebitNormal = in_array($account->type, [Account::TYPE_ASSET, Account::TYPE_EXPENSE]); return [ 'account' => $account, 'balance' => $balance, - 'debit_total' => in_array($account->type, ['asset', 'expense']) ? max(0, $balance) : 0, - 'credit_total' => in_array($account->type, ['liability', 'equity', 'revenue']) ? max(0, $balance) : 0, + 'debit_total' => $isDebitNormal ? max(0, $balance) : 0, + 'credit_total' => !$isDebitNormal ? max(0, $balance) : 0, ]; }); @@ -285,10 +286,531 @@ public function getTrialBalance(string $companyUuid, ?string $asOfDate = null): return [ 'accounts' => $accounts, - 'debit_total' => $debitTotal, - 'credit_total' => $creditTotal, + 'debit_total' => (int) $debitTotal, + 'credit_total' => (int) $creditTotal, 'balanced' => $debitTotal === $creditTotal, 'as_of_date' => $asOfDate, ]; } + + // ========================================================================= + // Balance Sheet + // ========================================================================= + + /** + * Generate a Balance Sheet (Statement of Financial Position). + * + * Presents the accounting equation: + * Assets = Liabilities + Equity + * + * Assets are listed first (current then non-current), followed by + * liabilities and equity. The report verifies that the equation holds. + * + * @param string $companyUuid + * @param string|null $asOfDate ISO date string; defaults to today. + * + * @return array + */ + public function getBalanceSheet(string $companyUuid, ?string $asOfDate = null): array + { + $asOfDate = $asOfDate ?? now()->toDateString(); + + $accounts = Account::where('company_uuid', $companyUuid) + ->where('is_active', true) + ->orderBy('code') + ->get(); + + $assets = []; + $liabilities = []; + $equity = []; + + foreach ($accounts as $account) { + $balance = $this->getBalanceAtDate($account, $asOfDate); + + // Only include accounts with non-zero balances + if ($balance === 0) { + continue; + } + + $row = [ + 'uuid' => $account->uuid, + 'code' => $account->code, + 'name' => $account->name, + 'balance' => $balance, + ]; + + switch ($account->type) { + case Account::TYPE_ASSET: + $assets[] = $row; + break; + case Account::TYPE_LIABILITY: + $liabilities[] = $row; + break; + case Account::TYPE_EQUITY: + $equity[] = $row; + break; + } + } + + $totalAssets = array_sum(array_column($assets, 'balance')); + $totalLiabilities = array_sum(array_column($liabilities, 'balance')); + $totalEquity = array_sum(array_column($equity, 'balance')); + + return [ + 'as_of_date' => $asOfDate, + 'assets' => $assets, + 'liabilities' => $liabilities, + 'equity' => $equity, + 'total_assets' => (int) $totalAssets, + 'total_liabilities' => (int) $totalLiabilities, + 'total_equity' => (int) $totalEquity, + 'total_liabilities_and_equity' => (int) ($totalLiabilities + $totalEquity), + 'balanced' => $totalAssets === ($totalLiabilities + $totalEquity), + ]; + } + + // ========================================================================= + // Income Statement (Profit & Loss) + // ========================================================================= + + /** + * Generate an Income Statement (Profit & Loss Statement). + * + * Presents revenue and expenses over a period, resulting in net income (or loss). + * + * Net Income = Total Revenue - Total Expenses + * + * @param string $companyUuid + * @param string|null $startDate ISO date string; defaults to start of current month. + * @param string|null $endDate ISO date string; defaults to today. + * + * @return array + */ + public function getIncomeStatement(string $companyUuid, ?string $startDate = null, ?string $endDate = null): array + { + $startDate = $startDate ?? now()->startOfMonth()->toDateString(); + $endDate = $endDate ?? now()->toDateString(); + + $accounts = Account::where('company_uuid', $companyUuid) + ->where('is_active', true) + ->whereIn('type', [Account::TYPE_REVENUE, Account::TYPE_EXPENSE]) + ->orderBy('code') + ->get(); + + $revenues = []; + $expenses = []; + + foreach ($accounts as $account) { + // Income statement uses only activity within the period + $debits = Journal::where('debit_account_uuid', $account->uuid) + ->whereBetween('date', [$startDate, $endDate]) + ->sum('amount'); + + $credits = Journal::where('credit_account_uuid', $account->uuid) + ->whereBetween('date', [$startDate, $endDate]) + ->sum('amount'); + + if ($account->type === Account::TYPE_REVENUE) { + $balance = (int) ($credits - $debits); // credit-normal + } else { + $balance = (int) ($debits - $credits); // debit-normal + } + + if ($balance === 0) { + continue; + } + + $row = [ + 'uuid' => $account->uuid, + 'code' => $account->code, + 'name' => $account->name, + 'balance' => $balance, + ]; + + if ($account->type === Account::TYPE_REVENUE) { + $revenues[] = $row; + } else { + $expenses[] = $row; + } + } + + $totalRevenue = array_sum(array_column($revenues, 'balance')); + $totalExpenses = array_sum(array_column($expenses, 'balance')); + $netIncome = $totalRevenue - $totalExpenses; + + return [ + 'period' => [ + 'from' => $startDate, + 'to' => $endDate, + ], + 'revenues' => $revenues, + 'expenses' => $expenses, + 'total_revenue' => (int) $totalRevenue, + 'total_expenses' => (int) $totalExpenses, + 'net_income' => (int) $netIncome, + 'profitable' => $netIncome >= 0, + ]; + } + + // ========================================================================= + // Cash Flow Summary + // ========================================================================= + + /** + * Generate a Cash Flow Summary. + * + * A simplified cash flow statement derived from wallet transactions. + * Groups cash movements into three standard categories: + * - Operating Activities (earnings, fees, refunds, adjustments) + * - Financing Activities (deposits, withdrawals, payouts, transfers) + * - Investing Activities (placeholder for future asset purchases) + * + * Also reports the opening and closing balance of the Cash account (code 1000) + * from the journal ledger for cross-validation. + * + * @param string $companyUuid + * @param string|null $startDate ISO date string; defaults to start of current month. + * @param string|null $endDate ISO date string; defaults to today. + * + * @return array + */ + public function getCashFlowSummary(string $companyUuid, ?string $startDate = null, ?string $endDate = null): array + { + $startDate = $startDate ?? now()->startOfMonth()->toDateString(); + $endDate = $endDate ?? now()->toDateString(); + + // Derive cash flows from wallet transactions (most reliable cash proxy) + $walletStats = WalletTransaction::where('company_uuid', $companyUuid) + ->where('status', WalletTransaction::STATUS_COMPLETED) + ->whereBetween(DB::raw('DATE(created_at)'), [$startDate, $endDate]) + ->select( + 'type', + 'direction', + 'currency', + DB::raw('sum(amount) as total'), + DB::raw('count(*) as count') + ) + ->groupBy('type', 'direction', 'currency') + ->get(); + + $operating = []; + $financing = []; + $investing = []; + + $operatingTypes = [ + WalletTransaction::TYPE_EARNING, + WalletTransaction::TYPE_FEE, + WalletTransaction::TYPE_ADJUSTMENT, + WalletTransaction::TYPE_REFUND, + ]; + $financingTypes = [ + WalletTransaction::TYPE_DEPOSIT, + WalletTransaction::TYPE_WITHDRAWAL, + WalletTransaction::TYPE_PAYOUT, + WalletTransaction::TYPE_TRANSFER_IN, + WalletTransaction::TYPE_TRANSFER_OUT, + ]; + + foreach ($walletStats as $row) { + $entry = [ + 'type' => $row->type, + 'direction' => $row->direction, + 'currency' => $row->currency, + 'total' => (int) $row->total, + 'count' => (int) $row->count, + ]; + + if (in_array($row->type, $operatingTypes)) { + $operating[] = $entry; + } elseif (in_array($row->type, $financingTypes)) { + $financing[] = $entry; + } else { + $investing[] = $entry; + } + } + + $netOperating = $this->computeNetFlow($operating); + $netFinancing = $this->computeNetFlow($financing); + $netInvesting = $this->computeNetFlow($investing); + + // Journal-based cash account movements for cross-validation + $cashAccount = Account::where('company_uuid', $companyUuid)->where('code', '1000')->first(); + $journalCashFlow = null; + + if ($cashAccount) { + $openingBalance = $this->getBalanceAtDate($cashAccount, now()->parse($startDate)->subDay()->toDateString()); + $closingBalance = $this->getBalanceAtDate($cashAccount, $endDate); + $journalCashFlow = [ + 'opening_balance' => $openingBalance, + 'closing_balance' => $closingBalance, + 'net_change' => $closingBalance - $openingBalance, + ]; + } + + return [ + 'period' => [ + 'from' => $startDate, + 'to' => $endDate, + ], + 'operating_activities' => [ + 'items' => $operating, + 'net_flow' => $netOperating, + ], + 'financing_activities' => [ + 'items' => $financing, + 'net_flow' => $netFinancing, + ], + 'investing_activities' => [ + 'items' => $investing, + 'net_flow' => $netInvesting, + ], + 'net_cash_change' => $netOperating + $netFinancing + $netInvesting, + 'cash_account' => $journalCashFlow, + ]; + } + + /** + * Compute net flow (credits - debits) from a list of categorised wallet transaction rows. + */ + protected function computeNetFlow(array $items): int + { + $net = 0; + foreach ($items as $item) { + if ($item['direction'] === WalletTransaction::DIRECTION_CREDIT) { + $net += $item['total']; + } else { + $net -= $item['total']; + } + } + return $net; + } + + // ========================================================================= + // Accounts Receivable Aging + // ========================================================================= + + /** + * Generate an Accounts Receivable Aging Report. + * + * Buckets outstanding (unpaid) invoices by how many days past due they are: + * - Current (not yet due or due today) + * - 1–30 days overdue + * - 31–60 days overdue + * - 61–90 days overdue + * - 90+ days overdue + * + * @param string $companyUuid + * @param string|null $asOfDate ISO date string; defaults to today. + * + * @return array + */ + public function getArAging(string $companyUuid, ?string $asOfDate = null): array + { + $asOfDate = $asOfDate ?? now()->toDateString(); + $asOfCarbon = now()->parse($asOfDate); + + // Load all unpaid/partially-paid invoices + $invoices = Invoice::where('company_uuid', $companyUuid) + ->whereNotIn('status', ['paid', 'cancelled', 'void']) + ->where('balance', '>', 0) + ->with('customer') + ->get(); + + $buckets = [ + 'current' => ['label' => 'Current', 'days_range' => '0', 'invoices' => [], 'total' => 0], + '1_30' => ['label' => '1–30 days', 'days_range' => '1-30', 'invoices' => [], 'total' => 0], + '31_60' => ['label' => '31–60 days', 'days_range' => '31-60', 'invoices' => [], 'total' => 0], + '61_90' => ['label' => '61–90 days', 'days_range' => '61-90', 'invoices' => [], 'total' => 0], + 'over_90' => ['label' => '90+ days', 'days_range' => '90+', 'invoices' => [], 'total' => 0], + ]; + + foreach ($invoices as $invoice) { + $daysOverdue = 0; + + if ($invoice->due_date) { + $daysOverdue = max(0, (int) $asOfCarbon->diffInDays($invoice->due_date, false) * -1); + } + + $row = [ + 'invoice_id' => $invoice->public_id, + 'invoice_uuid' => $invoice->uuid, + 'number' => $invoice->number, + 'customer' => $invoice->customer ? [ + 'name' => $invoice->customer->name ?? $invoice->customer->public_id ?? null, + ] : null, + 'date' => $invoice->date?->toDateString(), + 'due_date' => $invoice->due_date?->toDateString(), + 'total_amount' => $invoice->total_amount, + 'amount_paid' => $invoice->amount_paid, + 'balance' => $invoice->balance, + 'currency' => $invoice->currency, + 'days_overdue' => $daysOverdue, + 'status' => $invoice->status, + ]; + + if ($daysOverdue <= 0) { + $buckets['current']['invoices'][] = $row; + $buckets['current']['total'] += $invoice->balance; + } elseif ($daysOverdue <= 30) { + $buckets['1_30']['invoices'][] = $row; + $buckets['1_30']['total'] += $invoice->balance; + } elseif ($daysOverdue <= 60) { + $buckets['31_60']['invoices'][] = $row; + $buckets['31_60']['total'] += $invoice->balance; + } elseif ($daysOverdue <= 90) { + $buckets['61_90']['invoices'][] = $row; + $buckets['61_90']['total'] += $invoice->balance; + } else { + $buckets['over_90']['invoices'][] = $row; + $buckets['over_90']['total'] += $invoice->balance; + } + } + + $grandTotal = array_sum(array_column($buckets, 'total')); + + return [ + 'as_of_date' => $asOfDate, + 'buckets' => $buckets, + 'grand_total' => (int) $grandTotal, + 'total_invoices' => $invoices->count(), + ]; + } + + // ========================================================================= + // Dashboard Metrics + // ========================================================================= + + /** + * Get a comprehensive set of dashboard metrics for the Ledger overview page. + * + * Returns KPIs for the current period compared to the previous period: + * - Total revenue (current vs previous period, % change) + * - Total expenses (current vs previous period, % change) + * - Net income (current vs previous period, % change) + * - Outstanding AR (total + overdue) + * - Total wallet balances (by currency) + * - Invoice counts by status + * - Revenue trend (daily breakdown for the period) + * - Recent journal entries (last 10) + * + * @param string $companyUuid + * @param string|null $startDate ISO date string; defaults to start of current month. + * @param string|null $endDate ISO date string; defaults to today. + * + * @return array + */ + public function getDashboardMetrics(string $companyUuid, ?string $startDate = null, ?string $endDate = null): array + { + $startDate = $startDate ?? now()->startOfMonth()->toDateString(); + $endDate = $endDate ?? now()->toDateString(); + + // Previous period (same length, immediately before) + $periodDays = now()->parse($startDate)->diffInDays(now()->parse($endDate)) + 1; + $prevEndDate = now()->parse($startDate)->subDay()->toDateString(); + $prevStartDate = now()->parse($prevEndDate)->subDays($periodDays - 1)->toDateString(); + + // Income statements for current and previous period + $currentIncome = $this->getIncomeStatement($companyUuid, $startDate, $endDate); + $previousIncome = $this->getIncomeStatement($companyUuid, $prevStartDate, $prevEndDate); + + // Outstanding AR + $outstandingAr = Invoice::where('company_uuid', $companyUuid) + ->whereNotIn('status', ['paid', 'cancelled', 'void']) + ->where('balance', '>', 0) + ->sum('balance'); + + $overdueAr = Invoice::where('company_uuid', $companyUuid) + ->whereNotIn('status', ['paid', 'cancelled', 'void']) + ->where('balance', '>', 0) + ->where('due_date', '<', now()->toDateString()) + ->sum('balance'); + + // Invoice counts by status + $invoiceCounts = Invoice::where('company_uuid', $companyUuid) + ->select('status', DB::raw('count(*) as count')) + ->groupBy('status') + ->pluck('count', 'status') + ->toArray(); + + // Wallet totals by currency + $walletTotals = Wallet::where('company_uuid', $companyUuid) + ->where('status', Wallet::STATUS_ACTIVE) + ->select('currency', DB::raw('sum(balance) as total'), DB::raw('count(*) as count')) + ->groupBy('currency') + ->get() + ->map(fn ($r) => [ + 'currency' => $r->currency, + 'total' => (int) $r->total, + 'count' => (int) $r->count, + ]); + + // Revenue trend — daily breakdown for the current period + $revenueTrend = Journal::where('company_uuid', $companyUuid) + ->whereHas('creditAccount', fn ($q) => $q->where('type', Account::TYPE_REVENUE)) + ->whereBetween('date', [$startDate, $endDate]) + ->select('date', DB::raw('sum(amount) as daily_revenue')) + ->groupBy('date') + ->orderBy('date') + ->get() + ->map(fn ($r) => [ + 'date' => $r->date, + 'daily_revenue' => (int) $r->daily_revenue, + ]); + + // Recent journal entries + $recentJournals = Journal::where('company_uuid', $companyUuid) + ->with(['debitAccount', 'creditAccount']) + ->orderBy('created_at', 'desc') + ->limit(10) + ->get(); + + return [ + 'period' => [ + 'from' => $startDate, + 'to' => $endDate, + 'previous_from' => $prevStartDate, + 'previous_to' => $prevEndDate, + ], + 'kpis' => [ + 'total_revenue' => [ + 'current' => $currentIncome['total_revenue'], + 'previous' => $previousIncome['total_revenue'], + 'change_pct' => $this->percentageChange($previousIncome['total_revenue'], $currentIncome['total_revenue']), + ], + 'total_expenses' => [ + 'current' => $currentIncome['total_expenses'], + 'previous' => $previousIncome['total_expenses'], + 'change_pct' => $this->percentageChange($previousIncome['total_expenses'], $currentIncome['total_expenses']), + ], + 'net_income' => [ + 'current' => $currentIncome['net_income'], + 'previous' => $previousIncome['net_income'], + 'change_pct' => $this->percentageChange($previousIncome['net_income'], $currentIncome['net_income']), + 'profitable' => $currentIncome['net_income'] >= 0, + ], + 'outstanding_ar' => [ + 'total' => (int) $outstandingAr, + 'overdue' => (int) $overdueAr, + ], + 'wallet_totals' => $walletTotals, + ], + 'invoice_counts' => $invoiceCounts, + 'revenue_trend' => $revenueTrend, + 'recent_journals' => $recentJournals, + ]; + } + + /** + * Calculate percentage change between two values. + * + * @return float|null Returns null if previous is zero (undefined). + */ + protected function percentageChange(int|float $previous, int|float $current): ?float + { + if ($previous == 0) { + return $current > 0 ? 100.0 : null; + } + + return round((($current - $previous) / abs($previous)) * 100, 2); + } } diff --git a/server/src/routes.php b/server/src/routes.php index fe608a4..6aa198b 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -172,7 +172,25 @@ function ($router) { // ------------------------------------------------------------ // Reports & Financial Statements // ------------------------------------------------------------ + // Dashboard — KPIs, revenue trend, recent journals, invoice counts + $router->get('reports/dashboard', 'Internal\v1\ReportController@dashboard'); + + // Trial Balance — all accounts with debit/credit totals as of a date $router->get('reports/trial-balance', 'Internal\v1\ReportController@trialBalance'); + + // Balance Sheet — Assets = Liabilities + Equity as of a date + $router->get('reports/balance-sheet', 'Internal\v1\ReportController@balanceSheet'); + + // Income Statement (P&L) — Revenue - Expenses = Net Income for a period + $router->get('reports/income-statement', 'Internal\v1\ReportController@incomeStatement'); + + // Cash Flow Summary — Operating / Financing / Investing activities for a period + $router->get('reports/cash-flow', 'Internal\v1\ReportController@cashFlow'); + + // AR Aging — Outstanding invoices bucketed by days overdue + $router->get('reports/ar-aging', 'Internal\v1\ReportController@arAging'); + + // Wallet Summary — wallet counts, balances, period stats, top wallets $router->get('reports/wallet-summary', 'Internal\v1\ReportController@walletSummary'); } ); From 0083f437f8c4f7f3632d42e151d67c0b51d215a1 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sat, 28 Feb 2026 04:03:52 -0500 Subject: [PATCH 008/209] feat(frontend): implement complete Milestone 5 frontend UI ## Overview Full Ember engine frontend for the Ledger module. Implements all 8 navigation sections with declarative sidebar (EmberWormhole pattern from iam-engine), 7 Ember Data models, 16 route controllers, 16 templates, 26 components, and 80 app/ re-export files. ## Sidebar Navigation (declarative HBS, not universe menu service) - Dashboard (home route) - Billing > Invoices, Transactions - Wallets - Accounting > Journal Entries, Chart of Accounts - Reports - Settings > Payment Gateways ## Ember Data Models (addon/models/) - account, invoice, transaction, wallet, wallet-transaction, journal, gateway ## Routes & Controllers - home (dashboard) - billing/invoices/index + details (tabs: details, line-items, transactions) - billing/transactions/index + details (tabs: details) - wallets/index + details (tabs: details, transactions) - accounting/journal/index + details (tabs: details) - accounting/accounts/index + details (tabs: details, general-ledger) - reports/index (tab-based: trial-balance, balance-sheet, income-statement, cash-flow, ar-aging) - settings/gateways/index + details (tabs: configuration, webhook-events) ## Components (26 total across 8 namespaces) dashboard/: kpi-metric, revenue-chart, invoice-summary, wallet-balances, activity-feed invoice/: panel-header, details, line-items, transactions transaction/: panel-header, details wallet/: panel-header, details, transaction-history journal/: panel-header, details account/: panel-header, details, general-ledger report/: balance-sheet, income-statement, cash-flow, ar-aging gateway/: panel-header, details, webhook-events, form (dynamic config schema renderer) ## engine.js / extension.js / routes.js - engine.js: clean Ember engine with correct dependencies - extension.js: registers header menu item and dashboard widget only - routes.js: full nested route tree matching all 8 sections ## app/ Re-exports (80 files) All routes, controllers, models, and components re-exported from app/ directory under the @fleetbase/ledger-engine namespace for Ember resolver compatibility. --- addon/components/account/details.hbs | 34 +++++ addon/components/account/general-ledger.hbs | 52 +++++++ addon/components/account/general-ledger.js | 27 ++++ addon/components/account/panel-header.hbs | 9 ++ addon/components/dashboard/activity-feed.hbs | 19 +++ .../components/dashboard/invoice-summary.hbs | 13 ++ addon/components/dashboard/kpi-metric.hbs | 17 +++ addon/components/dashboard/kpi-metric.js | 25 ++++ addon/components/dashboard/revenue-chart.hbs | 12 ++ addon/components/dashboard/revenue-chart.js | 43 ++++++ .../components/dashboard/wallet-balances.hbs | 13 ++ addon/components/gateway/details.hbs | 39 +++++ addon/components/gateway/form.hbs | 103 ++++++++++++++ addon/components/gateway/form.js | 77 ++++++++++ addon/components/gateway/panel-header.hbs | 12 ++ addon/components/gateway/webhook-events.hbs | 36 +++++ addon/components/gateway/webhook-events.js | 29 ++++ addon/components/invoice/details.hbs | 60 ++++++++ addon/components/invoice/line-items.hbs | 26 ++++ addon/components/invoice/panel-header.hbs | 10 ++ addon/components/invoice/transactions.hbs | 32 +++++ addon/components/invoice/transactions.js | 27 ++++ addon/components/journal/details.hbs | 51 +++++++ addon/components/journal/panel-header.hbs | 10 ++ addon/components/report/ar-aging.hbs | 60 ++++++++ addon/components/report/balance-sheet.hbs | 75 ++++++++++ addon/components/report/cash-flow.hbs | 60 ++++++++ addon/components/report/income-statement.hbs | 61 ++++++++ addon/components/transaction/details.hbs | 42 ++++++ addon/components/transaction/panel-header.hbs | 10 ++ addon/components/wallet/details.hbs | 28 ++++ addon/components/wallet/panel-header.hbs | 10 ++ .../components/wallet/transaction-history.hbs | 38 +++++ .../components/wallet/transaction-history.js | 30 ++++ .../controllers/accounting/accounts/index.js | 50 +++++++ .../accounting/accounts/index/details.js | 14 ++ addon/controllers/accounting/journal/index.js | 103 ++++++++++++++ .../accounting/journal/index/details.js | 39 +++++ addon/controllers/billing/invoices/index.js | 134 ++++++++++++++++++ .../billing/invoices/index/details.js | 71 ++++++++++ .../controllers/billing/transactions/index.js | 43 ++++++ .../billing/transactions/index/details.js | 11 ++ addon/controllers/reports/index.js | 57 ++++++++ addon/controllers/settings/gateways/index.js | 93 ++++++++++++ .../settings/gateways/index/details.js | 63 ++++++++ addon/controllers/wallets/index.js | 69 +++++++++ addon/controllers/wallets/index/details.js | 59 ++++++++ addon/engine.js | 7 +- addon/extension.js | 27 +++- addon/models/account.js | 38 +++++ addon/models/gateway.js | 40 ++++++ addon/models/invoice.js | 71 ++++++++++ addon/models/journal.js | 47 ++++++ addon/models/transaction.js | 37 +++++ addon/models/wallet-transaction.js | 51 +++++++ addon/models/wallet.js | 45 ++++++ addon/routes.js | 97 ++++++++----- addon/routes/accounting/accounts.js | 3 + addon/routes/accounting/accounts/index.js | 18 +++ .../accounting/accounts/index/details.js | 12 ++ addon/routes/accounting/journal.js | 3 + addon/routes/accounting/journal/index.js | 18 +++ .../accounting/journal/index/details.js | 12 ++ addon/routes/billing/invoices.js | 3 + addon/routes/billing/invoices/index.js | 18 +++ .../routes/billing/invoices/index/details.js | 12 ++ addon/routes/billing/transactions.js | 3 + addon/routes/billing/transactions/index.js | 18 +++ .../billing/transactions/index/details.js | 12 ++ addon/routes/home.js | 15 ++ addon/routes/reports/index.js | 3 + addon/routes/settings/gateways.js | 3 + addon/routes/settings/gateways/index.js | 10 ++ .../routes/settings/gateways/index/details.js | 12 ++ .../settings/gateways/index/details/index.js | 2 + .../gateways/index/details/webhooks.js | 2 + addon/routes/wallets.js | 2 + addon/routes/wallets/index.js | 18 +++ addon/routes/wallets/index/details.js | 12 ++ addon/routes/wallets/index/details/index.js | 2 + .../wallets/index/details/transactions.js | 2 + addon/templates/accounting/accounts.hbs | 15 ++ addon/templates/accounting/accounts/index.hbs | 15 ++ .../accounting/accounts/index/details.hbs | 16 +++ .../accounts/index/details/index.hbs | 1 + .../accounts/index/details/ledger.hbs | 1 + addon/templates/accounting/journal.hbs | 16 +++ addon/templates/accounting/journal/index.hbs | 15 ++ .../accounting/journal/index/details.hbs | 16 +++ .../journal/index/details/index.hbs | 1 + addon/templates/application.hbs | 29 ++++ addon/templates/billing/invoices.hbs | 16 +++ addon/templates/billing/invoices/index.hbs | 15 ++ .../billing/invoices/index/details.hbs | 16 +++ .../billing/invoices/index/details/index.hbs | 1 + .../invoices/index/details/line-items.hbs | 1 + .../invoices/index/details/transactions.hbs | 1 + addon/templates/billing/transactions.hbs | 15 ++ .../templates/billing/transactions/index.hbs | 15 ++ .../billing/transactions/index/details.hbs | 15 ++ .../transactions/index/details/index.hbs | 1 + addon/templates/home.hbs | 57 ++++++++ addon/templates/reports/index.hbs | 44 ++++++ addon/templates/settings/gateways.hbs | 15 ++ addon/templates/settings/gateways/index.hbs | 11 ++ .../settings/gateways/index/details.hbs | 16 +++ .../settings/gateways/index/details/index.hbs | 1 + .../gateways/index/details/webhooks.hbs | 1 + addon/templates/wallets.hbs | 15 ++ addon/templates/wallets/index.hbs | 15 ++ addon/templates/wallets/index/details.hbs | 16 +++ .../templates/wallets/index/details/index.hbs | 1 + .../wallets/index/details/transactions.hbs | 1 + app/components/ledger/account/details.js | 1 + .../ledger/account/general-ledger.js | 1 + app/components/ledger/account/panel-header.js | 1 + .../ledger/dashboard/activity-feed.js | 1 + .../ledger/dashboard/invoice-summary.js | 1 + app/components/ledger/dashboard/kpi-metric.js | 1 + .../ledger/dashboard/revenue-chart.js | 1 + .../ledger/dashboard/wallet-balances.js | 1 + app/components/ledger/gateway/details.js | 1 + app/components/ledger/gateway/form.js | 1 + app/components/ledger/gateway/panel-header.js | 1 + .../ledger/gateway/webhook-events.js | 1 + app/components/ledger/invoice/details.js | 1 + app/components/ledger/invoice/line-items.js | 1 + app/components/ledger/invoice/panel-header.js | 1 + app/components/ledger/invoice/transactions.js | 1 + app/components/ledger/journal/details.js | 1 + app/components/ledger/journal/panel-header.js | 1 + app/components/ledger/report/ar-aging.js | 1 + app/components/ledger/report/balance-sheet.js | 1 + app/components/ledger/report/cash-flow.js | 1 + .../ledger/report/income-statement.js | 1 + app/components/ledger/transaction/details.js | 1 + .../ledger/transaction/panel-header.js | 1 + app/components/ledger/wallet/details.js | 1 + app/components/ledger/wallet/panel-header.js | 1 + .../ledger/wallet/transaction-history.js | 1 + .../ledger/accounting/accounts/index.js | 1 + .../accounting/accounts/index/details.js | 1 + .../ledger/accounting/journal/index.js | 1 + .../accounting/journal/index/details.js | 1 + .../ledger/billing/invoices/index.js | 1 + .../ledger/billing/invoices/index/details.js | 1 + .../ledger/billing/transactions/index.js | 1 + .../billing/transactions/index/details.js | 1 + app/controllers/ledger/home.js | 1 + app/controllers/ledger/reports/index.js | 1 + .../ledger/settings/gateways/index.js | 1 + .../ledger/settings/gateways/index/details.js | 1 + app/controllers/ledger/wallets/index.js | 1 + .../ledger/wallets/index/details.js | 1 + app/models/account.js | 1 + app/models/gateway.js | 1 + app/models/invoice.js | 1 + app/models/journal.js | 1 + app/models/transaction.js | 1 + app/models/wallet-transaction.js | 1 + app/models/wallet.js | 1 + app/routes/ledger/accounting/accounts.js | 1 + .../ledger/accounting/accounts/index.js | 1 + .../accounting/accounts/index/details.js | 1 + .../accounts/index/details/index.js | 1 + .../accounts/index/details/ledger.js | 1 + app/routes/ledger/accounting/journal.js | 1 + app/routes/ledger/accounting/journal/index.js | 1 + .../accounting/journal/index/details.js | 1 + .../accounting/journal/index/details/index.js | 1 + app/routes/ledger/billing/invoices.js | 1 + app/routes/ledger/billing/invoices/index.js | 1 + .../ledger/billing/invoices/index/details.js | 1 + .../billing/invoices/index/details/index.js | 1 + .../invoices/index/details/line-items.js | 1 + .../invoices/index/details/transactions.js | 1 + app/routes/ledger/billing/transactions.js | 1 + .../ledger/billing/transactions/index.js | 1 + .../billing/transactions/index/details.js | 1 + .../transactions/index/details/index.js | 1 + app/routes/ledger/home.js | 1 + app/routes/ledger/reports/index.js | 1 + app/routes/ledger/settings/gateways.js | 1 + app/routes/ledger/settings/gateways/index.js | 1 + .../ledger/settings/gateways/index/details.js | 1 + .../settings/gateways/index/details/index.js | 1 + .../gateways/index/details/webhooks.js | 1 + app/routes/ledger/wallets.js | 1 + app/routes/ledger/wallets/index.js | 1 + app/routes/ledger/wallets/index/details.js | 1 + .../ledger/wallets/index/details/index.js | 1 + .../wallets/index/details/transactions.js | 1 + 192 files changed, 3116 insertions(+), 48 deletions(-) create mode 100644 addon/components/account/details.hbs create mode 100644 addon/components/account/general-ledger.hbs create mode 100644 addon/components/account/general-ledger.js create mode 100644 addon/components/account/panel-header.hbs create mode 100644 addon/components/dashboard/activity-feed.hbs create mode 100644 addon/components/dashboard/invoice-summary.hbs create mode 100644 addon/components/dashboard/kpi-metric.hbs create mode 100644 addon/components/dashboard/kpi-metric.js create mode 100644 addon/components/dashboard/revenue-chart.hbs create mode 100644 addon/components/dashboard/revenue-chart.js create mode 100644 addon/components/dashboard/wallet-balances.hbs create mode 100644 addon/components/gateway/details.hbs create mode 100644 addon/components/gateway/form.hbs create mode 100644 addon/components/gateway/form.js create mode 100644 addon/components/gateway/panel-header.hbs create mode 100644 addon/components/gateway/webhook-events.hbs create mode 100644 addon/components/gateway/webhook-events.js create mode 100644 addon/components/invoice/details.hbs create mode 100644 addon/components/invoice/line-items.hbs create mode 100644 addon/components/invoice/panel-header.hbs create mode 100644 addon/components/invoice/transactions.hbs create mode 100644 addon/components/invoice/transactions.js create mode 100644 addon/components/journal/details.hbs create mode 100644 addon/components/journal/panel-header.hbs create mode 100644 addon/components/report/ar-aging.hbs create mode 100644 addon/components/report/balance-sheet.hbs create mode 100644 addon/components/report/cash-flow.hbs create mode 100644 addon/components/report/income-statement.hbs create mode 100644 addon/components/transaction/details.hbs create mode 100644 addon/components/transaction/panel-header.hbs create mode 100644 addon/components/wallet/details.hbs create mode 100644 addon/components/wallet/panel-header.hbs create mode 100644 addon/components/wallet/transaction-history.hbs create mode 100644 addon/components/wallet/transaction-history.js create mode 100644 addon/controllers/accounting/accounts/index.js create mode 100644 addon/controllers/accounting/accounts/index/details.js create mode 100644 addon/controllers/accounting/journal/index.js create mode 100644 addon/controllers/accounting/journal/index/details.js create mode 100644 addon/controllers/billing/invoices/index.js create mode 100644 addon/controllers/billing/invoices/index/details.js create mode 100644 addon/controllers/billing/transactions/index.js create mode 100644 addon/controllers/billing/transactions/index/details.js create mode 100644 addon/controllers/reports/index.js create mode 100644 addon/controllers/settings/gateways/index.js create mode 100644 addon/controllers/settings/gateways/index/details.js create mode 100644 addon/controllers/wallets/index.js create mode 100644 addon/controllers/wallets/index/details.js create mode 100644 addon/models/account.js create mode 100644 addon/models/gateway.js create mode 100644 addon/models/invoice.js create mode 100644 addon/models/journal.js create mode 100644 addon/models/transaction.js create mode 100644 addon/models/wallet-transaction.js create mode 100644 addon/models/wallet.js create mode 100644 addon/routes/accounting/accounts.js create mode 100644 addon/routes/accounting/accounts/index.js create mode 100644 addon/routes/accounting/accounts/index/details.js create mode 100644 addon/routes/accounting/journal.js create mode 100644 addon/routes/accounting/journal/index.js create mode 100644 addon/routes/accounting/journal/index/details.js create mode 100644 addon/routes/billing/invoices.js create mode 100644 addon/routes/billing/invoices/index.js create mode 100644 addon/routes/billing/invoices/index/details.js create mode 100644 addon/routes/billing/transactions.js create mode 100644 addon/routes/billing/transactions/index.js create mode 100644 addon/routes/billing/transactions/index/details.js create mode 100644 addon/routes/home.js create mode 100644 addon/routes/reports/index.js create mode 100644 addon/routes/settings/gateways.js create mode 100644 addon/routes/settings/gateways/index.js create mode 100644 addon/routes/settings/gateways/index/details.js create mode 100644 addon/routes/settings/gateways/index/details/index.js create mode 100644 addon/routes/settings/gateways/index/details/webhooks.js create mode 100644 addon/routes/wallets.js create mode 100644 addon/routes/wallets/index.js create mode 100644 addon/routes/wallets/index/details.js create mode 100644 addon/routes/wallets/index/details/index.js create mode 100644 addon/routes/wallets/index/details/transactions.js create mode 100644 addon/templates/accounting/accounts.hbs create mode 100644 addon/templates/accounting/accounts/index.hbs create mode 100644 addon/templates/accounting/accounts/index/details.hbs create mode 100644 addon/templates/accounting/accounts/index/details/index.hbs create mode 100644 addon/templates/accounting/accounts/index/details/ledger.hbs create mode 100644 addon/templates/accounting/journal.hbs create mode 100644 addon/templates/accounting/journal/index.hbs create mode 100644 addon/templates/accounting/journal/index/details.hbs create mode 100644 addon/templates/accounting/journal/index/details/index.hbs create mode 100644 addon/templates/application.hbs create mode 100644 addon/templates/billing/invoices.hbs create mode 100644 addon/templates/billing/invoices/index.hbs create mode 100644 addon/templates/billing/invoices/index/details.hbs create mode 100644 addon/templates/billing/invoices/index/details/index.hbs create mode 100644 addon/templates/billing/invoices/index/details/line-items.hbs create mode 100644 addon/templates/billing/invoices/index/details/transactions.hbs create mode 100644 addon/templates/billing/transactions.hbs create mode 100644 addon/templates/billing/transactions/index.hbs create mode 100644 addon/templates/billing/transactions/index/details.hbs create mode 100644 addon/templates/billing/transactions/index/details/index.hbs create mode 100644 addon/templates/home.hbs create mode 100644 addon/templates/reports/index.hbs create mode 100644 addon/templates/settings/gateways.hbs create mode 100644 addon/templates/settings/gateways/index.hbs create mode 100644 addon/templates/settings/gateways/index/details.hbs create mode 100644 addon/templates/settings/gateways/index/details/index.hbs create mode 100644 addon/templates/settings/gateways/index/details/webhooks.hbs create mode 100644 addon/templates/wallets.hbs create mode 100644 addon/templates/wallets/index.hbs create mode 100644 addon/templates/wallets/index/details.hbs create mode 100644 addon/templates/wallets/index/details/index.hbs create mode 100644 addon/templates/wallets/index/details/transactions.hbs create mode 100644 app/components/ledger/account/details.js create mode 100644 app/components/ledger/account/general-ledger.js create mode 100644 app/components/ledger/account/panel-header.js create mode 100644 app/components/ledger/dashboard/activity-feed.js create mode 100644 app/components/ledger/dashboard/invoice-summary.js create mode 100644 app/components/ledger/dashboard/kpi-metric.js create mode 100644 app/components/ledger/dashboard/revenue-chart.js create mode 100644 app/components/ledger/dashboard/wallet-balances.js create mode 100644 app/components/ledger/gateway/details.js create mode 100644 app/components/ledger/gateway/form.js create mode 100644 app/components/ledger/gateway/panel-header.js create mode 100644 app/components/ledger/gateway/webhook-events.js create mode 100644 app/components/ledger/invoice/details.js create mode 100644 app/components/ledger/invoice/line-items.js create mode 100644 app/components/ledger/invoice/panel-header.js create mode 100644 app/components/ledger/invoice/transactions.js create mode 100644 app/components/ledger/journal/details.js create mode 100644 app/components/ledger/journal/panel-header.js create mode 100644 app/components/ledger/report/ar-aging.js create mode 100644 app/components/ledger/report/balance-sheet.js create mode 100644 app/components/ledger/report/cash-flow.js create mode 100644 app/components/ledger/report/income-statement.js create mode 100644 app/components/ledger/transaction/details.js create mode 100644 app/components/ledger/transaction/panel-header.js create mode 100644 app/components/ledger/wallet/details.js create mode 100644 app/components/ledger/wallet/panel-header.js create mode 100644 app/components/ledger/wallet/transaction-history.js create mode 100644 app/controllers/ledger/accounting/accounts/index.js create mode 100644 app/controllers/ledger/accounting/accounts/index/details.js create mode 100644 app/controllers/ledger/accounting/journal/index.js create mode 100644 app/controllers/ledger/accounting/journal/index/details.js create mode 100644 app/controllers/ledger/billing/invoices/index.js create mode 100644 app/controllers/ledger/billing/invoices/index/details.js create mode 100644 app/controllers/ledger/billing/transactions/index.js create mode 100644 app/controllers/ledger/billing/transactions/index/details.js create mode 100644 app/controllers/ledger/home.js create mode 100644 app/controllers/ledger/reports/index.js create mode 100644 app/controllers/ledger/settings/gateways/index.js create mode 100644 app/controllers/ledger/settings/gateways/index/details.js create mode 100644 app/controllers/ledger/wallets/index.js create mode 100644 app/controllers/ledger/wallets/index/details.js create mode 100644 app/models/account.js create mode 100644 app/models/gateway.js create mode 100644 app/models/invoice.js create mode 100644 app/models/journal.js create mode 100644 app/models/transaction.js create mode 100644 app/models/wallet-transaction.js create mode 100644 app/models/wallet.js create mode 100644 app/routes/ledger/accounting/accounts.js create mode 100644 app/routes/ledger/accounting/accounts/index.js create mode 100644 app/routes/ledger/accounting/accounts/index/details.js create mode 100644 app/routes/ledger/accounting/accounts/index/details/index.js create mode 100644 app/routes/ledger/accounting/accounts/index/details/ledger.js create mode 100644 app/routes/ledger/accounting/journal.js create mode 100644 app/routes/ledger/accounting/journal/index.js create mode 100644 app/routes/ledger/accounting/journal/index/details.js create mode 100644 app/routes/ledger/accounting/journal/index/details/index.js create mode 100644 app/routes/ledger/billing/invoices.js create mode 100644 app/routes/ledger/billing/invoices/index.js create mode 100644 app/routes/ledger/billing/invoices/index/details.js create mode 100644 app/routes/ledger/billing/invoices/index/details/index.js create mode 100644 app/routes/ledger/billing/invoices/index/details/line-items.js create mode 100644 app/routes/ledger/billing/invoices/index/details/transactions.js create mode 100644 app/routes/ledger/billing/transactions.js create mode 100644 app/routes/ledger/billing/transactions/index.js create mode 100644 app/routes/ledger/billing/transactions/index/details.js create mode 100644 app/routes/ledger/billing/transactions/index/details/index.js create mode 100644 app/routes/ledger/home.js create mode 100644 app/routes/ledger/reports/index.js create mode 100644 app/routes/ledger/settings/gateways.js create mode 100644 app/routes/ledger/settings/gateways/index.js create mode 100644 app/routes/ledger/settings/gateways/index/details.js create mode 100644 app/routes/ledger/settings/gateways/index/details/index.js create mode 100644 app/routes/ledger/settings/gateways/index/details/webhooks.js create mode 100644 app/routes/ledger/wallets.js create mode 100644 app/routes/ledger/wallets/index.js create mode 100644 app/routes/ledger/wallets/index/details.js create mode 100644 app/routes/ledger/wallets/index/details/index.js create mode 100644 app/routes/ledger/wallets/index/details/transactions.js diff --git a/addon/components/account/details.hbs b/addon/components/account/details.hbs new file mode 100644 index 0000000..01ce9c8 --- /dev/null +++ b/addon/components/account/details.hbs @@ -0,0 +1,34 @@ +
+
+
+ +

{{@account.name}}

+
+
+ +

{{@account.code}}

+
+
+ +

{{@account.type_label}}

+
+
+ + {{@account.status_label}} +
+
+ +

{{@account.formatted_balance}}

+
+
+ +

{{@account.currency}}

+
+
+ {{#if @account.description}} +
+ +

{{@account.description}}

+
+ {{/if}} +
diff --git a/addon/components/account/general-ledger.hbs b/addon/components/account/general-ledger.hbs new file mode 100644 index 0000000..8991029 --- /dev/null +++ b/addon/components/account/general-ledger.hbs @@ -0,0 +1,52 @@ +
+ {{#if this.loadLedger.isRunning}} + + {{else}} + {{#if this.summary}} +
+
+

Total Debits

+

{{this.summary.formatted_total_debits}}

+
+
+

Total Credits

+

{{this.summary.formatted_total_credits}}

+
+
+

Net Balance

+

{{this.summary.formatted_net_balance}}

+
+
+ {{/if}} + + + + + + + + + + + + {{#each this.entries as |entry|}} + + + + + + + + {{else}} + + + + {{/each}} + +
DateDescriptionDebitCreditBalance
{{format-date entry.date format="MMM d, yyyy"}}{{entry.description}} + {{or entry.formatted_debit "—"}} + + {{or entry.formatted_credit "—"}} + {{entry.formatted_running_balance}}
No entries
+ {{/if}} +
diff --git a/addon/components/account/general-ledger.js b/addon/components/account/general-ledger.js new file mode 100644 index 0000000..a4090ea --- /dev/null +++ b/addon/components/account/general-ledger.js @@ -0,0 +1,27 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class AccountGeneralLedgerComponent extends Component { + @service fetch; + @tracked entries = []; + @tracked summary = null; + + constructor(owner, args) { + super(owner, args); + this.loadLedger.perform(); + } + + @task *loadLedger() { + const account = this.args.account; + if (!account?.public_id) return; + try { + const result = yield this.fetch.get(`ledger/int/v1/accounts/${account.public_id}/ledger`); + this.entries = result?.data?.entries ?? []; + this.summary = result?.data?.summary ?? null; + } catch { + this.entries = []; + } + } +} diff --git a/addon/components/account/panel-header.hbs b/addon/components/account/panel-header.hbs new file mode 100644 index 0000000..65fdc06 --- /dev/null +++ b/addon/components/account/panel-header.hbs @@ -0,0 +1,9 @@ +
+
+

{{@account.code}} · {{@account.type_label}}

+
+
+ {{@account.formatted_balance}} + {{@account.status_label}} +
+
diff --git a/addon/components/dashboard/activity-feed.hbs b/addon/components/dashboard/activity-feed.hbs new file mode 100644 index 0000000..bb90e11 --- /dev/null +++ b/addon/components/dashboard/activity-feed.hbs @@ -0,0 +1,19 @@ +
+

Recent Journal Entries

+
+ {{#each @entries as |entry|}} +
+
+ {{entry.description}} + DR: {{entry.debit_account_name}} / CR: {{entry.credit_account_name}} +
+
+ {{entry.formatted_amount}} + {{format-date entry.date format="MMM d"}} +
+
+ {{else}} +

No recent journal entries

+ {{/each}} +
+
diff --git a/addon/components/dashboard/invoice-summary.hbs b/addon/components/dashboard/invoice-summary.hbs new file mode 100644 index 0000000..1d7cbd5 --- /dev/null +++ b/addon/components/dashboard/invoice-summary.hbs @@ -0,0 +1,13 @@ +
+

Invoices

+
+ {{#each-in @data as |status count|}} +
+ {{status}} + {{count}} +
+ {{else}} +

No invoice data

+ {{/each-in}} +
+
diff --git a/addon/components/dashboard/kpi-metric.hbs b/addon/components/dashboard/kpi-metric.hbs new file mode 100644 index 0000000..265c68f --- /dev/null +++ b/addon/components/dashboard/kpi-metric.hbs @@ -0,0 +1,17 @@ +
+
+ {{@title}} + {{#if @icon}} + + {{/if}} +
+
+ {{this.formattedValue}} +
+ {{#if this.changeLabel}} +
+ {{this.changeLabel}} + vs last period +
+ {{/if}} +
diff --git a/addon/components/dashboard/kpi-metric.js b/addon/components/dashboard/kpi-metric.js new file mode 100644 index 0000000..2a061af --- /dev/null +++ b/addon/components/dashboard/kpi-metric.js @@ -0,0 +1,25 @@ +import Component from '@glimmer/component'; +import { computed } from '@ember/object'; + +export default class DashboardKpiMetricComponent extends Component { + get formattedValue() { + const { value, currency } = this.args; + if (value === undefined || value === null) return '—'; + const amount = value / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency || 'USD' }).format(amount); + } + + get changeLabel() { + const change = this.args.change; + if (change === undefined || change === null) return null; + const sign = change >= 0 ? '+' : ''; + return `${sign}${change.toFixed(1)}%`; + } + + get changeColor() { + const change = this.args.change; + if (change === undefined || change === null) return 'gray'; + const positive = change >= 0; + return this.args.inverse ? (positive ? 'red' : 'green') : (positive ? 'green' : 'red'); + } +} diff --git a/addon/components/dashboard/revenue-chart.hbs b/addon/components/dashboard/revenue-chart.hbs new file mode 100644 index 0000000..08a1013 --- /dev/null +++ b/addon/components/dashboard/revenue-chart.hbs @@ -0,0 +1,12 @@ +
+

Revenue Trend

+
+ {{#if @data}} + + {{else}} +
+ No revenue data available +
+ {{/if}} +
+
diff --git a/addon/components/dashboard/revenue-chart.js b/addon/components/dashboard/revenue-chart.js new file mode 100644 index 0000000..e113aaf --- /dev/null +++ b/addon/components/dashboard/revenue-chart.js @@ -0,0 +1,43 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; + +export default class DashboardRevenueChartComponent extends Component { + @tracked chartData = null; + + @action + setupChart(element) { + const data = this.args.data || []; + const labels = data.map((d) => d.date); + const values = data.map((d) => (d.amount || 0) / 100); + + this.chartData = { labels, values }; + + if (typeof window !== 'undefined' && window.Chart) { + new window.Chart(element, { + type: 'line', + data: { + labels, + datasets: [ + { + label: 'Revenue', + data: values, + borderColor: 'rgb(59, 130, 246)', + backgroundColor: 'rgba(59, 130, 246, 0.1)', + tension: 0.4, + fill: true, + }, + ], + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { legend: { display: false } }, + scales: { + y: { beginAtZero: true, ticks: { callback: (v) => '$' + v.toLocaleString() } }, + }, + }, + }); + } + } +} diff --git a/addon/components/dashboard/wallet-balances.hbs b/addon/components/dashboard/wallet-balances.hbs new file mode 100644 index 0000000..ede6cb1 --- /dev/null +++ b/addon/components/dashboard/wallet-balances.hbs @@ -0,0 +1,13 @@ +
+

Wallet Balances

+
+ {{#each @data as |item|}} +
+ {{item.currency}} + {{item.formatted_total}} +
+ {{else}} +

No wallet data

+ {{/each}} +
+
diff --git a/addon/components/gateway/details.hbs b/addon/components/gateway/details.hbs new file mode 100644 index 0000000..6abd782 --- /dev/null +++ b/addon/components/gateway/details.hbs @@ -0,0 +1,39 @@ +
+
+
+ +

{{@gateway.name}}

+
+
+ +

{{@gateway.driver_label}}

+
+
+ + {{@gateway.environment}} +
+
+ + {{@gateway.status_label}} +
+
+ +

{{if @gateway.is_default "Yes" "No"}}

+
+
+ +

{{@gateway.webhook_url}}

+
+
+ + {{#if @gateway.capabilities}} +
+

Capabilities

+
+ {{#each @gateway.capabilities as |cap|}} + {{cap}} + {{/each}} +
+
+ {{/if}} +
diff --git a/addon/components/gateway/form.hbs b/addon/components/gateway/form.hbs new file mode 100644 index 0000000..1a570d5 --- /dev/null +++ b/addon/components/gateway/form.hbs @@ -0,0 +1,103 @@ +
+ {{! Gateway Name }} + + + {{! Driver selector }} +
+ + + {{#if this.selectedDriver}} + {{#let (find-by "code" this.selectedDriver this.availableDrivers) as |driver|}} + {{#if driver.description}} +

{{driver.description}}

+ {{/if}} + {{#if driver.capabilities}} +
+ {{#each driver.capabilities as |cap|}} + {{cap}} + {{/each}} +
+ {{/if}} + {{/let}} + {{/if}} +
+ + {{! Environment }} +
+ + +
+ + {{! Default toggle }} + + + {{! Dynamic config schema fields }} + {{#if this.configSchema.length}} +
+

Configuration

+
+ {{#each this.configSchema as |field|}} + {{#if (eq field.type "text")}} + + {{else if (eq field.type "password")}} + + {{else if (eq field.type "select")}} +
+ + + {{#if field.description}} +

{{field.description}}

+ {{/if}} +
+ {{else if (eq field.type "boolean")}} + + {{/if}} + {{/each}} +
+
+ {{/if}} +
diff --git a/addon/components/gateway/form.js b/addon/components/gateway/form.js new file mode 100644 index 0000000..9e6d21f --- /dev/null +++ b/addon/components/gateway/form.js @@ -0,0 +1,77 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; +import { task } from 'ember-concurrency'; + +export default class GatewayFormComponent extends Component { + @service fetch; + + @tracked selectedDriver = null; + @tracked configSchema = []; + @tracked configValues = {}; + @tracked name = ''; + @tracked environment = 'sandbox'; + @tracked isDefault = false; + + get availableDrivers() { + return this.args.availableDrivers ?? []; + } + + get environmentOptions() { + return [ + { value: 'sandbox', label: 'Sandbox / Test' }, + { value: 'live', label: 'Live / Production' }, + ]; + } + + @task *loadSchema(driverCode) { + const driver = this.availableDrivers.find((d) => d.code === driverCode); + this.configSchema = driver?.config_schema ?? []; + this.configValues = {}; + // Pre-fill defaults + this.configSchema.forEach((field) => { + if (field.default !== undefined) { + this.configValues[field.key] = field.default; + } + }); + } + + @action selectDriver(driverCode) { + this.selectedDriver = driverCode; + this.loadSchema.perform(driverCode); + this.notifyChange(); + } + + @action updateConfigField(key, value) { + this.configValues = { ...this.configValues, [key]: value }; + this.notifyChange(); + } + + @action updateName(value) { + this.name = value; + this.notifyChange(); + } + + @action updateEnvironment(value) { + this.environment = value; + this.notifyChange(); + } + + @action toggleDefault(value) { + this.isDefault = value; + this.notifyChange(); + } + + notifyChange() { + if (this.args.onChange) { + this.args.onChange({ + name: this.name, + driver: this.selectedDriver, + environment: this.environment, + is_default: this.isDefault, + config: this.configValues, + }); + } + } +} diff --git a/addon/components/gateway/panel-header.hbs b/addon/components/gateway/panel-header.hbs new file mode 100644 index 0000000..f9aa089 --- /dev/null +++ b/addon/components/gateway/panel-header.hbs @@ -0,0 +1,12 @@ +
+
+

{{@gateway.driver_label}}

+

{{@gateway.environment}}

+
+
+ {{#if @gateway.is_default}} + Default + {{/if}} + {{@gateway.status_label}} +
+
diff --git a/addon/components/gateway/webhook-events.hbs b/addon/components/gateway/webhook-events.hbs new file mode 100644 index 0000000..f09bedd --- /dev/null +++ b/addon/components/gateway/webhook-events.hbs @@ -0,0 +1,36 @@ +
+ {{#if this.loadEvents.isRunning}} + + {{else}} + + + + + + + + + + + + {{#each this.events as |event|}} + + + + + + + + {{else}} + + + + {{/each}} + +
DateEvent TypeGateway RefAmountStatus
{{format-date event.created_at format="MMM d, HH:mm"}}{{event.event_type}}{{event.gateway_reference_id}}{{event.formatted_amount}} + + {{event.status}} + +
No webhook events recorded
+ {{/if}} +
diff --git a/addon/components/gateway/webhook-events.js b/addon/components/gateway/webhook-events.js new file mode 100644 index 0000000..7151c04 --- /dev/null +++ b/addon/components/gateway/webhook-events.js @@ -0,0 +1,29 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class GatewayWebhookEventsComponent extends Component { + @service fetch; + @tracked events = []; + @tracked meta = null; + + constructor(owner, args) { + super(owner, args); + this.loadEvents.perform(); + } + + @task *loadEvents() { + const gateway = this.args.gateway; + if (!gateway?.public_id) return; + try { + const result = yield this.fetch.get(`ledger/int/v1/gateways/${gateway.public_id}/transactions`, { + params: { limit: 20 }, + }); + this.events = result?.data ?? []; + this.meta = result?.meta ?? null; + } catch { + this.events = []; + } + } +} diff --git a/addon/components/invoice/details.hbs b/addon/components/invoice/details.hbs new file mode 100644 index 0000000..204cf34 --- /dev/null +++ b/addon/components/invoice/details.hbs @@ -0,0 +1,60 @@ +
+
+
+ +

{{@invoice.number}}

+
+
+ + {{@invoice.status}} +
+
+ +

{{@invoice.customer_name}}

+
+
+ +

{{or @invoice.customer_email "—"}}

+
+
+ +

{{format-date @invoice.due_at format="MMM d, yyyy"}}

+
+
+ +

{{@invoice.currency}}

+
+
+ +
+
+
+ +

{{@invoice.formatted_subtotal}}

+
+
+ +

{{@invoice.formatted_tax}}

+
+
+ +

{{@invoice.formatted_total}}

+
+
+ +

{{@invoice.formatted_amount_paid}}

+
+
+ +

{{@invoice.formatted_balance}}

+
+
+
+ + {{#if @invoice.notes}} +
+ +

{{@invoice.notes}}

+
+ {{/if}} +
diff --git a/addon/components/invoice/line-items.hbs b/addon/components/invoice/line-items.hbs new file mode 100644 index 0000000..09697ec --- /dev/null +++ b/addon/components/invoice/line-items.hbs @@ -0,0 +1,26 @@ +
+ + + + + + + + + + + {{#each @invoice.line_items as |item|}} + + + + + + + {{else}} + + + + {{/each}} + +
DescriptionQtyUnit PriceTotal
{{item.description}}{{item.quantity}}{{item.formatted_unit_price}}{{item.formatted_total}}
No line items
+
diff --git a/addon/components/invoice/panel-header.hbs b/addon/components/invoice/panel-header.hbs new file mode 100644 index 0000000..5ea0e99 --- /dev/null +++ b/addon/components/invoice/panel-header.hbs @@ -0,0 +1,10 @@ +
+
+

{{@invoice.customer_name}}

+

Due {{format-date @invoice.due_at format="MMM d, yyyy"}}

+
+
+ {{@invoice.formatted_total}} + {{@invoice.status}} +
+
diff --git a/addon/components/invoice/transactions.hbs b/addon/components/invoice/transactions.hbs new file mode 100644 index 0000000..cd8a7be --- /dev/null +++ b/addon/components/invoice/transactions.hbs @@ -0,0 +1,32 @@ +
+ {{#if this.loadTransactions.isRunning}} + + {{else}} + + + + + + + + + + + {{#each this.transactions as |txn|}} + + + + + + + {{else}} + + + + {{/each}} + +
DateGatewayAmountStatus
{{format-date txn.created_at format="MMM d, yyyy"}}{{txn.gateway_code}}{{txn.formatted_amount}} + {{txn.status}} +
No transactions recorded
+ {{/if}} +
diff --git a/addon/components/invoice/transactions.js b/addon/components/invoice/transactions.js new file mode 100644 index 0000000..729b255 --- /dev/null +++ b/addon/components/invoice/transactions.js @@ -0,0 +1,27 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class InvoiceTransactionsComponent extends Component { + @service fetch; + @tracked transactions = []; + + constructor(owner, args) { + super(owner, args); + this.loadTransactions.perform(); + } + + @task *loadTransactions() { + const invoice = this.args.invoice; + if (!invoice?.public_id) return; + try { + const result = yield this.fetch.get(`ledger/int/v1/transactions`, { + params: { invoice_uuid: invoice.id }, + }); + this.transactions = result?.data ?? []; + } catch { + this.transactions = []; + } + } +} diff --git a/addon/components/journal/details.hbs b/addon/components/journal/details.hbs new file mode 100644 index 0000000..ac369ba --- /dev/null +++ b/addon/components/journal/details.hbs @@ -0,0 +1,51 @@ +
+
+
+ +

{{@entry.number}}

+
+
+ +

{{@entry.type_label}}

+
+
+ +

{{format-date @entry.date format="MMM d, yyyy"}}

+
+
+ + {{@entry.entry_source}} +
+
+ +

{{@entry.formatted_amount}}

+
+
+ +

{{@entry.currency}}

+
+
+ +
+

Double-Entry

+
+
+

Debit

+

{{@entry.debit_account_name}}

+

{{@entry.debit_account_code}}

+
+
+

Credit

+

{{@entry.credit_account_name}}

+

{{@entry.credit_account_code}}

+
+
+
+ + {{#if @entry.description}} +
+ +

{{@entry.description}}

+
+ {{/if}} +
diff --git a/addon/components/journal/panel-header.hbs b/addon/components/journal/panel-header.hbs new file mode 100644 index 0000000..c54373c --- /dev/null +++ b/addon/components/journal/panel-header.hbs @@ -0,0 +1,10 @@ +
+
+

{{@entry.type_label}}

+

{{format-date @entry.date format="MMM d, yyyy"}}

+
+
+ {{@entry.formatted_amount}} + {{@entry.entry_source}} +
+
diff --git a/addon/components/report/ar-aging.hbs b/addon/components/report/ar-aging.hbs new file mode 100644 index 0000000..ed8b4d5 --- /dev/null +++ b/addon/components/report/ar-aging.hbs @@ -0,0 +1,60 @@ +
+
+

Accounts Receivable Aging

+ {{#if @data.as_of}} + As of {{format-date @data.as_of format="MMMM d, yyyy"}} + {{/if}} +
+ + {{! Summary buckets }} +
+ {{#each @data.buckets as |bucket|}} +
+

{{bucket.label}}

+

{{bucket.formatted_total}}

+

{{bucket.count}} invoice(s)

+
+ {{/each}} +
+ + {{! Detail rows }} + + + + + + + + + + + + + {{#each @data.invoices as |row|}} + + + + + + + + + {{else}} + + + + {{/each}} + + {{#if @data.total_outstanding}} + + + + + + + + {{/if}} +
InvoiceCustomerDue DateBalanceDays OverdueBucket
{{row.number}}{{row.customer_name}}{{format-date row.due_date format="MMM d, yyyy"}}{{row.formatted_balance}}{{row.days_overdue}} + {{row.bucket_label}} +
No outstanding receivables
Total Outstanding{{@data.formatted_total_outstanding}}
+
diff --git a/addon/components/report/balance-sheet.hbs b/addon/components/report/balance-sheet.hbs new file mode 100644 index 0000000..23731fb --- /dev/null +++ b/addon/components/report/balance-sheet.hbs @@ -0,0 +1,75 @@ +
+
+

Balance Sheet

+ {{#if @data.as_of}} + As of {{format-date @data.as_of format="MMMM d, yyyy"}} + {{/if}} + {{if @data.balanced "Balanced" "Unbalanced"}} +
+ + {{! Assets }} +
+

Assets

+ + + {{#each @data.assets as |item|}} + + + + + + {{/each}} + + + + + + + +
{{item.name}}{{item.code}}{{item.formatted_balance}}
Total Assets{{@data.formatted_total_assets}}
+
+ + {{! Liabilities }} +
+

Liabilities

+ + + {{#each @data.liabilities as |item|}} + + + + + + {{/each}} + + + + + + + +
{{item.name}}{{item.code}}{{item.formatted_balance}}
Total Liabilities{{@data.formatted_total_liabilities}}
+
+ + {{! Equity }} +
+

Equity

+ + + {{#each @data.equity as |item|}} + + + + + + {{/each}} + + + + + + + +
{{item.name}}{{item.code}}{{item.formatted_balance}}
Total Equity{{@data.formatted_total_equity}}
+
+
diff --git a/addon/components/report/cash-flow.hbs b/addon/components/report/cash-flow.hbs new file mode 100644 index 0000000..84c27b3 --- /dev/null +++ b/addon/components/report/cash-flow.hbs @@ -0,0 +1,60 @@ +
+
+

Cash Flow Statement

+ {{#if @data.period}} + {{@data.period}} + {{/if}} +
+ + {{! Operating Activities }} +
+

Operating Activities

+ + + {{#each @data.operating as |item|}} + + + + + {{/each}} + + + + + + + +
{{item.type}}{{item.formatted_net}}
Net Operating Cash Flow{{@data.formatted_net_operating}}
+
+ + {{! Financing Activities }} +
+

Financing Activities

+ + + {{#each @data.financing as |item|}} + + + + + {{/each}} + + + + + + + +
{{item.type}}{{item.formatted_net}}
Net Financing Cash Flow{{@data.formatted_net_financing}}
+
+ + {{! Net Change }} +
+
+ Net Change in Cash + + {{@data.formatted_net_change}} + +
+
+
diff --git a/addon/components/report/income-statement.hbs b/addon/components/report/income-statement.hbs new file mode 100644 index 0000000..424cd57 --- /dev/null +++ b/addon/components/report/income-statement.hbs @@ -0,0 +1,61 @@ +
+
+

Income Statement

+ {{#if @data.period}} + {{@data.period}} + {{/if}} + {{if @data.profitable "Profitable" "Net Loss"}} +
+ + {{! Revenue }} +
+

Revenue

+ + + {{#each @data.revenue as |item|}} + + + + + {{/each}} + + + + + + + +
{{item.name}}{{item.formatted_amount}}
Total Revenue{{@data.formatted_total_revenue}}
+
+ + {{! Expenses }} +
+

Expenses

+ + + {{#each @data.expenses as |item|}} + + + + + {{/each}} + + + + + + + +
{{item.name}}{{item.formatted_amount}}
Total Expenses{{@data.formatted_total_expenses}}
+
+ + {{! Net Income }} +
+
+ Net Income + + {{@data.formatted_net_income}} + +
+
+
diff --git a/addon/components/transaction/details.hbs b/addon/components/transaction/details.hbs new file mode 100644 index 0000000..2d45088 --- /dev/null +++ b/addon/components/transaction/details.hbs @@ -0,0 +1,42 @@ +
+
+
+ +

{{@transaction.gateway_transaction_id}}

+
+
+ + {{@transaction.status}} +
+
+ +

{{@transaction.gateway_code}}

+
+
+ +

{{@transaction.type}}

+
+
+ +

{{@transaction.formatted_amount}}

+
+
+ +

{{@transaction.currency}}

+
+
+ +

{{or @transaction.customer_name "—"}}

+
+
+ +

{{format-date @transaction.created_at format="MMM d, yyyy HH:mm"}}

+
+
+ {{#if @transaction.description}} +
+ +

{{@transaction.description}}

+
+ {{/if}} +
diff --git a/addon/components/transaction/panel-header.hbs b/addon/components/transaction/panel-header.hbs new file mode 100644 index 0000000..d7c7882 --- /dev/null +++ b/addon/components/transaction/panel-header.hbs @@ -0,0 +1,10 @@ +
+
+

{{@transaction.gateway_code}}

+

{{format-date @transaction.created_at format="MMM d, yyyy HH:mm"}}

+
+
+ {{@transaction.formatted_amount}} + {{@transaction.status}} +
+
diff --git a/addon/components/wallet/details.hbs b/addon/components/wallet/details.hbs new file mode 100644 index 0000000..afe036c --- /dev/null +++ b/addon/components/wallet/details.hbs @@ -0,0 +1,28 @@ +
+
+
+ +

{{@wallet.name}}

+
+
+ +

{{@wallet.type_label}}

+
+
+ +

{{@wallet.formatted_balance}}

+
+
+ +

{{@wallet.currency}}

+
+
+ + {{@wallet.status_label}} +
+
+ +

{{format-date @wallet.created_at format="MMM d, yyyy"}}

+
+
+
diff --git a/addon/components/wallet/panel-header.hbs b/addon/components/wallet/panel-header.hbs new file mode 100644 index 0000000..af2f4c1 --- /dev/null +++ b/addon/components/wallet/panel-header.hbs @@ -0,0 +1,10 @@ +
+
+

{{@wallet.type_label}} Wallet

+

{{@wallet.currency}}

+
+
+ {{@wallet.formatted_balance}} + {{@wallet.status_label}} +
+
diff --git a/addon/components/wallet/transaction-history.hbs b/addon/components/wallet/transaction-history.hbs new file mode 100644 index 0000000..cc30f40 --- /dev/null +++ b/addon/components/wallet/transaction-history.hbs @@ -0,0 +1,38 @@ +
+ {{#if this.loadTransactions.isRunning}} + + {{else}} + + + + + + + + + + + + + {{#each this.transactions as |txn|}} + + + + + + + + + {{else}} + + + + {{/each}} + +
DateTypeDescriptionAmountBalance AfterStatus
{{format-date txn.created_at format="MMM d, HH:mm"}}{{txn.type}}{{or txn.description "—"}} + {{txn.direction_sign}}{{txn.formatted_amount}} + {{txn.formatted_balance_after}} + {{txn.status}} +
No transactions
+ {{/if}} +
diff --git a/addon/components/wallet/transaction-history.js b/addon/components/wallet/transaction-history.js new file mode 100644 index 0000000..7fd12b4 --- /dev/null +++ b/addon/components/wallet/transaction-history.js @@ -0,0 +1,30 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WalletTransactionHistoryComponent extends Component { + @service fetch; + @tracked transactions = []; + @tracked meta = null; + @tracked page = 1; + + constructor(owner, args) { + super(owner, args); + this.loadTransactions.perform(); + } + + @task *loadTransactions() { + const wallet = this.args.wallet; + if (!wallet?.public_id) return; + try { + const result = yield this.fetch.get(`ledger/int/v1/wallets/${wallet.public_id}/transactions`, { + params: { page: this.page, limit: 20 }, + }); + this.transactions = result?.data ?? []; + this.meta = result?.meta ?? null; + } catch { + this.transactions = []; + } + } +} diff --git a/addon/controllers/accounting/accounts/index.js b/addon/controllers/accounting/accounts/index.js new file mode 100644 index 0000000..8452440 --- /dev/null +++ b/addon/controllers/accounting/accounts/index.js @@ -0,0 +1,50 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { task } from 'ember-concurrency'; + +export default class AccountingAccountsIndexController extends Controller { + @service hostRouter; + @service notifications; + @service modalsManager; + + queryParams = ['page', 'limit', 'sort', 'query', 'type']; + + @tracked page = 1; + @tracked limit = 100; + @tracked sort = 'code'; + @tracked query = null; + @tracked type = null; + @tracked table = null; + + columns = [ + { label: 'Code', valuePath: 'code', width: '80px', sortable: true }, + { label: 'Account Name', valuePath: 'name', width: '220px', sortable: true }, + { label: 'Type', valuePath: 'type_label', width: '100px' }, + { label: 'Balance', valuePath: 'formatted_balance', width: '140px', sortable: true }, + { label: 'Status', valuePath: 'status_label', width: '90px', component: 'table/cell/status' }, + ]; + + get actionButtons() { + return [ + { label: 'New Account', icon: 'plus', type: 'primary', onClick: this.createAccount }, + ]; + } + + @task({ restartable: true }) *search(query) { + this.query = query; + } + + @action createAccount() { + this.hostRouter.transitionTo('console.ledger.accounting.accounts.index.new'); + } + + @action viewAccount(account) { + this.hostRouter.transitionTo('console.ledger.accounting.accounts.index.details', account.public_id); + } + + @action reload() { + return this.hostRouter.refresh(); + } +} diff --git a/addon/controllers/accounting/accounts/index/details.js b/addon/controllers/accounting/accounts/index/details.js new file mode 100644 index 0000000..af61b0a --- /dev/null +++ b/addon/controllers/accounting/accounts/index/details.js @@ -0,0 +1,14 @@ +import Controller from '@ember/controller'; + +export default class AccountingAccountsIndexDetailsController extends Controller { + get tabs() { + return [ + { label: 'Details', route: 'console.ledger.accounting.accounts.index.details.index' }, + { label: 'General Ledger', route: 'console.ledger.accounting.accounts.index.details.ledger' }, + ]; + } + + get actionButtons() { + return []; + } +} diff --git a/addon/controllers/accounting/journal/index.js b/addon/controllers/accounting/journal/index.js new file mode 100644 index 0000000..8b878bd --- /dev/null +++ b/addon/controllers/accounting/journal/index.js @@ -0,0 +1,103 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { task } from 'ember-concurrency'; + +export default class AccountingJournalIndexController extends Controller { + @service hostRouter; + @service notifications; + @service modalsManager; + + queryParams = ['page', 'limit', 'sort', 'query', 'type']; + + @tracked page = 1; + @tracked limit = 30; + @tracked sort = '-date'; + @tracked query = null; + @tracked type = null; + @tracked table = null; + + columns = [ + { label: 'Date', valuePath: 'date', width: '120px', sortable: true, component: 'table/cell/date' }, + { label: 'Entry #', valuePath: 'number', width: '120px' }, + { label: 'Description', valuePath: 'description', width: '220px' }, + { label: 'Debit Account', valuePath: 'debit_account_name', width: '160px' }, + { label: 'Credit Account', valuePath: 'credit_account_name', width: '160px' }, + { label: 'Amount', valuePath: 'formatted_amount', width: '120px', sortable: true }, + { label: 'Source', valuePath: 'entry_source', width: '90px' }, + ]; + + get actionButtons() { + return [ + { label: 'New Entry', icon: 'plus', type: 'primary', onClick: this.createEntry }, + ]; + } + + get bulkActions() { + return [ + { label: 'Delete Selected', icon: 'trash', fn: this.bulkDeleteEntries }, + ]; + } + + @task({ restartable: true }) *search(query) { + this.query = query; + } + + @action createEntry() { + this.hostRouter.transitionTo('console.ledger.accounting.journal.index.new'); + } + + @action viewEntry(entry) { + this.hostRouter.transitionTo('console.ledger.accounting.journal.index.details', entry.public_id); + } + + @action async deleteEntry(entry) { + if (entry.is_system_entry) { + return this.notifications.warning('System journal entries cannot be deleted.'); + } + this.modalsManager.confirm({ + title: 'Delete Journal Entry?', + body: 'This action cannot be undone.', + confirm: async (modal) => { + modal.startLoading(); + try { + await entry.destroyRecord(); + this.notifications.success('Journal entry deleted.'); + this.hostRouter.refresh(); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } + + @action async bulkDeleteEntries(selected) { + const manual = selected.filter((e) => !e.is_system_entry); + if (!manual.length) { + return this.notifications.warning('Only manual entries can be deleted.'); + } + this.modalsManager.confirm({ + title: `Delete ${manual.length} manual entry(s)?`, + body: 'This action cannot be undone.', + confirm: async (modal) => { + modal.startLoading(); + try { + await Promise.all(manual.map((e) => e.destroyRecord())); + this.notifications.success(`${manual.length} entry(s) deleted.`); + this.hostRouter.refresh(); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } + + @action reload() { + return this.hostRouter.refresh(); + } +} diff --git a/addon/controllers/accounting/journal/index/details.js b/addon/controllers/accounting/journal/index/details.js new file mode 100644 index 0000000..b37c819 --- /dev/null +++ b/addon/controllers/accounting/journal/index/details.js @@ -0,0 +1,39 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; + +export default class AccountingJournalIndexDetailsController extends Controller { + @service notifications; + @service modalsManager; + @service hostRouter; + + get tabs() { + return [{ label: 'Details', route: 'console.ledger.accounting.journal.index.details.index' }]; + } + + get actionButtons() { + const entry = this.model; + if (entry?.is_system_entry) return []; + return [{ label: 'Delete', icon: 'trash', type: 'danger', onClick: this.deleteEntry }]; + } + + @action async deleteEntry() { + const entry = this.model; + this.modalsManager.confirm({ + title: 'Delete Journal Entry?', + body: 'This action cannot be undone.', + confirm: async (modal) => { + modal.startLoading(); + try { + await entry.destroyRecord(); + this.notifications.success('Journal entry deleted.'); + this.hostRouter.transitionTo('console.ledger.accounting.journal.index'); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } +} diff --git a/addon/controllers/billing/invoices/index.js b/addon/controllers/billing/invoices/index.js new file mode 100644 index 0000000..d66d8dd --- /dev/null +++ b/addon/controllers/billing/invoices/index.js @@ -0,0 +1,134 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { task } from 'ember-concurrency'; + +export default class BillingInvoicesIndexController extends Controller { + @service store; + @service notifications; + @service modalsManager; + @service intl; + @service hostRouter; + @service crud; + + queryParams = ['page', 'limit', 'sort', 'query', 'status']; + + @tracked page = 1; + @tracked limit = 30; + @tracked sort = '-created_at'; + @tracked query = null; + @tracked status = null; + @tracked table = null; + + columns = [ + { + label: 'Invoice #', + valuePath: 'number', + width: '140px', + sortable: true, + }, + { + label: 'Customer', + valuePath: 'customer_name', + width: '180px', + }, + { + label: 'Due Date', + valuePath: 'due_at', + width: '120px', + sortable: true, + component: 'table/cell/date', + }, + { + label: 'Total', + valuePath: 'formatted_total', + width: '120px', + sortable: true, + }, + { + label: 'Balance', + valuePath: 'formatted_balance', + width: '120px', + }, + { + label: 'Status', + valuePath: 'status', + width: '100px', + component: 'table/cell/status', + }, + ]; + + get actionButtons() { + return [ + { + label: 'New Invoice', + icon: 'plus', + type: 'primary', + onClick: this.createInvoice, + }, + ]; + } + + get bulkActions() { + return [ + { + label: 'Delete Selected', + icon: 'trash', + fn: this.bulkDeleteInvoices, + }, + ]; + } + + @task({ restartable: true }) *search(query) { + this.query = query; + } + + @action createInvoice() { + this.hostRouter.transitionTo('console.ledger.billing.invoices.index.new'); + } + + @action viewInvoice(invoice) { + this.hostRouter.transitionTo('console.ledger.billing.invoices.index.details', invoice.public_id); + } + + @action async deleteInvoice(invoice) { + this.modalsManager.confirm({ + title: `Delete Invoice ${invoice.number}?`, + body: 'This action cannot be undone.', + confirm: async (modal) => { + modal.startLoading(); + try { + await invoice.destroyRecord(); + this.notifications.success('Invoice deleted.'); + this.hostRouter.refresh(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } + + @action async bulkDeleteInvoices(selected) { + this.modalsManager.confirm({ + title: `Delete ${selected.length} invoice(s)?`, + body: 'This action cannot be undone.', + confirm: async (modal) => { + modal.startLoading(); + try { + await Promise.all(selected.map((i) => i.destroyRecord())); + this.notifications.success(`${selected.length} invoice(s) deleted.`); + this.hostRouter.refresh(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } + + @action reload() { + return this.hostRouter.refresh(); + } +} diff --git a/addon/controllers/billing/invoices/index/details.js b/addon/controllers/billing/invoices/index/details.js new file mode 100644 index 0000000..47f22d5 --- /dev/null +++ b/addon/controllers/billing/invoices/index/details.js @@ -0,0 +1,71 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; + +export default class BillingInvoicesIndexDetailsController extends Controller { + @service notifications; + @service modalsManager; + @service fetch; + @service hostRouter; + + get tabs() { + return [ + { label: 'Details', route: 'console.ledger.billing.invoices.index.details.index' }, + { label: 'Line Items', route: 'console.ledger.billing.invoices.index.details.line-items' }, + { label: 'Transactions', route: 'console.ledger.billing.invoices.index.details.transactions' }, + ]; + } + + get actionButtons() { + const invoice = this.model; + const buttons = []; + + if (invoice?.status === 'draft') { + buttons.push({ label: 'Send', icon: 'paper-plane', type: 'primary', onClick: this.sendInvoice }); + } + if (['sent', 'overdue', 'partial'].includes(invoice?.status)) { + buttons.push({ label: 'Record Payment', icon: 'check-circle', type: 'success', onClick: this.recordPayment }); + } + if (!['paid', 'void'].includes(invoice?.status)) { + buttons.push({ label: 'Void', icon: 'ban', type: 'danger', onClick: this.voidInvoice }); + } + + return buttons; + } + + @action async sendInvoice() { + const invoice = this.model; + try { + await this.fetch.post(`ledger/int/v1/invoices/${invoice.public_id}/send`); + this.notifications.success('Invoice sent successfully.'); + this.hostRouter.refresh(); + } catch (error) { + this.notifications.serverError(error); + } + } + + @action async recordPayment() { + const invoice = this.model; + this.modalsManager.show('modals/record-payment', { invoice }); + } + + @action async voidInvoice() { + const invoice = this.model; + this.modalsManager.confirm({ + title: `Void Invoice ${invoice.number}?`, + body: 'This will mark the invoice as void and cannot be undone.', + confirm: async (modal) => { + modal.startLoading(); + try { + await this.fetch.post(`ledger/int/v1/invoices/${invoice.public_id}/void`); + this.notifications.success('Invoice voided.'); + this.hostRouter.refresh(); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } +} diff --git a/addon/controllers/billing/transactions/index.js b/addon/controllers/billing/transactions/index.js new file mode 100644 index 0000000..0f5a9bc --- /dev/null +++ b/addon/controllers/billing/transactions/index.js @@ -0,0 +1,43 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { task } from 'ember-concurrency'; + +export default class BillingTransactionsIndexController extends Controller { + @service hostRouter; + + queryParams = ['page', 'limit', 'sort', 'query', 'status']; + + @tracked page = 1; + @tracked limit = 30; + @tracked sort = '-created_at'; + @tracked query = null; + @tracked status = null; + @tracked table = null; + + columns = [ + { label: 'Date', valuePath: 'created_at', width: '140px', sortable: true, component: 'table/cell/date' }, + { label: 'Reference', valuePath: 'gateway_transaction_id', width: '200px' }, + { label: 'Gateway', valuePath: 'gateway_code', width: '120px' }, + { label: 'Customer', valuePath: 'customer_name', width: '160px' }, + { label: 'Amount', valuePath: 'formatted_amount', width: '120px', sortable: true }, + { label: 'Status', valuePath: 'status', width: '100px', component: 'table/cell/status' }, + ]; + + get actionButtons() { + return []; + } + + @task({ restartable: true }) *search(query) { + this.query = query; + } + + @action viewTransaction(txn) { + this.hostRouter.transitionTo('console.ledger.billing.transactions.index.details', txn.public_id); + } + + @action reload() { + return this.hostRouter.refresh(); + } +} diff --git a/addon/controllers/billing/transactions/index/details.js b/addon/controllers/billing/transactions/index/details.js new file mode 100644 index 0000000..8720d6b --- /dev/null +++ b/addon/controllers/billing/transactions/index/details.js @@ -0,0 +1,11 @@ +import Controller from '@ember/controller'; + +export default class BillingTransactionsIndexDetailsController extends Controller { + get tabs() { + return [{ label: 'Details', route: 'console.ledger.billing.transactions.index.details.index' }]; + } + + get actionButtons() { + return []; + } +} diff --git a/addon/controllers/reports/index.js b/addon/controllers/reports/index.js new file mode 100644 index 0000000..998f605 --- /dev/null +++ b/addon/controllers/reports/index.js @@ -0,0 +1,57 @@ +import Controller from '@ember/controller'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class ReportsIndexController extends Controller { + @service fetch; + + @tracked activeReport = 'balance-sheet'; + @tracked reportData = null; + @tracked isLoading = false; + @tracked dateFrom = null; + @tracked dateTo = null; + @tracked asOf = null; + + reportTabs = [ + { id: 'balance-sheet', label: 'Balance Sheet' }, + { id: 'income-statement', label: 'Income Statement' }, + { id: 'cash-flow', label: 'Cash Flow' }, + { id: 'ar-aging', label: 'AR Aging' }, + ]; + + @task *loadReport() { + this.isLoading = true; + try { + const params = {}; + if (this.dateFrom) params.date_from = this.dateFrom; + if (this.dateTo) params.date_to = this.dateTo; + if (this.asOf) params.as_of = this.asOf; + + const endpointMap = { + 'balance-sheet': 'ledger/int/v1/reports/balance-sheet', + 'income-statement': 'ledger/int/v1/reports/income-statement', + 'cash-flow': 'ledger/int/v1/reports/cash-flow', + 'ar-aging': 'ledger/int/v1/reports/ar-aging', + }; + + const result = yield this.fetch.get(endpointMap[this.activeReport], { params }); + this.reportData = result?.data ?? null; + } catch { + this.reportData = null; + } finally { + this.isLoading = false; + } + } + + @action selectReport(reportId) { + this.activeReport = reportId; + this.reportData = null; + this.loadReport.perform(); + } + + @action runReport() { + this.loadReport.perform(); + } +} diff --git a/addon/controllers/settings/gateways/index.js b/addon/controllers/settings/gateways/index.js new file mode 100644 index 0000000..118e1d9 --- /dev/null +++ b/addon/controllers/settings/gateways/index.js @@ -0,0 +1,93 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { task } from 'ember-concurrency'; + +export default class SettingsGatewaysIndexController extends Controller { + @service hostRouter; + @service notifications; + @service modalsManager; + @service fetch; + + @tracked query = null; + @tracked table = null; + @tracked availableDrivers = []; + + columns = [ + { label: 'Name', valuePath: 'name', width: '180px' }, + { label: 'Driver', valuePath: 'driver_label', width: '120px' }, + { label: 'Environment', valuePath: 'environment', width: '100px' }, + { label: 'Default', valuePath: 'is_default', width: '80px', component: 'table/cell/boolean' }, + { label: 'Status', valuePath: 'status_label', width: '90px', component: 'table/cell/status' }, + ]; + + get actionButtons() { + return [ + { label: 'Add Gateway', icon: 'plus', type: 'primary', onClick: this.addGateway }, + ]; + } + + @task({ restartable: true }) *search(query) { + this.query = query; + } + + @task *loadDrivers() { + try { + const result = yield this.fetch.get('ledger/int/v1/gateways/drivers'); + this.availableDrivers = result?.data ?? []; + } catch { + this.availableDrivers = []; + } + } + + @action addGateway() { + this.loadDrivers.perform().then(() => { + this.modalsManager.show('modals/gateway-form', { + title: 'Add Payment Gateway', + availableDrivers: this.availableDrivers, + confirm: async (modal) => { + modal.startLoading(); + try { + const gateway = modal.getOption('gateway'); + const record = this.store.createRecord('gateway', gateway); + await record.save(); + this.notifications.success('Gateway added.'); + this.hostRouter.refresh(); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + }); + } + + @action viewGateway(gateway) { + this.hostRouter.transitionTo('console.ledger.settings.gateways.index.details', gateway.public_id); + } + + @action async deleteGateway(gateway) { + this.modalsManager.confirm({ + title: 'Remove Payment Gateway?', + body: `This will remove "${gateway.name}". Any active integrations using this gateway will stop working.`, + confirm: async (modal) => { + modal.startLoading(); + try { + await gateway.destroyRecord(); + this.notifications.success('Gateway removed.'); + this.hostRouter.refresh(); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } + + @action reload() { + return this.hostRouter.refresh(); + } +} diff --git a/addon/controllers/settings/gateways/index/details.js b/addon/controllers/settings/gateways/index/details.js new file mode 100644 index 0000000..b1b82c7 --- /dev/null +++ b/addon/controllers/settings/gateways/index/details.js @@ -0,0 +1,63 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; + +export default class SettingsGatewaysIndexDetailsController extends Controller { + @service notifications; + @service modalsManager; + @service hostRouter; + @service fetch; + + get tabs() { + return [ + { label: 'Configuration', route: 'console.ledger.settings.gateways.index.details.index' }, + { label: 'Webhook Events', route: 'console.ledger.settings.gateways.index.details.webhooks' }, + ]; + } + + get actionButtons() { + return [ + { label: 'Edit', icon: 'pencil', type: 'default', onClick: this.editGateway }, + { label: 'Remove', icon: 'trash', type: 'danger', onClick: this.deleteGateway }, + ]; + } + + @action editGateway() { + this.modalsManager.show('modals/gateway-form', { + title: 'Edit Payment Gateway', + gateway: this.model.serialize(), + confirm: async (modal) => { + modal.startLoading(); + try { + const updates = modal.getOption('gateway'); + this.model.setProperties(updates); + await this.model.save(); + this.notifications.success('Gateway updated.'); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } + + @action async deleteGateway() { + this.modalsManager.confirm({ + title: 'Remove Payment Gateway?', + body: `This will remove "${this.model.name}". Any active integrations using this gateway will stop working.`, + confirm: async (modal) => { + modal.startLoading(); + try { + await this.model.destroyRecord(); + this.notifications.success('Gateway removed.'); + this.hostRouter.transitionTo('console.ledger.settings.gateways.index'); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } +} diff --git a/addon/controllers/wallets/index.js b/addon/controllers/wallets/index.js new file mode 100644 index 0000000..ad706f9 --- /dev/null +++ b/addon/controllers/wallets/index.js @@ -0,0 +1,69 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { task } from 'ember-concurrency'; + +export default class WalletsIndexController extends Controller { + @service hostRouter; + @service notifications; + @service modalsManager; + @service fetch; + + queryParams = ['page', 'limit', 'sort', 'query', 'type']; + + @tracked page = 1; + @tracked limit = 30; + @tracked sort = '-created_at'; + @tracked query = null; + @tracked type = null; + @tracked table = null; + + columns = [ + { label: 'Name', valuePath: 'name', width: '200px', sortable: true }, + { label: 'Type', valuePath: 'type_label', width: '100px' }, + { label: 'Currency', valuePath: 'currency', width: '80px' }, + { label: 'Balance', valuePath: 'formatted_balance', width: '140px', sortable: true }, + { label: 'Status', valuePath: 'status_label', width: '100px', component: 'table/cell/status' }, + ]; + + get actionButtons() { + return []; + } + + get bulkActions() { + return []; + } + + @task({ restartable: true }) *search(query) { + this.query = query; + } + + @action viewWallet(wallet) { + this.hostRouter.transitionTo('console.ledger.wallets.index.details', wallet.public_id); + } + + @action async freezeWallet(wallet) { + try { + await this.fetch.post(`ledger/int/v1/wallets/${wallet.public_id}/freeze`); + this.notifications.success('Wallet frozen.'); + this.hostRouter.refresh(); + } catch (error) { + this.notifications.serverError(error); + } + } + + @action async unfreezeWallet(wallet) { + try { + await this.fetch.post(`ledger/int/v1/wallets/${wallet.public_id}/unfreeze`); + this.notifications.success('Wallet unfrozen.'); + this.hostRouter.refresh(); + } catch (error) { + this.notifications.serverError(error); + } + } + + @action reload() { + return this.hostRouter.refresh(); + } +} diff --git a/addon/controllers/wallets/index/details.js b/addon/controllers/wallets/index/details.js new file mode 100644 index 0000000..0271983 --- /dev/null +++ b/addon/controllers/wallets/index/details.js @@ -0,0 +1,59 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; + +export default class WalletsIndexDetailsController extends Controller { + @service notifications; + @service modalsManager; + @service fetch; + @service hostRouter; + + get tabs() { + return [ + { label: 'Details', route: 'console.ledger.wallets.index.details.index' }, + { label: 'Transactions', route: 'console.ledger.wallets.index.details.transactions' }, + ]; + } + + get actionButtons() { + const wallet = this.model; + const buttons = [ + { label: 'Deposit', icon: 'arrow-down', type: 'success', onClick: this.depositFunds }, + { label: 'Withdraw', icon: 'arrow-up', type: 'default', onClick: this.withdrawFunds }, + ]; + if (wallet?.is_frozen) { + buttons.push({ label: 'Unfreeze', icon: 'unlock', type: 'primary', onClick: this.unfreezeWallet }); + } else { + buttons.push({ label: 'Freeze', icon: 'lock', type: 'danger', onClick: this.freezeWallet }); + } + return buttons; + } + + @action async depositFunds() { + this.modalsManager.show('modals/wallet-deposit', { wallet: this.model }); + } + + @action async withdrawFunds() { + this.modalsManager.show('modals/wallet-withdraw', { wallet: this.model }); + } + + @action async freezeWallet() { + try { + await this.fetch.post(`ledger/int/v1/wallets/${this.model.public_id}/freeze`); + this.notifications.success('Wallet frozen.'); + this.hostRouter.refresh(); + } catch (error) { + this.notifications.serverError(error); + } + } + + @action async unfreezeWallet() { + try { + await this.fetch.post(`ledger/int/v1/wallets/${this.model.public_id}/unfreeze`); + this.notifications.success('Wallet unfrozen.'); + this.hostRouter.refresh(); + } catch (error) { + this.notifications.serverError(error); + } + } +} diff --git a/addon/engine.js b/addon/engine.js index 1a72dc7..cfc151b 100644 --- a/addon/engine.js +++ b/addon/engine.js @@ -2,10 +2,9 @@ import Engine from '@ember/engine'; import loadInitializers from 'ember-load-initializers'; import Resolver from 'ember-resolver'; import config from './config/environment'; -import services from '@fleetbase/ember-core/exports/services'; +import { services, externalRoutes } from '@fleetbase/ember-core/exports'; const { modulePrefix } = config; -const externalRoutes = ['console', 'extensions']; export default class LedgerEngine extends Engine { modulePrefix = modulePrefix; @@ -14,10 +13,6 @@ export default class LedgerEngine extends Engine { services, externalRoutes, }; - setupExtension = function (app, engine, universe) { - // register menu item in header - universe.registerHeaderMenuItem('Ledger', 'console.ledger', { icon: 'calculator', priority: 1 }); - }; } loadInitializers(LedgerEngine, modulePrefix); diff --git a/addon/extension.js b/addon/extension.js index 3a3a373..fd5ca41 100644 --- a/addon/extension.js +++ b/addon/extension.js @@ -1,9 +1,26 @@ -import { Widget, ExtensionComponent, Hook } from '@fleetbase/ember-core/contracts'; +import { Widget, ExtensionComponent } from '@fleetbase/ember-core/contracts'; export default { setupExtension(app, universe) { - // const menuService = universe.getService('universe/menu-service'); - // const hookService = universe.getService('universe/hook-service'); - // const widgetService = universe.getService('universe/widget-service'); - } + const menuService = universe.getService('menu'); + const widgetService = universe.getService('widget'); + + // Register Ledger in the console header navigation + menuService.registerHeaderMenuItem('Ledger', 'console.ledger', { icon: 'calculator', priority: 4 }); + + // Register dashboard widget + const widgets = [ + new Widget({ + id: 'ledger-financial-summary-widget', + name: 'Financial Summary', + description: 'Key financial metrics including revenue, expenses, and outstanding invoices.', + icon: 'calculator', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/financial-summary'), + grid_options: { w: 6, h: 8, minW: 6, minH: 8 }, + options: { title: 'Financial Summary' }, + }), + ]; + + widgetService.registerWidgets('dashboard', widgets); + }, }; diff --git a/addon/models/account.js b/addon/models/account.js new file mode 100644 index 0000000..4a60cff --- /dev/null +++ b/addon/models/account.js @@ -0,0 +1,38 @@ +import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; + +export default class AccountModel extends Model { + @attr('string') public_id; + @attr('string') name; + @attr('string') code; + @attr('string') type; + @attr('string') description; + @attr('string') currency; + @attr('number') balance; + @attr('boolean') is_active; + @attr('date') created_at; + @attr('date') updated_at; + + @computed('balance', 'currency') + get formatted_balance() { + const amount = (this.balance || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); + } + + @computed('type') + get type_label() { + const labels = { + asset: 'Asset', + liability: 'Liability', + equity: 'Equity', + revenue: 'Revenue', + expense: 'Expense', + }; + return labels[this.type] || this.type; + } + + @computed('is_active') + get status_label() { + return this.is_active ? 'Active' : 'Inactive'; + } +} diff --git a/addon/models/gateway.js b/addon/models/gateway.js new file mode 100644 index 0000000..d308f0e --- /dev/null +++ b/addon/models/gateway.js @@ -0,0 +1,40 @@ +import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; + +export default class GatewayModel extends Model { + @attr('string') public_id; + @attr('string') name; + @attr('string') code; + @attr('string') type; + @attr('string') description; + @attr('string') status; + @attr('boolean') sandbox; + @attr('raw') config_schema; + @attr('date') created_at; + @attr('date') updated_at; + + @computed('status') + get status_badge_color() { + return this.status === 'active' ? 'green' : 'gray'; + } + + @computed('sandbox') + get mode_label() { + return this.sandbox ? 'Sandbox' : 'Live'; + } + + @computed('sandbox') + get mode_badge_color() { + return this.sandbox ? 'yellow' : 'green'; + } + + @computed('code') + get icon_name() { + const icons = { + stripe: 'credit-card', + qpay: 'money-bill', + cash: 'money-bill-wave', + }; + return icons[this.code] || 'credit-card'; + } +} diff --git a/addon/models/invoice.js b/addon/models/invoice.js new file mode 100644 index 0000000..f06a9ba --- /dev/null +++ b/addon/models/invoice.js @@ -0,0 +1,71 @@ +import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; + +export default class InvoiceModel extends Model { + @attr('string') public_id; + @attr('string') number; + @attr('string') status; + @attr('string') currency; + @attr('number') subtotal; + @attr('number') tax; + @attr('number') total; + @attr('number') amount_paid; + @attr('number') balance; + @attr('string') notes; + @attr('string') customer_name; + @attr('string') customer_email; + @attr('string') customer_phone; + @attr('raw') line_items; + @attr('raw') meta; + @attr('date') due_at; + @attr('date') paid_at; + @attr('date') voided_at; + @attr('date') created_at; + @attr('date') updated_at; + + @computed('total', 'currency') + get formatted_total() { + const amount = (this.total || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); + } + + @computed('balance', 'currency') + get formatted_balance() { + const amount = (this.balance || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); + } + + @computed('amount_paid', 'currency') + get formatted_amount_paid() { + const amount = (this.amount_paid || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); + } + + @computed('status') + get status_badge_color() { + const colors = { + draft: 'gray', + sent: 'blue', + paid: 'green', + partial: 'yellow', + overdue: 'red', + void: 'gray', + }; + return colors[this.status] || 'gray'; + } + + @computed('status') + get is_paid() { + return this.status === 'paid'; + } + + @computed('status') + get is_overdue() { + return this.status === 'overdue'; + } + + @computed('status') + get is_draft() { + return this.status === 'draft'; + } +} diff --git a/addon/models/journal.js b/addon/models/journal.js new file mode 100644 index 0000000..9c035da --- /dev/null +++ b/addon/models/journal.js @@ -0,0 +1,47 @@ +import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; + +export default class JournalModel extends Model { + @attr('string') public_id; + @attr('string') number; + @attr('string') type; + @attr('string') currency; + @attr('number') amount; + @attr('string') description; + @attr('string') debit_account_uuid; + @attr('string') debit_account_name; + @attr('string') debit_account_code; + @attr('string') credit_account_uuid; + @attr('string') credit_account_name; + @attr('string') credit_account_code; + @attr('boolean') is_system_entry; + @attr('raw') meta; + @attr('date') date; + @attr('date') created_at; + @attr('date') updated_at; + + @computed('amount', 'currency') + get formatted_amount() { + const value = (this.amount || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); + } + + @computed('is_system_entry') + get entry_source() { + return this.is_system_entry ? 'System' : 'Manual'; + } + + @computed('type') + get type_label() { + const labels = { + general: 'General', + payment: 'Payment', + refund: 'Refund', + adjustment: 'Adjustment', + deposit: 'Deposit', + withdrawal: 'Withdrawal', + transfer: 'Transfer', + }; + return labels[this.type] || this.type; + } +} diff --git a/addon/models/transaction.js b/addon/models/transaction.js new file mode 100644 index 0000000..38ecef7 --- /dev/null +++ b/addon/models/transaction.js @@ -0,0 +1,37 @@ +import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; + +export default class TransactionModel extends Model { + @attr('string') public_id; + @attr('string') gateway_transaction_id; + @attr('string') gateway_code; + @attr('string') type; + @attr('string') status; + @attr('string') currency; + @attr('number') amount; + @attr('string') description; + @attr('string') customer_name; + @attr('string') customer_email; + @attr('raw') meta; + @attr('date') created_at; + @attr('date') updated_at; + + @computed('amount', 'currency') + get formatted_amount() { + const value = (this.amount || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); + } + + @computed('status') + get status_badge_color() { + const colors = { + pending: 'yellow', + succeeded: 'green', + failed: 'red', + refunded: 'blue', + partially_refunded: 'blue', + cancelled: 'gray', + }; + return colors[this.status] || 'gray'; + } +} diff --git a/addon/models/wallet-transaction.js b/addon/models/wallet-transaction.js new file mode 100644 index 0000000..1147d09 --- /dev/null +++ b/addon/models/wallet-transaction.js @@ -0,0 +1,51 @@ +import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; + +export default class WalletTransactionModel extends Model { + @attr('string') public_id; + @attr('string') wallet_uuid; + @attr('string') type; + @attr('string') direction; + @attr('string') status; + @attr('string') currency; + @attr('number') amount; + @attr('number') balance_after; + @attr('string') description; + @attr('string') reference; + @attr('raw') meta; + @attr('date') created_at; + @attr('date') updated_at; + + @computed('amount', 'currency') + get formatted_amount() { + const value = (this.amount || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); + } + + @computed('balance_after', 'currency') + get formatted_balance_after() { + const value = (this.balance_after || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); + } + + @computed('direction') + get direction_sign() { + return this.direction === 'credit' ? '+' : '-'; + } + + @computed('direction') + get direction_color() { + return this.direction === 'credit' ? 'green' : 'red'; + } + + @computed('status') + get status_badge_color() { + const colors = { + pending: 'yellow', + completed: 'green', + failed: 'red', + reversed: 'blue', + }; + return colors[this.status] || 'gray'; + } +} diff --git a/addon/models/wallet.js b/addon/models/wallet.js new file mode 100644 index 0000000..fe232e0 --- /dev/null +++ b/addon/models/wallet.js @@ -0,0 +1,45 @@ +import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; + +export default class WalletModel extends Model { + @attr('string') public_id; + @attr('string') name; + @attr('string') owner_uuid; + @attr('string') owner_type; + @attr('string') type; + @attr('string') status; + @attr('string') currency; + @attr('number') balance; + @attr('boolean') is_frozen; + @attr('date') created_at; + @attr('date') updated_at; + + @computed('balance', 'currency') + get formatted_balance() { + const amount = (this.balance || 0) / 100; + return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); + } + + @computed('type') + get type_label() { + const labels = { + driver: 'Driver', + customer: 'Customer', + company: 'Company', + system: 'System', + }; + return labels[this.type] || this.type; + } + + @computed('is_frozen', 'status') + get status_label() { + if (this.is_frozen) return 'Frozen'; + return this.status === 'active' ? 'Active' : 'Inactive'; + } + + @computed('is_frozen', 'status') + get status_badge_color() { + if (this.is_frozen) return 'blue'; + return this.status === 'active' ? 'green' : 'gray'; + } +} diff --git a/addon/routes.js b/addon/routes.js index 3217c6b..8690c7b 100644 --- a/addon/routes.js +++ b/addon/routes.js @@ -1,53 +1,76 @@ import buildRoutes from 'ember-engines/routes'; export default buildRoutes(function () { + // Dashboard this.route('home', { path: '/' }); - this.route('products', function () { - this.route('index', { path: '/' }, function () { - this.route('new'); - this.route('details', { path: '/:public_id' }); - this.route('edit', { path: '/edit/:public_id' }); + + // Billing + this.route('billing', function () { + this.route('invoices', function () { + this.route('index', { path: '/' }, function () { + this.route('new'); + this.route('details', { path: '/:public_id' }, function () { + this.route('index', { path: '/' }); + this.route('line-items'); + this.route('transactions'); + }); + }); }); - }); - this.route('inventory', function () { - this.route('low-stock'); - this.route('expired-stock'); - this.route('index', { path: '/' }, function () { - this.route('new'); - this.route('new-stock-adjustment'); - this.route('details', { path: '/:public_id' }); - this.route('edit', { path: '/edit/:public_id' }); + this.route('transactions', function () { + this.route('index', { path: '/' }, function () { + this.route('details', { path: '/:public_id' }, function () { + this.route('index', { path: '/' }); + }); + }); }); }); - this.route('warehouses', function () { + + // Wallets + this.route('wallets', function () { this.route('index', { path: '/' }, function () { - this.route('new'); - this.route('details', { path: '/:public_id' }); - this.route('edit', { path: '/edit/:public_id' }); + this.route('details', { path: '/:public_id' }, function () { + this.route('index', { path: '/' }); + this.route('transactions'); + }); }); }); - this.route('suppliers', function () { - this.route('index', { path: '/' }, function () { - this.route('new'); - this.route('details', { path: '/:public_id' }); - this.route('edit', { path: '/edit/:public_id' }); + + // Accounting + this.route('accounting', function () { + this.route('journal', function () { + this.route('index', { path: '/' }, function () { + this.route('new'); + this.route('details', { path: '/:public_id' }, function () { + this.route('index', { path: '/' }); + }); + }); }); - }); - this.route('sales-orders', function () { - this.route('index', { path: '/' }, function () { - this.route('new'); - this.route('details', { path: '/:public_id' }); - this.route('edit', { path: '/edit/:public_id' }); + this.route('accounts', function () { + this.route('index', { path: '/' }, function () { + this.route('new'); + this.route('details', { path: '/:public_id' }, function () { + this.route('index', { path: '/' }); + this.route('ledger'); + }); + }); }); }); - this.route('purchase-orders', function () { - this.route('index', { path: '/' }, function () { - this.route('new'); - this.route('details', { path: '/:public_id' }); - this.route('edit', { path: '/edit/:public_id' }); + + // Reports + this.route('reports', function () { + this.route('index', { path: '/' }); + }); + + // Settings + this.route('settings', function () { + this.route('gateways', function () { + this.route('index', { path: '/' }, function () { + this.route('new'); + this.route('details', { path: '/:public_id' }, function () { + this.route('index', { path: '/' }); + this.route('webhooks'); + }); + }); }); }); - this.route('batch', function () {}); - this.route('audits', function () {}); - this.route('reports', function () {}); }); diff --git a/addon/routes/accounting/accounts.js b/addon/routes/accounting/accounts.js new file mode 100644 index 0000000..aec5a73 --- /dev/null +++ b/addon/routes/accounting/accounts.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class AccountingAccountsRoute extends Route {} diff --git a/addon/routes/accounting/accounts/index.js b/addon/routes/accounting/accounts/index.js new file mode 100644 index 0000000..18206a4 --- /dev/null +++ b/addon/routes/accounting/accounts/index.js @@ -0,0 +1,18 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class AccountingAccountsIndexRoute extends Route { + @service store; + + queryParams = { + page: { refreshModel: true }, + limit: { refreshModel: true }, + sort: { refreshModel: true }, + query: { refreshModel: true }, + type: { refreshModel: true }, + }; + + model(params) { + return this.store.query('account', { ...params, namespace: 'ledger/int/v1' }); + } +} diff --git a/addon/routes/accounting/accounts/index/details.js b/addon/routes/accounting/accounts/index/details.js new file mode 100644 index 0000000..b7e8853 --- /dev/null +++ b/addon/routes/accounting/accounts/index/details.js @@ -0,0 +1,12 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class AccountingAccountsIndexDetailsRoute extends Route { + @service store; + + model({ public_id }) { + return this.store.findRecord('account', public_id, { + adapterOptions: { namespace: 'ledger/int/v1' }, + }); + } +} diff --git a/addon/routes/accounting/journal.js b/addon/routes/accounting/journal.js new file mode 100644 index 0000000..40e286e --- /dev/null +++ b/addon/routes/accounting/journal.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class AccountingJournalRoute extends Route {} diff --git a/addon/routes/accounting/journal/index.js b/addon/routes/accounting/journal/index.js new file mode 100644 index 0000000..5f8ef48 --- /dev/null +++ b/addon/routes/accounting/journal/index.js @@ -0,0 +1,18 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class AccountingJournalIndexRoute extends Route { + @service store; + + queryParams = { + page: { refreshModel: true }, + limit: { refreshModel: true }, + sort: { refreshModel: true }, + query: { refreshModel: true }, + type: { refreshModel: true }, + }; + + model(params) { + return this.store.query('journal', { ...params, namespace: 'ledger/int/v1' }); + } +} diff --git a/addon/routes/accounting/journal/index/details.js b/addon/routes/accounting/journal/index/details.js new file mode 100644 index 0000000..f2ef9f4 --- /dev/null +++ b/addon/routes/accounting/journal/index/details.js @@ -0,0 +1,12 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class AccountingJournalIndexDetailsRoute extends Route { + @service store; + + model({ public_id }) { + return this.store.findRecord('journal', public_id, { + adapterOptions: { namespace: 'ledger/int/v1' }, + }); + } +} diff --git a/addon/routes/billing/invoices.js b/addon/routes/billing/invoices.js new file mode 100644 index 0000000..2a54194 --- /dev/null +++ b/addon/routes/billing/invoices.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class BillingInvoicesRoute extends Route {} diff --git a/addon/routes/billing/invoices/index.js b/addon/routes/billing/invoices/index.js new file mode 100644 index 0000000..7bd8401 --- /dev/null +++ b/addon/routes/billing/invoices/index.js @@ -0,0 +1,18 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class BillingInvoicesIndexRoute extends Route { + @service store; + + queryParams = { + page: { refreshModel: true }, + limit: { refreshModel: true }, + sort: { refreshModel: true }, + query: { refreshModel: true }, + status: { refreshModel: true }, + }; + + model(params) { + return this.store.query('invoice', { ...params, namespace: 'ledger/int/v1' }); + } +} diff --git a/addon/routes/billing/invoices/index/details.js b/addon/routes/billing/invoices/index/details.js new file mode 100644 index 0000000..d13f719 --- /dev/null +++ b/addon/routes/billing/invoices/index/details.js @@ -0,0 +1,12 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class BillingInvoicesIndexDetailsRoute extends Route { + @service store; + + model({ public_id }) { + return this.store.findRecord('invoice', public_id, { + adapterOptions: { namespace: 'ledger/int/v1' }, + }); + } +} diff --git a/addon/routes/billing/transactions.js b/addon/routes/billing/transactions.js new file mode 100644 index 0000000..f9ba322 --- /dev/null +++ b/addon/routes/billing/transactions.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class BillingTransactionsRoute extends Route {} diff --git a/addon/routes/billing/transactions/index.js b/addon/routes/billing/transactions/index.js new file mode 100644 index 0000000..31ccaf4 --- /dev/null +++ b/addon/routes/billing/transactions/index.js @@ -0,0 +1,18 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class BillingTransactionsIndexRoute extends Route { + @service store; + + queryParams = { + page: { refreshModel: true }, + limit: { refreshModel: true }, + sort: { refreshModel: true }, + query: { refreshModel: true }, + status: { refreshModel: true }, + }; + + model(params) { + return this.store.query('transaction', { ...params, namespace: 'ledger/int/v1' }); + } +} diff --git a/addon/routes/billing/transactions/index/details.js b/addon/routes/billing/transactions/index/details.js new file mode 100644 index 0000000..c77058f --- /dev/null +++ b/addon/routes/billing/transactions/index/details.js @@ -0,0 +1,12 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class BillingTransactionsIndexDetailsRoute extends Route { + @service store; + + model({ public_id }) { + return this.store.findRecord('transaction', public_id, { + adapterOptions: { namespace: 'ledger/int/v1' }, + }); + } +} diff --git a/addon/routes/home.js b/addon/routes/home.js new file mode 100644 index 0000000..8f1cb74 --- /dev/null +++ b/addon/routes/home.js @@ -0,0 +1,15 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class HomeRoute extends Route { + @service fetch; + + async model() { + try { + const response = await this.fetch.get('ledger/int/v1/reports/dashboard'); + return response?.data ?? {}; + } catch { + return {}; + } + } +} diff --git a/addon/routes/reports/index.js b/addon/routes/reports/index.js new file mode 100644 index 0000000..8a359da --- /dev/null +++ b/addon/routes/reports/index.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class ReportsIndexRoute extends Route {} diff --git a/addon/routes/settings/gateways.js b/addon/routes/settings/gateways.js new file mode 100644 index 0000000..193dcef --- /dev/null +++ b/addon/routes/settings/gateways.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class SettingsGatewaysRoute extends Route {} diff --git a/addon/routes/settings/gateways/index.js b/addon/routes/settings/gateways/index.js new file mode 100644 index 0000000..1ca1617 --- /dev/null +++ b/addon/routes/settings/gateways/index.js @@ -0,0 +1,10 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class SettingsGatewaysIndexRoute extends Route { + @service store; + + model() { + return this.store.query('gateway', { namespace: 'ledger/int/v1' }); + } +} diff --git a/addon/routes/settings/gateways/index/details.js b/addon/routes/settings/gateways/index/details.js new file mode 100644 index 0000000..3700583 --- /dev/null +++ b/addon/routes/settings/gateways/index/details.js @@ -0,0 +1,12 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class SettingsGatewaysIndexDetailsRoute extends Route { + @service store; + + model({ public_id }) { + return this.store.findRecord('gateway', public_id, { + adapterOptions: { namespace: 'ledger/int/v1' }, + }); + } +} diff --git a/addon/routes/settings/gateways/index/details/index.js b/addon/routes/settings/gateways/index/details/index.js new file mode 100644 index 0000000..a7c4713 --- /dev/null +++ b/addon/routes/settings/gateways/index/details/index.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class SettingsGatewaysIndexDetailsIndexRoute extends Route {} diff --git a/addon/routes/settings/gateways/index/details/webhooks.js b/addon/routes/settings/gateways/index/details/webhooks.js new file mode 100644 index 0000000..5f240fa --- /dev/null +++ b/addon/routes/settings/gateways/index/details/webhooks.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class SettingsGatewaysIndexDetailsWebhooksRoute extends Route {} diff --git a/addon/routes/wallets.js b/addon/routes/wallets.js new file mode 100644 index 0000000..a772400 --- /dev/null +++ b/addon/routes/wallets.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class WalletsRoute extends Route {} diff --git a/addon/routes/wallets/index.js b/addon/routes/wallets/index.js new file mode 100644 index 0000000..0f8d96a --- /dev/null +++ b/addon/routes/wallets/index.js @@ -0,0 +1,18 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class WalletsIndexRoute extends Route { + @service store; + + queryParams = { + page: { refreshModel: true }, + limit: { refreshModel: true }, + sort: { refreshModel: true }, + query: { refreshModel: true }, + type: { refreshModel: true }, + }; + + model(params) { + return this.store.query('wallet', { ...params, namespace: 'ledger/int/v1' }); + } +} diff --git a/addon/routes/wallets/index/details.js b/addon/routes/wallets/index/details.js new file mode 100644 index 0000000..5e81fa5 --- /dev/null +++ b/addon/routes/wallets/index/details.js @@ -0,0 +1,12 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class WalletsIndexDetailsRoute extends Route { + @service store; + + model({ public_id }) { + return this.store.findRecord('wallet', public_id, { + adapterOptions: { namespace: 'ledger/int/v1' }, + }); + } +} diff --git a/addon/routes/wallets/index/details/index.js b/addon/routes/wallets/index/details/index.js new file mode 100644 index 0000000..12db618 --- /dev/null +++ b/addon/routes/wallets/index/details/index.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class WalletsIndexDetailsIndexRoute extends Route {} diff --git a/addon/routes/wallets/index/details/transactions.js b/addon/routes/wallets/index/details/transactions.js new file mode 100644 index 0000000..f051e40 --- /dev/null +++ b/addon/routes/wallets/index/details/transactions.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class WalletsIndexDetailsTransactionsRoute extends Route {} diff --git a/addon/templates/accounting/accounts.hbs b/addon/templates/accounting/accounts.hbs new file mode 100644 index 0000000..688ec8d --- /dev/null +++ b/addon/templates/accounting/accounts.hbs @@ -0,0 +1,15 @@ + + <:actions> +
+ +
+ +
+{{outlet}} diff --git a/addon/templates/accounting/accounts/index.hbs b/addon/templates/accounting/accounts/index.hbs new file mode 100644 index 0000000..0a17908 --- /dev/null +++ b/addon/templates/accounting/accounts/index.hbs @@ -0,0 +1,15 @@ + + + +{{outlet}} diff --git a/addon/templates/accounting/accounts/index/details.hbs b/addon/templates/accounting/accounts/index/details.hbs new file mode 100644 index 0000000..6641778 --- /dev/null +++ b/addon/templates/accounting/accounts/index/details.hbs @@ -0,0 +1,16 @@ + + <:header> + + + <:default> + + <:default> + {{outlet}} + + + + diff --git a/addon/templates/accounting/accounts/index/details/index.hbs b/addon/templates/accounting/accounts/index/details/index.hbs new file mode 100644 index 0000000..b55794e --- /dev/null +++ b/addon/templates/accounting/accounts/index/details/index.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/accounting/accounts/index/details/ledger.hbs b/addon/templates/accounting/accounts/index/details/ledger.hbs new file mode 100644 index 0000000..946ab50 --- /dev/null +++ b/addon/templates/accounting/accounts/index/details/ledger.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/accounting/journal.hbs b/addon/templates/accounting/journal.hbs new file mode 100644 index 0000000..7b20191 --- /dev/null +++ b/addon/templates/accounting/journal.hbs @@ -0,0 +1,16 @@ + + <:actions> +
+ +
+ +
+{{outlet}} diff --git a/addon/templates/accounting/journal/index.hbs b/addon/templates/accounting/journal/index.hbs new file mode 100644 index 0000000..a701cd3 --- /dev/null +++ b/addon/templates/accounting/journal/index.hbs @@ -0,0 +1,15 @@ + +
+ +{{outlet}} diff --git a/addon/templates/accounting/journal/index/details.hbs b/addon/templates/accounting/journal/index/details.hbs new file mode 100644 index 0000000..29c74bd --- /dev/null +++ b/addon/templates/accounting/journal/index/details.hbs @@ -0,0 +1,16 @@ + + <:header> + + + <:default> + + <:default> + {{outlet}} + + + + diff --git a/addon/templates/accounting/journal/index/details/index.hbs b/addon/templates/accounting/journal/index/details/index.hbs new file mode 100644 index 0000000..b43758f --- /dev/null +++ b/addon/templates/accounting/journal/index/details/index.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/application.hbs b/addon/templates/application.hbs new file mode 100644 index 0000000..f50ef2b --- /dev/null +++ b/addon/templates/application.hbs @@ -0,0 +1,29 @@ + + + Dashboard + + + Invoices + Transactions + + + + Wallets + + + + Journal Entries + Chart of Accounts + + + Reports + + + Payment Gateways + + + + + + {{outlet}} + diff --git a/addon/templates/billing/invoices.hbs b/addon/templates/billing/invoices.hbs new file mode 100644 index 0000000..51c59dd --- /dev/null +++ b/addon/templates/billing/invoices.hbs @@ -0,0 +1,16 @@ + + <:actions> +
+ +
+ +
+{{outlet}} diff --git a/addon/templates/billing/invoices/index.hbs b/addon/templates/billing/invoices/index.hbs new file mode 100644 index 0000000..64ce498 --- /dev/null +++ b/addon/templates/billing/invoices/index.hbs @@ -0,0 +1,15 @@ + +
+ +{{outlet}} diff --git a/addon/templates/billing/invoices/index/details.hbs b/addon/templates/billing/invoices/index/details.hbs new file mode 100644 index 0000000..eeb2e5b --- /dev/null +++ b/addon/templates/billing/invoices/index/details.hbs @@ -0,0 +1,16 @@ + + <:header> + + + <:default> + + <:default> + {{outlet}} + + + + diff --git a/addon/templates/billing/invoices/index/details/index.hbs b/addon/templates/billing/invoices/index/details/index.hbs new file mode 100644 index 0000000..0d27309 --- /dev/null +++ b/addon/templates/billing/invoices/index/details/index.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/billing/invoices/index/details/line-items.hbs b/addon/templates/billing/invoices/index/details/line-items.hbs new file mode 100644 index 0000000..6bedc5c --- /dev/null +++ b/addon/templates/billing/invoices/index/details/line-items.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/billing/invoices/index/details/transactions.hbs b/addon/templates/billing/invoices/index/details/transactions.hbs new file mode 100644 index 0000000..2c916e9 --- /dev/null +++ b/addon/templates/billing/invoices/index/details/transactions.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/billing/transactions.hbs b/addon/templates/billing/transactions.hbs new file mode 100644 index 0000000..5122f48 --- /dev/null +++ b/addon/templates/billing/transactions.hbs @@ -0,0 +1,15 @@ + + <:actions> +
+ +
+ +
+{{outlet}} diff --git a/addon/templates/billing/transactions/index.hbs b/addon/templates/billing/transactions/index.hbs new file mode 100644 index 0000000..e97af01 --- /dev/null +++ b/addon/templates/billing/transactions/index.hbs @@ -0,0 +1,15 @@ + +
+ +{{outlet}} diff --git a/addon/templates/billing/transactions/index/details.hbs b/addon/templates/billing/transactions/index/details.hbs new file mode 100644 index 0000000..9b05ed6 --- /dev/null +++ b/addon/templates/billing/transactions/index/details.hbs @@ -0,0 +1,15 @@ + + <:header> + + + <:default> + + <:default> + {{outlet}} + + + + diff --git a/addon/templates/billing/transactions/index/details/index.hbs b/addon/templates/billing/transactions/index/details/index.hbs new file mode 100644 index 0000000..fb9e92b --- /dev/null +++ b/addon/templates/billing/transactions/index/details/index.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/home.hbs b/addon/templates/home.hbs new file mode 100644 index 0000000..bf01036 --- /dev/null +++ b/addon/templates/home.hbs @@ -0,0 +1,57 @@ + + +
+ {{! KPI Row }} +
+ + + + +
+ + {{! Charts & Summary Row }} +
+
+ +
+
+ + +
+
+ + {{! Recent Activity }} + +
+
diff --git a/addon/templates/reports/index.hbs b/addon/templates/reports/index.hbs new file mode 100644 index 0000000..924f06f --- /dev/null +++ b/addon/templates/reports/index.hbs @@ -0,0 +1,44 @@ + + +
+ {{! Report selector tabs }} +
+ {{#each this.reportTabs as |tab|}} + + {{/each}} +
+ +
+ + {{! Report content }} + {{#if this.isLoading}} + + {{else if this.reportData}} + {{#if (eq this.activeReport "balance-sheet")}} + + {{else if (eq this.activeReport "income-statement")}} + + {{else if (eq this.activeReport "cash-flow")}} + + {{else if (eq this.activeReport "ar-aging")}} + + {{/if}} + {{else}} +
+ +

Select a report and click "Run Report" to generate it.

+
+ {{/if}} +
+
diff --git a/addon/templates/settings/gateways.hbs b/addon/templates/settings/gateways.hbs new file mode 100644 index 0000000..1e87295 --- /dev/null +++ b/addon/templates/settings/gateways.hbs @@ -0,0 +1,15 @@ + + <:actions> +
+ +
+ +
+{{outlet}} diff --git a/addon/templates/settings/gateways/index.hbs b/addon/templates/settings/gateways/index.hbs new file mode 100644 index 0000000..271a689 --- /dev/null +++ b/addon/templates/settings/gateways/index.hbs @@ -0,0 +1,11 @@ + +
+ +{{outlet}} diff --git a/addon/templates/settings/gateways/index/details.hbs b/addon/templates/settings/gateways/index/details.hbs new file mode 100644 index 0000000..23beb24 --- /dev/null +++ b/addon/templates/settings/gateways/index/details.hbs @@ -0,0 +1,16 @@ + + <:header> + + + <:default> + + <:default> + {{outlet}} + + + + diff --git a/addon/templates/settings/gateways/index/details/index.hbs b/addon/templates/settings/gateways/index/details/index.hbs new file mode 100644 index 0000000..2fafa97 --- /dev/null +++ b/addon/templates/settings/gateways/index/details/index.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/settings/gateways/index/details/webhooks.hbs b/addon/templates/settings/gateways/index/details/webhooks.hbs new file mode 100644 index 0000000..5f2919f --- /dev/null +++ b/addon/templates/settings/gateways/index/details/webhooks.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/wallets.hbs b/addon/templates/wallets.hbs new file mode 100644 index 0000000..9622eea --- /dev/null +++ b/addon/templates/wallets.hbs @@ -0,0 +1,15 @@ + + <:actions> +
+ +
+ +
+{{outlet}} diff --git a/addon/templates/wallets/index.hbs b/addon/templates/wallets/index.hbs new file mode 100644 index 0000000..5367695 --- /dev/null +++ b/addon/templates/wallets/index.hbs @@ -0,0 +1,15 @@ + +
+ +{{outlet}} diff --git a/addon/templates/wallets/index/details.hbs b/addon/templates/wallets/index/details.hbs new file mode 100644 index 0000000..93358ab --- /dev/null +++ b/addon/templates/wallets/index/details.hbs @@ -0,0 +1,16 @@ + + <:header> + + + <:default> + + <:default> + {{outlet}} + + + + diff --git a/addon/templates/wallets/index/details/index.hbs b/addon/templates/wallets/index/details/index.hbs new file mode 100644 index 0000000..b2102e6 --- /dev/null +++ b/addon/templates/wallets/index/details/index.hbs @@ -0,0 +1 @@ + diff --git a/addon/templates/wallets/index/details/transactions.hbs b/addon/templates/wallets/index/details/transactions.hbs new file mode 100644 index 0000000..8fdd614 --- /dev/null +++ b/addon/templates/wallets/index/details/transactions.hbs @@ -0,0 +1 @@ + diff --git a/app/components/ledger/account/details.js b/app/components/ledger/account/details.js new file mode 100644 index 0000000..43cf55f --- /dev/null +++ b/app/components/ledger/account/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/account/details'; diff --git a/app/components/ledger/account/general-ledger.js b/app/components/ledger/account/general-ledger.js new file mode 100644 index 0000000..c9d77e4 --- /dev/null +++ b/app/components/ledger/account/general-ledger.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/account/general-ledger'; diff --git a/app/components/ledger/account/panel-header.js b/app/components/ledger/account/panel-header.js new file mode 100644 index 0000000..3ec1612 --- /dev/null +++ b/app/components/ledger/account/panel-header.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/account/panel-header'; diff --git a/app/components/ledger/dashboard/activity-feed.js b/app/components/ledger/dashboard/activity-feed.js new file mode 100644 index 0000000..939b4ae --- /dev/null +++ b/app/components/ledger/dashboard/activity-feed.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/dashboard/activity-feed'; diff --git a/app/components/ledger/dashboard/invoice-summary.js b/app/components/ledger/dashboard/invoice-summary.js new file mode 100644 index 0000000..9c2afc3 --- /dev/null +++ b/app/components/ledger/dashboard/invoice-summary.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/dashboard/invoice-summary'; diff --git a/app/components/ledger/dashboard/kpi-metric.js b/app/components/ledger/dashboard/kpi-metric.js new file mode 100644 index 0000000..205cf87 --- /dev/null +++ b/app/components/ledger/dashboard/kpi-metric.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/dashboard/kpi-metric'; diff --git a/app/components/ledger/dashboard/revenue-chart.js b/app/components/ledger/dashboard/revenue-chart.js new file mode 100644 index 0000000..c293e99 --- /dev/null +++ b/app/components/ledger/dashboard/revenue-chart.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/dashboard/revenue-chart'; diff --git a/app/components/ledger/dashboard/wallet-balances.js b/app/components/ledger/dashboard/wallet-balances.js new file mode 100644 index 0000000..9bba3e9 --- /dev/null +++ b/app/components/ledger/dashboard/wallet-balances.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/dashboard/wallet-balances'; diff --git a/app/components/ledger/gateway/details.js b/app/components/ledger/gateway/details.js new file mode 100644 index 0000000..122462f --- /dev/null +++ b/app/components/ledger/gateway/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/gateway/details'; diff --git a/app/components/ledger/gateway/form.js b/app/components/ledger/gateway/form.js new file mode 100644 index 0000000..df7ddd4 --- /dev/null +++ b/app/components/ledger/gateway/form.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/gateway/form'; diff --git a/app/components/ledger/gateway/panel-header.js b/app/components/ledger/gateway/panel-header.js new file mode 100644 index 0000000..18cdf26 --- /dev/null +++ b/app/components/ledger/gateway/panel-header.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/gateway/panel-header'; diff --git a/app/components/ledger/gateway/webhook-events.js b/app/components/ledger/gateway/webhook-events.js new file mode 100644 index 0000000..f4f082a --- /dev/null +++ b/app/components/ledger/gateway/webhook-events.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/gateway/webhook-events'; diff --git a/app/components/ledger/invoice/details.js b/app/components/ledger/invoice/details.js new file mode 100644 index 0000000..40408f7 --- /dev/null +++ b/app/components/ledger/invoice/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/invoice/details'; diff --git a/app/components/ledger/invoice/line-items.js b/app/components/ledger/invoice/line-items.js new file mode 100644 index 0000000..bf2334b --- /dev/null +++ b/app/components/ledger/invoice/line-items.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/invoice/line-items'; diff --git a/app/components/ledger/invoice/panel-header.js b/app/components/ledger/invoice/panel-header.js new file mode 100644 index 0000000..046f103 --- /dev/null +++ b/app/components/ledger/invoice/panel-header.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/invoice/panel-header'; diff --git a/app/components/ledger/invoice/transactions.js b/app/components/ledger/invoice/transactions.js new file mode 100644 index 0000000..f20a297 --- /dev/null +++ b/app/components/ledger/invoice/transactions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/invoice/transactions'; diff --git a/app/components/ledger/journal/details.js b/app/components/ledger/journal/details.js new file mode 100644 index 0000000..a687391 --- /dev/null +++ b/app/components/ledger/journal/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/journal/details'; diff --git a/app/components/ledger/journal/panel-header.js b/app/components/ledger/journal/panel-header.js new file mode 100644 index 0000000..6c9eadd --- /dev/null +++ b/app/components/ledger/journal/panel-header.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/journal/panel-header'; diff --git a/app/components/ledger/report/ar-aging.js b/app/components/ledger/report/ar-aging.js new file mode 100644 index 0000000..ba40537 --- /dev/null +++ b/app/components/ledger/report/ar-aging.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/report/ar-aging'; diff --git a/app/components/ledger/report/balance-sheet.js b/app/components/ledger/report/balance-sheet.js new file mode 100644 index 0000000..16c91c6 --- /dev/null +++ b/app/components/ledger/report/balance-sheet.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/report/balance-sheet'; diff --git a/app/components/ledger/report/cash-flow.js b/app/components/ledger/report/cash-flow.js new file mode 100644 index 0000000..aff0258 --- /dev/null +++ b/app/components/ledger/report/cash-flow.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/report/cash-flow'; diff --git a/app/components/ledger/report/income-statement.js b/app/components/ledger/report/income-statement.js new file mode 100644 index 0000000..9084aa7 --- /dev/null +++ b/app/components/ledger/report/income-statement.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/report/income-statement'; diff --git a/app/components/ledger/transaction/details.js b/app/components/ledger/transaction/details.js new file mode 100644 index 0000000..436f848 --- /dev/null +++ b/app/components/ledger/transaction/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/transaction/details'; diff --git a/app/components/ledger/transaction/panel-header.js b/app/components/ledger/transaction/panel-header.js new file mode 100644 index 0000000..ef701d8 --- /dev/null +++ b/app/components/ledger/transaction/panel-header.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/transaction/panel-header'; diff --git a/app/components/ledger/wallet/details.js b/app/components/ledger/wallet/details.js new file mode 100644 index 0000000..0c39463 --- /dev/null +++ b/app/components/ledger/wallet/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/wallet/details'; diff --git a/app/components/ledger/wallet/panel-header.js b/app/components/ledger/wallet/panel-header.js new file mode 100644 index 0000000..ff6c699 --- /dev/null +++ b/app/components/ledger/wallet/panel-header.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/wallet/panel-header'; diff --git a/app/components/ledger/wallet/transaction-history.js b/app/components/ledger/wallet/transaction-history.js new file mode 100644 index 0000000..5ba37f5 --- /dev/null +++ b/app/components/ledger/wallet/transaction-history.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/wallet/transaction-history'; diff --git a/app/controllers/ledger/accounting/accounts/index.js b/app/controllers/ledger/accounting/accounts/index.js new file mode 100644 index 0000000..e57c559 --- /dev/null +++ b/app/controllers/ledger/accounting/accounts/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/accounting/accounts/index'; diff --git a/app/controllers/ledger/accounting/accounts/index/details.js b/app/controllers/ledger/accounting/accounts/index/details.js new file mode 100644 index 0000000..becfd41 --- /dev/null +++ b/app/controllers/ledger/accounting/accounts/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/accounting/accounts/index/details'; diff --git a/app/controllers/ledger/accounting/journal/index.js b/app/controllers/ledger/accounting/journal/index.js new file mode 100644 index 0000000..ba5a25b --- /dev/null +++ b/app/controllers/ledger/accounting/journal/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/accounting/journal/index'; diff --git a/app/controllers/ledger/accounting/journal/index/details.js b/app/controllers/ledger/accounting/journal/index/details.js new file mode 100644 index 0000000..69d43c7 --- /dev/null +++ b/app/controllers/ledger/accounting/journal/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/accounting/journal/index/details'; diff --git a/app/controllers/ledger/billing/invoices/index.js b/app/controllers/ledger/billing/invoices/index.js new file mode 100644 index 0000000..bc40c25 --- /dev/null +++ b/app/controllers/ledger/billing/invoices/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/billing/invoices/index'; diff --git a/app/controllers/ledger/billing/invoices/index/details.js b/app/controllers/ledger/billing/invoices/index/details.js new file mode 100644 index 0000000..c958440 --- /dev/null +++ b/app/controllers/ledger/billing/invoices/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/billing/invoices/index/details'; diff --git a/app/controllers/ledger/billing/transactions/index.js b/app/controllers/ledger/billing/transactions/index.js new file mode 100644 index 0000000..df97650 --- /dev/null +++ b/app/controllers/ledger/billing/transactions/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/billing/transactions/index'; diff --git a/app/controllers/ledger/billing/transactions/index/details.js b/app/controllers/ledger/billing/transactions/index/details.js new file mode 100644 index 0000000..ea27fff --- /dev/null +++ b/app/controllers/ledger/billing/transactions/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/billing/transactions/index/details'; diff --git a/app/controllers/ledger/home.js b/app/controllers/ledger/home.js new file mode 100644 index 0000000..3fd3ea0 --- /dev/null +++ b/app/controllers/ledger/home.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/home'; diff --git a/app/controllers/ledger/reports/index.js b/app/controllers/ledger/reports/index.js new file mode 100644 index 0000000..47e96f3 --- /dev/null +++ b/app/controllers/ledger/reports/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/reports/index'; diff --git a/app/controllers/ledger/settings/gateways/index.js b/app/controllers/ledger/settings/gateways/index.js new file mode 100644 index 0000000..680d3e8 --- /dev/null +++ b/app/controllers/ledger/settings/gateways/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/settings/gateways/index'; diff --git a/app/controllers/ledger/settings/gateways/index/details.js b/app/controllers/ledger/settings/gateways/index/details.js new file mode 100644 index 0000000..cffca60 --- /dev/null +++ b/app/controllers/ledger/settings/gateways/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/settings/gateways/index/details'; diff --git a/app/controllers/ledger/wallets/index.js b/app/controllers/ledger/wallets/index.js new file mode 100644 index 0000000..ecf3eb4 --- /dev/null +++ b/app/controllers/ledger/wallets/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/wallets/index'; diff --git a/app/controllers/ledger/wallets/index/details.js b/app/controllers/ledger/wallets/index/details.js new file mode 100644 index 0000000..a7b44f6 --- /dev/null +++ b/app/controllers/ledger/wallets/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/controllers/wallets/index/details'; diff --git a/app/models/account.js b/app/models/account.js new file mode 100644 index 0000000..b9decce --- /dev/null +++ b/app/models/account.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/account'; diff --git a/app/models/gateway.js b/app/models/gateway.js new file mode 100644 index 0000000..a0648b4 --- /dev/null +++ b/app/models/gateway.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/gateway'; diff --git a/app/models/invoice.js b/app/models/invoice.js new file mode 100644 index 0000000..8fc92f3 --- /dev/null +++ b/app/models/invoice.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/invoice'; diff --git a/app/models/journal.js b/app/models/journal.js new file mode 100644 index 0000000..fc13a60 --- /dev/null +++ b/app/models/journal.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/journal'; diff --git a/app/models/transaction.js b/app/models/transaction.js new file mode 100644 index 0000000..dd48f27 --- /dev/null +++ b/app/models/transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/transaction'; diff --git a/app/models/wallet-transaction.js b/app/models/wallet-transaction.js new file mode 100644 index 0000000..4b5328d --- /dev/null +++ b/app/models/wallet-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/wallet-transaction'; diff --git a/app/models/wallet.js b/app/models/wallet.js new file mode 100644 index 0000000..7414123 --- /dev/null +++ b/app/models/wallet.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/wallet'; diff --git a/app/routes/ledger/accounting/accounts.js b/app/routes/ledger/accounting/accounts.js new file mode 100644 index 0000000..fc3fe4c --- /dev/null +++ b/app/routes/ledger/accounting/accounts.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/accounts'; diff --git a/app/routes/ledger/accounting/accounts/index.js b/app/routes/ledger/accounting/accounts/index.js new file mode 100644 index 0000000..35cdede --- /dev/null +++ b/app/routes/ledger/accounting/accounts/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/accounts/index'; diff --git a/app/routes/ledger/accounting/accounts/index/details.js b/app/routes/ledger/accounting/accounts/index/details.js new file mode 100644 index 0000000..342cfff --- /dev/null +++ b/app/routes/ledger/accounting/accounts/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/accounts/index/details'; diff --git a/app/routes/ledger/accounting/accounts/index/details/index.js b/app/routes/ledger/accounting/accounts/index/details/index.js new file mode 100644 index 0000000..b13f2fd --- /dev/null +++ b/app/routes/ledger/accounting/accounts/index/details/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/accounts/index/details/index'; diff --git a/app/routes/ledger/accounting/accounts/index/details/ledger.js b/app/routes/ledger/accounting/accounts/index/details/ledger.js new file mode 100644 index 0000000..6c7e463 --- /dev/null +++ b/app/routes/ledger/accounting/accounts/index/details/ledger.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/accounts/index/details/ledger'; diff --git a/app/routes/ledger/accounting/journal.js b/app/routes/ledger/accounting/journal.js new file mode 100644 index 0000000..78141bf --- /dev/null +++ b/app/routes/ledger/accounting/journal.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/journal'; diff --git a/app/routes/ledger/accounting/journal/index.js b/app/routes/ledger/accounting/journal/index.js new file mode 100644 index 0000000..a8eced2 --- /dev/null +++ b/app/routes/ledger/accounting/journal/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/journal/index'; diff --git a/app/routes/ledger/accounting/journal/index/details.js b/app/routes/ledger/accounting/journal/index/details.js new file mode 100644 index 0000000..9cf7f3b --- /dev/null +++ b/app/routes/ledger/accounting/journal/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/journal/index/details'; diff --git a/app/routes/ledger/accounting/journal/index/details/index.js b/app/routes/ledger/accounting/journal/index/details/index.js new file mode 100644 index 0000000..befb1ec --- /dev/null +++ b/app/routes/ledger/accounting/journal/index/details/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/journal/index/details/index'; diff --git a/app/routes/ledger/billing/invoices.js b/app/routes/ledger/billing/invoices.js new file mode 100644 index 0000000..05dfd17 --- /dev/null +++ b/app/routes/ledger/billing/invoices.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/invoices'; diff --git a/app/routes/ledger/billing/invoices/index.js b/app/routes/ledger/billing/invoices/index.js new file mode 100644 index 0000000..7a6a016 --- /dev/null +++ b/app/routes/ledger/billing/invoices/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/invoices/index'; diff --git a/app/routes/ledger/billing/invoices/index/details.js b/app/routes/ledger/billing/invoices/index/details.js new file mode 100644 index 0000000..642966b --- /dev/null +++ b/app/routes/ledger/billing/invoices/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/invoices/index/details'; diff --git a/app/routes/ledger/billing/invoices/index/details/index.js b/app/routes/ledger/billing/invoices/index/details/index.js new file mode 100644 index 0000000..c9ffa09 --- /dev/null +++ b/app/routes/ledger/billing/invoices/index/details/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/invoices/index/details/index'; diff --git a/app/routes/ledger/billing/invoices/index/details/line-items.js b/app/routes/ledger/billing/invoices/index/details/line-items.js new file mode 100644 index 0000000..93016bf --- /dev/null +++ b/app/routes/ledger/billing/invoices/index/details/line-items.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/invoices/index/details/line-items'; diff --git a/app/routes/ledger/billing/invoices/index/details/transactions.js b/app/routes/ledger/billing/invoices/index/details/transactions.js new file mode 100644 index 0000000..7fbc6ec --- /dev/null +++ b/app/routes/ledger/billing/invoices/index/details/transactions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/invoices/index/details/transactions'; diff --git a/app/routes/ledger/billing/transactions.js b/app/routes/ledger/billing/transactions.js new file mode 100644 index 0000000..49f8d9f --- /dev/null +++ b/app/routes/ledger/billing/transactions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/transactions'; diff --git a/app/routes/ledger/billing/transactions/index.js b/app/routes/ledger/billing/transactions/index.js new file mode 100644 index 0000000..93bc2d6 --- /dev/null +++ b/app/routes/ledger/billing/transactions/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/transactions/index'; diff --git a/app/routes/ledger/billing/transactions/index/details.js b/app/routes/ledger/billing/transactions/index/details.js new file mode 100644 index 0000000..a9f7ca2 --- /dev/null +++ b/app/routes/ledger/billing/transactions/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/transactions/index/details'; diff --git a/app/routes/ledger/billing/transactions/index/details/index.js b/app/routes/ledger/billing/transactions/index/details/index.js new file mode 100644 index 0000000..05f1116 --- /dev/null +++ b/app/routes/ledger/billing/transactions/index/details/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/billing/transactions/index/details/index'; diff --git a/app/routes/ledger/home.js b/app/routes/ledger/home.js new file mode 100644 index 0000000..99aab2b --- /dev/null +++ b/app/routes/ledger/home.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/home'; diff --git a/app/routes/ledger/reports/index.js b/app/routes/ledger/reports/index.js new file mode 100644 index 0000000..999f638 --- /dev/null +++ b/app/routes/ledger/reports/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/reports/index'; diff --git a/app/routes/ledger/settings/gateways.js b/app/routes/ledger/settings/gateways.js new file mode 100644 index 0000000..d9533b0 --- /dev/null +++ b/app/routes/ledger/settings/gateways.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/gateways'; diff --git a/app/routes/ledger/settings/gateways/index.js b/app/routes/ledger/settings/gateways/index.js new file mode 100644 index 0000000..342a46a --- /dev/null +++ b/app/routes/ledger/settings/gateways/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index'; diff --git a/app/routes/ledger/settings/gateways/index/details.js b/app/routes/ledger/settings/gateways/index/details.js new file mode 100644 index 0000000..de1d4e8 --- /dev/null +++ b/app/routes/ledger/settings/gateways/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index/details'; diff --git a/app/routes/ledger/settings/gateways/index/details/index.js b/app/routes/ledger/settings/gateways/index/details/index.js new file mode 100644 index 0000000..9b82de0 --- /dev/null +++ b/app/routes/ledger/settings/gateways/index/details/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index/details/index'; diff --git a/app/routes/ledger/settings/gateways/index/details/webhooks.js b/app/routes/ledger/settings/gateways/index/details/webhooks.js new file mode 100644 index 0000000..46d5de4 --- /dev/null +++ b/app/routes/ledger/settings/gateways/index/details/webhooks.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index/details/webhooks'; diff --git a/app/routes/ledger/wallets.js b/app/routes/ledger/wallets.js new file mode 100644 index 0000000..f7ab727 --- /dev/null +++ b/app/routes/ledger/wallets.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/wallets'; diff --git a/app/routes/ledger/wallets/index.js b/app/routes/ledger/wallets/index.js new file mode 100644 index 0000000..43f2118 --- /dev/null +++ b/app/routes/ledger/wallets/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/wallets/index'; diff --git a/app/routes/ledger/wallets/index/details.js b/app/routes/ledger/wallets/index/details.js new file mode 100644 index 0000000..71dee86 --- /dev/null +++ b/app/routes/ledger/wallets/index/details.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/wallets/index/details'; diff --git a/app/routes/ledger/wallets/index/details/index.js b/app/routes/ledger/wallets/index/details/index.js new file mode 100644 index 0000000..fb2a5ea --- /dev/null +++ b/app/routes/ledger/wallets/index/details/index.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/wallets/index/details/index'; diff --git a/app/routes/ledger/wallets/index/details/transactions.js b/app/routes/ledger/wallets/index/details/transactions.js new file mode 100644 index 0000000..d12a1f3 --- /dev/null +++ b/app/routes/ledger/wallets/index/details/transactions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/wallets/index/details/transactions'; From 9cc366eb23aaf7a9c201a3fd3a5ea915076641b1 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sat, 28 Feb 2026 04:18:33 -0500 Subject: [PATCH 009/209] fix(frontend+backend): correct fetch namespace pattern and replace public_id with id/uuid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend fixes: - addon/routes.js: all details route path params changed from /:public_id to /:id - All 6 detail routes: model({ public_id }) -> model({ id }), findRecord uses id - All 7 Ember Data models: removed @attr('string') public_id (Ember uses id automatically) - All list controllers: transitionTo calls use .id not .public_id - billing/invoices/index/details controller: fetch calls use namespace option - wallets/index and wallets/index/details controllers: fetch calls use namespace option - reports/index controller: endpointMap paths corrected, namespace option added - settings/gateways/index controller: gateways/drivers fetch uses namespace option - routes/home.js: dashboard fetch uses namespace option - components/invoice/transactions.js: guard uses id, fetch uses namespace option - components/wallet/transaction-history.js: guard uses id, fetch uses namespace option - components/account/general-ledger.js: guard uses id, fetch uses namespace option - components/gateway/webhook-events.js: guard uses id, fetch uses namespace option Backend fixes: - server/src/Http/Resources/v1/Gateway.php: now extends FleetbaseResource, id field returns uuid for internal requests and public_id for public API requests, consistent with all other Ledger resources (Account, Invoice, Wallet, etc.) - All other controllers already resolve {id} via orWhere(uuid, id) — no changes needed --- addon/components/account/general-ledger.js | 4 ++-- addon/components/gateway/webhook-events.js | 5 +++-- addon/components/invoice/transactions.js | 5 +++-- addon/components/wallet/transaction-history.js | 5 +++-- addon/controllers/accounting/accounts/index.js | 2 +- addon/controllers/accounting/journal/index.js | 2 +- addon/controllers/billing/invoices/index.js | 2 +- .../billing/invoices/index/details.js | 4 ++-- addon/controllers/billing/transactions/index.js | 2 +- addon/controllers/reports/index.js | 10 +++++----- addon/controllers/settings/gateways/index.js | 4 ++-- addon/controllers/wallets/index.js | 6 +++--- addon/controllers/wallets/index/details.js | 4 ++-- addon/models/account.js | 1 - addon/models/gateway.js | 1 - addon/models/invoice.js | 1 - addon/models/journal.js | 1 - addon/models/transaction.js | 1 - addon/models/wallet-transaction.js | 1 - addon/models/wallet.js | 1 - addon/routes.js | 12 ++++++------ .../routes/accounting/accounts/index/details.js | 4 ++-- .../routes/accounting/journal/index/details.js | 4 ++-- addon/routes/billing/invoices/index/details.js | 4 ++-- .../billing/transactions/index/details.js | 4 ++-- addon/routes/home.js | 2 +- addon/routes/settings/gateways/index/details.js | 4 ++-- addon/routes/wallets/index/details.js | 4 ++-- server/src/Http/Resources/v1/Gateway.php | 17 ++++++++++++----- 29 files changed, 60 insertions(+), 57 deletions(-) diff --git a/addon/components/account/general-ledger.js b/addon/components/account/general-ledger.js index a4090ea..9587501 100644 --- a/addon/components/account/general-ledger.js +++ b/addon/components/account/general-ledger.js @@ -15,9 +15,9 @@ export default class AccountGeneralLedgerComponent extends Component { @task *loadLedger() { const account = this.args.account; - if (!account?.public_id) return; + if (!account?.id) return; try { - const result = yield this.fetch.get(`ledger/int/v1/accounts/${account.public_id}/ledger`); + const result = yield this.fetch.get(`accounts/${account.id}/ledger`, { namespace: 'ledger/int/v1' }); this.entries = result?.data?.entries ?? []; this.summary = result?.data?.summary ?? null; } catch { diff --git a/addon/components/gateway/webhook-events.js b/addon/components/gateway/webhook-events.js index 7151c04..41ef9b9 100644 --- a/addon/components/gateway/webhook-events.js +++ b/addon/components/gateway/webhook-events.js @@ -15,9 +15,10 @@ export default class GatewayWebhookEventsComponent extends Component { @task *loadEvents() { const gateway = this.args.gateway; - if (!gateway?.public_id) return; + if (!gateway?.id) return; try { - const result = yield this.fetch.get(`ledger/int/v1/gateways/${gateway.public_id}/transactions`, { + const result = yield this.fetch.get(`gateways/${gateway.id}/transactions`, { + namespace: 'ledger/int/v1', params: { limit: 20 }, }); this.events = result?.data ?? []; diff --git a/addon/components/invoice/transactions.js b/addon/components/invoice/transactions.js index 729b255..0b86640 100644 --- a/addon/components/invoice/transactions.js +++ b/addon/components/invoice/transactions.js @@ -14,9 +14,10 @@ export default class InvoiceTransactionsComponent extends Component { @task *loadTransactions() { const invoice = this.args.invoice; - if (!invoice?.public_id) return; + if (!invoice?.id) return; try { - const result = yield this.fetch.get(`ledger/int/v1/transactions`, { + const result = yield this.fetch.get('transactions', { + namespace: 'ledger/int/v1', params: { invoice_uuid: invoice.id }, }); this.transactions = result?.data ?? []; diff --git a/addon/components/wallet/transaction-history.js b/addon/components/wallet/transaction-history.js index 7fd12b4..c29d238 100644 --- a/addon/components/wallet/transaction-history.js +++ b/addon/components/wallet/transaction-history.js @@ -16,9 +16,10 @@ export default class WalletTransactionHistoryComponent extends Component { @task *loadTransactions() { const wallet = this.args.wallet; - if (!wallet?.public_id) return; + if (!wallet?.id) return; try { - const result = yield this.fetch.get(`ledger/int/v1/wallets/${wallet.public_id}/transactions`, { + const result = yield this.fetch.get(`wallets/${wallet.id}/transactions`, { + namespace: 'ledger/int/v1', params: { page: this.page, limit: 20 }, }); this.transactions = result?.data ?? []; diff --git a/addon/controllers/accounting/accounts/index.js b/addon/controllers/accounting/accounts/index.js index 8452440..85d2cf6 100644 --- a/addon/controllers/accounting/accounts/index.js +++ b/addon/controllers/accounting/accounts/index.js @@ -41,7 +41,7 @@ export default class AccountingAccountsIndexController extends Controller { } @action viewAccount(account) { - this.hostRouter.transitionTo('console.ledger.accounting.accounts.index.details', account.public_id); + this.hostRouter.transitionTo('console.ledger.accounting.accounts.index.details', account.id); } @action reload() { diff --git a/addon/controllers/accounting/journal/index.js b/addon/controllers/accounting/journal/index.js index 8b878bd..1a14f2f 100644 --- a/addon/controllers/accounting/journal/index.js +++ b/addon/controllers/accounting/journal/index.js @@ -49,7 +49,7 @@ export default class AccountingJournalIndexController extends Controller { } @action viewEntry(entry) { - this.hostRouter.transitionTo('console.ledger.accounting.journal.index.details', entry.public_id); + this.hostRouter.transitionTo('console.ledger.accounting.journal.index.details', entry.id); } @action async deleteEntry(entry) { diff --git a/addon/controllers/billing/invoices/index.js b/addon/controllers/billing/invoices/index.js index d66d8dd..01109bf 100644 --- a/addon/controllers/billing/invoices/index.js +++ b/addon/controllers/billing/invoices/index.js @@ -89,7 +89,7 @@ export default class BillingInvoicesIndexController extends Controller { } @action viewInvoice(invoice) { - this.hostRouter.transitionTo('console.ledger.billing.invoices.index.details', invoice.public_id); + this.hostRouter.transitionTo('console.ledger.billing.invoices.index.details', invoice.id); } @action async deleteInvoice(invoice) { diff --git a/addon/controllers/billing/invoices/index/details.js b/addon/controllers/billing/invoices/index/details.js index 47f22d5..efd8aba 100644 --- a/addon/controllers/billing/invoices/index/details.js +++ b/addon/controllers/billing/invoices/index/details.js @@ -36,7 +36,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller { @action async sendInvoice() { const invoice = this.model; try { - await this.fetch.post(`ledger/int/v1/invoices/${invoice.public_id}/send`); + await this.fetch.post(`invoices/${invoice.id}/send`, {}, { namespace: 'ledger/int/v1' }); this.notifications.success('Invoice sent successfully.'); this.hostRouter.refresh(); } catch (error) { @@ -57,7 +57,7 @@ export default class BillingInvoicesIndexDetailsController extends Controller { confirm: async (modal) => { modal.startLoading(); try { - await this.fetch.post(`ledger/int/v1/invoices/${invoice.public_id}/void`); + await this.fetch.post(`invoices/${invoice.id}/void`, {}, { namespace: 'ledger/int/v1' }); this.notifications.success('Invoice voided.'); this.hostRouter.refresh(); modal.done(); diff --git a/addon/controllers/billing/transactions/index.js b/addon/controllers/billing/transactions/index.js index 0f5a9bc..2e22236 100644 --- a/addon/controllers/billing/transactions/index.js +++ b/addon/controllers/billing/transactions/index.js @@ -34,7 +34,7 @@ export default class BillingTransactionsIndexController extends Controller { } @action viewTransaction(txn) { - this.hostRouter.transitionTo('console.ledger.billing.transactions.index.details', txn.public_id); + this.hostRouter.transitionTo('console.ledger.billing.transactions.index.details', txn.id); } @action reload() { diff --git a/addon/controllers/reports/index.js b/addon/controllers/reports/index.js index 998f605..9b06dff 100644 --- a/addon/controllers/reports/index.js +++ b/addon/controllers/reports/index.js @@ -30,13 +30,13 @@ export default class ReportsIndexController extends Controller { if (this.asOf) params.as_of = this.asOf; const endpointMap = { - 'balance-sheet': 'ledger/int/v1/reports/balance-sheet', - 'income-statement': 'ledger/int/v1/reports/income-statement', - 'cash-flow': 'ledger/int/v1/reports/cash-flow', - 'ar-aging': 'ledger/int/v1/reports/ar-aging', + 'balance-sheet': 'reports/balance-sheet', + 'income-statement': 'reports/income-statement', + 'cash-flow': 'reports/cash-flow', + 'ar-aging': 'reports/ar-aging', }; - const result = yield this.fetch.get(endpointMap[this.activeReport], { params }); + const result = yield this.fetch.get(endpointMap[this.activeReport], { namespace: 'ledger/int/v1', params }); this.reportData = result?.data ?? null; } catch { this.reportData = null; diff --git a/addon/controllers/settings/gateways/index.js b/addon/controllers/settings/gateways/index.js index 118e1d9..d0a6945 100644 --- a/addon/controllers/settings/gateways/index.js +++ b/addon/controllers/settings/gateways/index.js @@ -34,7 +34,7 @@ export default class SettingsGatewaysIndexController extends Controller { @task *loadDrivers() { try { - const result = yield this.fetch.get('ledger/int/v1/gateways/drivers'); + const result = yield this.fetch.get('gateways/drivers', { namespace: 'ledger/int/v1' }); this.availableDrivers = result?.data ?? []; } catch { this.availableDrivers = []; @@ -65,7 +65,7 @@ export default class SettingsGatewaysIndexController extends Controller { } @action viewGateway(gateway) { - this.hostRouter.transitionTo('console.ledger.settings.gateways.index.details', gateway.public_id); + this.hostRouter.transitionTo('console.ledger.settings.gateways.index.details', gateway.id); } @action async deleteGateway(gateway) { diff --git a/addon/controllers/wallets/index.js b/addon/controllers/wallets/index.js index ad706f9..3afb8d4 100644 --- a/addon/controllers/wallets/index.js +++ b/addon/controllers/wallets/index.js @@ -40,12 +40,12 @@ export default class WalletsIndexController extends Controller { } @action viewWallet(wallet) { - this.hostRouter.transitionTo('console.ledger.wallets.index.details', wallet.public_id); + this.hostRouter.transitionTo('console.ledger.wallets.index.details', wallet.id); } @action async freezeWallet(wallet) { try { - await this.fetch.post(`ledger/int/v1/wallets/${wallet.public_id}/freeze`); + await this.fetch.post(`wallets/${wallet.id}/freeze`, {}, { namespace: 'ledger/int/v1' }); this.notifications.success('Wallet frozen.'); this.hostRouter.refresh(); } catch (error) { @@ -55,7 +55,7 @@ export default class WalletsIndexController extends Controller { @action async unfreezeWallet(wallet) { try { - await this.fetch.post(`ledger/int/v1/wallets/${wallet.public_id}/unfreeze`); + await this.fetch.post(`wallets/${wallet.id}/unfreeze`, {}, { namespace: 'ledger/int/v1' }); this.notifications.success('Wallet unfrozen.'); this.hostRouter.refresh(); } catch (error) { diff --git a/addon/controllers/wallets/index/details.js b/addon/controllers/wallets/index/details.js index 0271983..a2fa3d4 100644 --- a/addon/controllers/wallets/index/details.js +++ b/addon/controllers/wallets/index/details.js @@ -39,7 +39,7 @@ export default class WalletsIndexDetailsController extends Controller { @action async freezeWallet() { try { - await this.fetch.post(`ledger/int/v1/wallets/${this.model.public_id}/freeze`); + await this.fetch.post(`wallets/${this.model.id}/freeze`, {}, { namespace: 'ledger/int/v1' }); this.notifications.success('Wallet frozen.'); this.hostRouter.refresh(); } catch (error) { @@ -49,7 +49,7 @@ export default class WalletsIndexDetailsController extends Controller { @action async unfreezeWallet() { try { - await this.fetch.post(`ledger/int/v1/wallets/${this.model.public_id}/unfreeze`); + await this.fetch.post(`wallets/${this.model.id}/unfreeze`, {}, { namespace: 'ledger/int/v1' }); this.notifications.success('Wallet unfrozen.'); this.hostRouter.refresh(); } catch (error) { diff --git a/addon/models/account.js b/addon/models/account.js index 4a60cff..f406ffe 100644 --- a/addon/models/account.js +++ b/addon/models/account.js @@ -2,7 +2,6 @@ import Model, { attr } from '@ember-data/model'; import { computed } from '@ember/object'; export default class AccountModel extends Model { - @attr('string') public_id; @attr('string') name; @attr('string') code; @attr('string') type; diff --git a/addon/models/gateway.js b/addon/models/gateway.js index d308f0e..80fe71c 100644 --- a/addon/models/gateway.js +++ b/addon/models/gateway.js @@ -2,7 +2,6 @@ import Model, { attr } from '@ember-data/model'; import { computed } from '@ember/object'; export default class GatewayModel extends Model { - @attr('string') public_id; @attr('string') name; @attr('string') code; @attr('string') type; diff --git a/addon/models/invoice.js b/addon/models/invoice.js index f06a9ba..b9e927f 100644 --- a/addon/models/invoice.js +++ b/addon/models/invoice.js @@ -2,7 +2,6 @@ import Model, { attr } from '@ember-data/model'; import { computed } from '@ember/object'; export default class InvoiceModel extends Model { - @attr('string') public_id; @attr('string') number; @attr('string') status; @attr('string') currency; diff --git a/addon/models/journal.js b/addon/models/journal.js index 9c035da..079879a 100644 --- a/addon/models/journal.js +++ b/addon/models/journal.js @@ -2,7 +2,6 @@ import Model, { attr } from '@ember-data/model'; import { computed } from '@ember/object'; export default class JournalModel extends Model { - @attr('string') public_id; @attr('string') number; @attr('string') type; @attr('string') currency; diff --git a/addon/models/transaction.js b/addon/models/transaction.js index 38ecef7..1715bb1 100644 --- a/addon/models/transaction.js +++ b/addon/models/transaction.js @@ -2,7 +2,6 @@ import Model, { attr } from '@ember-data/model'; import { computed } from '@ember/object'; export default class TransactionModel extends Model { - @attr('string') public_id; @attr('string') gateway_transaction_id; @attr('string') gateway_code; @attr('string') type; diff --git a/addon/models/wallet-transaction.js b/addon/models/wallet-transaction.js index 1147d09..86729f9 100644 --- a/addon/models/wallet-transaction.js +++ b/addon/models/wallet-transaction.js @@ -2,7 +2,6 @@ import Model, { attr } from '@ember-data/model'; import { computed } from '@ember/object'; export default class WalletTransactionModel extends Model { - @attr('string') public_id; @attr('string') wallet_uuid; @attr('string') type; @attr('string') direction; diff --git a/addon/models/wallet.js b/addon/models/wallet.js index fe232e0..f195e13 100644 --- a/addon/models/wallet.js +++ b/addon/models/wallet.js @@ -2,7 +2,6 @@ import Model, { attr } from '@ember-data/model'; import { computed } from '@ember/object'; export default class WalletModel extends Model { - @attr('string') public_id; @attr('string') name; @attr('string') owner_uuid; @attr('string') owner_type; diff --git a/addon/routes.js b/addon/routes.js index 8690c7b..798e649 100644 --- a/addon/routes.js +++ b/addon/routes.js @@ -9,7 +9,7 @@ export default buildRoutes(function () { this.route('invoices', function () { this.route('index', { path: '/' }, function () { this.route('new'); - this.route('details', { path: '/:public_id' }, function () { + this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); this.route('line-items'); this.route('transactions'); @@ -18,7 +18,7 @@ export default buildRoutes(function () { }); this.route('transactions', function () { this.route('index', { path: '/' }, function () { - this.route('details', { path: '/:public_id' }, function () { + this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); }); }); @@ -28,7 +28,7 @@ export default buildRoutes(function () { // Wallets this.route('wallets', function () { this.route('index', { path: '/' }, function () { - this.route('details', { path: '/:public_id' }, function () { + this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); this.route('transactions'); }); @@ -40,7 +40,7 @@ export default buildRoutes(function () { this.route('journal', function () { this.route('index', { path: '/' }, function () { this.route('new'); - this.route('details', { path: '/:public_id' }, function () { + this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); }); }); @@ -48,7 +48,7 @@ export default buildRoutes(function () { this.route('accounts', function () { this.route('index', { path: '/' }, function () { this.route('new'); - this.route('details', { path: '/:public_id' }, function () { + this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); this.route('ledger'); }); @@ -66,7 +66,7 @@ export default buildRoutes(function () { this.route('gateways', function () { this.route('index', { path: '/' }, function () { this.route('new'); - this.route('details', { path: '/:public_id' }, function () { + this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); this.route('webhooks'); }); diff --git a/addon/routes/accounting/accounts/index/details.js b/addon/routes/accounting/accounts/index/details.js index b7e8853..adf9990 100644 --- a/addon/routes/accounting/accounts/index/details.js +++ b/addon/routes/accounting/accounts/index/details.js @@ -4,8 +4,8 @@ import { inject as service } from '@ember/service'; export default class AccountingAccountsIndexDetailsRoute extends Route { @service store; - model({ public_id }) { - return this.store.findRecord('account', public_id, { + model({ id }) { + return this.store.findRecord('account', id, { adapterOptions: { namespace: 'ledger/int/v1' }, }); } diff --git a/addon/routes/accounting/journal/index/details.js b/addon/routes/accounting/journal/index/details.js index f2ef9f4..1fc3e24 100644 --- a/addon/routes/accounting/journal/index/details.js +++ b/addon/routes/accounting/journal/index/details.js @@ -4,8 +4,8 @@ import { inject as service } from '@ember/service'; export default class AccountingJournalIndexDetailsRoute extends Route { @service store; - model({ public_id }) { - return this.store.findRecord('journal', public_id, { + model({ id }) { + return this.store.findRecord('journal', id, { adapterOptions: { namespace: 'ledger/int/v1' }, }); } diff --git a/addon/routes/billing/invoices/index/details.js b/addon/routes/billing/invoices/index/details.js index d13f719..971a439 100644 --- a/addon/routes/billing/invoices/index/details.js +++ b/addon/routes/billing/invoices/index/details.js @@ -4,8 +4,8 @@ import { inject as service } from '@ember/service'; export default class BillingInvoicesIndexDetailsRoute extends Route { @service store; - model({ public_id }) { - return this.store.findRecord('invoice', public_id, { + model({ id }) { + return this.store.findRecord('invoice', id, { adapterOptions: { namespace: 'ledger/int/v1' }, }); } diff --git a/addon/routes/billing/transactions/index/details.js b/addon/routes/billing/transactions/index/details.js index c77058f..5cd1c8d 100644 --- a/addon/routes/billing/transactions/index/details.js +++ b/addon/routes/billing/transactions/index/details.js @@ -4,8 +4,8 @@ import { inject as service } from '@ember/service'; export default class BillingTransactionsIndexDetailsRoute extends Route { @service store; - model({ public_id }) { - return this.store.findRecord('transaction', public_id, { + model({ id }) { + return this.store.findRecord('transaction', id, { adapterOptions: { namespace: 'ledger/int/v1' }, }); } diff --git a/addon/routes/home.js b/addon/routes/home.js index 8f1cb74..16a3bb7 100644 --- a/addon/routes/home.js +++ b/addon/routes/home.js @@ -6,7 +6,7 @@ export default class HomeRoute extends Route { async model() { try { - const response = await this.fetch.get('ledger/int/v1/reports/dashboard'); + const response = await this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); return response?.data ?? {}; } catch { return {}; diff --git a/addon/routes/settings/gateways/index/details.js b/addon/routes/settings/gateways/index/details.js index 3700583..95c3695 100644 --- a/addon/routes/settings/gateways/index/details.js +++ b/addon/routes/settings/gateways/index/details.js @@ -4,8 +4,8 @@ import { inject as service } from '@ember/service'; export default class SettingsGatewaysIndexDetailsRoute extends Route { @service store; - model({ public_id }) { - return this.store.findRecord('gateway', public_id, { + model({ id }) { + return this.store.findRecord('gateway', id, { adapterOptions: { namespace: 'ledger/int/v1' }, }); } diff --git a/addon/routes/wallets/index/details.js b/addon/routes/wallets/index/details.js index 5e81fa5..24ad14f 100644 --- a/addon/routes/wallets/index/details.js +++ b/addon/routes/wallets/index/details.js @@ -4,8 +4,8 @@ import { inject as service } from '@ember/service'; export default class WalletsIndexDetailsRoute extends Route { @service store; - model({ public_id }) { - return this.store.findRecord('wallet', public_id, { + model({ id }) { + return this.store.findRecord('wallet', id, { adapterOptions: { namespace: 'ledger/int/v1' }, }); } diff --git a/server/src/Http/Resources/v1/Gateway.php b/server/src/Http/Resources/v1/Gateway.php index 3a6e6f2..fc4875f 100644 --- a/server/src/Http/Resources/v1/Gateway.php +++ b/server/src/Http/Resources/v1/Gateway.php @@ -2,17 +2,22 @@ namespace Fleetbase\Ledger\Http\Resources\v1; -use Illuminate\Http\Resources\Json\JsonResource; +use Fleetbase\Http\Resources\FleetbaseResource; +use Fleetbase\Support\Http; /** * Gateway API Resource * * Serializes the Gateway model for API responses. - * The config (credentials) field is intentionally excluded. + * The config (credentials) field is intentionally excluded to prevent + * accidental exposure of API keys and secrets. + * + * Internal requests (console) receive uuid as the id field. + * Public API requests receive public_id as the id field. * * @package Fleetbase\Ledger\Http\Resources\v1 */ -class Gateway extends JsonResource +class Gateway extends FleetbaseResource { /** * Transform the resource into an array. @@ -24,8 +29,10 @@ class Gateway extends JsonResource public function toArray($request): array { return [ - 'id' => $this->public_id, - 'uuid' => $this->uuid, + 'id' => $this->when(Http::isInternalRequest(), $this->uuid, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id), + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), 'name' => $this->name, 'driver' => $this->driver, 'description' => $this->description, From 3b8d3b0997ddcf3ebbe529b89369740cdb461acc Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Sun, 1 Mar 2026 14:29:46 +0800 Subject: [PATCH 010/209] fix engine.js and extension.js --- addon/engine.js | 8 +------- addon/extension.js | 9 ++++++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/addon/engine.js b/addon/engine.js index 1a72dc7..47fd96b 100644 --- a/addon/engine.js +++ b/addon/engine.js @@ -2,11 +2,9 @@ import Engine from '@ember/engine'; import loadInitializers from 'ember-load-initializers'; import Resolver from 'ember-resolver'; import config from './config/environment'; -import services from '@fleetbase/ember-core/exports/services'; +import { services, externalRoutes } from '@fleetbase/ember-core/exports'; const { modulePrefix } = config; -const externalRoutes = ['console', 'extensions']; - export default class LedgerEngine extends Engine { modulePrefix = modulePrefix; Resolver = Resolver; @@ -14,10 +12,6 @@ export default class LedgerEngine extends Engine { services, externalRoutes, }; - setupExtension = function (app, engine, universe) { - // register menu item in header - universe.registerHeaderMenuItem('Ledger', 'console.ledger', { icon: 'calculator', priority: 1 }); - }; } loadInitializers(LedgerEngine, modulePrefix); diff --git a/addon/extension.js b/addon/extension.js index 3a3a373..f2dbe7e 100644 --- a/addon/extension.js +++ b/addon/extension.js @@ -2,8 +2,11 @@ import { Widget, ExtensionComponent, Hook } from '@fleetbase/ember-core/contract export default { setupExtension(app, universe) { - // const menuService = universe.getService('universe/menu-service'); - // const hookService = universe.getService('universe/hook-service'); - // const widgetService = universe.getService('universe/widget-service'); + const menuService = universe.getService('universe/menu-service'); + const hookService = universe.getService('universe/hook-service'); + const widgetService = universe.getService('universe/widget-service'); + + // Register header navigation + menuService.registerHeaderMenuItem('Ledger', 'console.ledger', { icon: 'calculator', priority: 1 }); } }; From d2b06afebdfdf782f053553f67cc7fa913c3102b Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 01:41:00 -0500 Subject: [PATCH 011/209] fix(frontend): correct sidebar to use separate Layout::Sidebar::Panel per group Replace single Panel with Layout::Sidebar::Section wrappers with the correct pattern of one Panel per navigation group, matching the pallet/iam-engine/dev-engine pattern. Each group (Ledger, Billing, Wallets, Accounting, Reports, Settings) is now its own collapsible Panel. Also added missing to application.hbs. --- addon/templates/application.hbs | 35 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/addon/templates/application.hbs b/addon/templates/application.hbs index f50ef2b..c521253 100644 --- a/addon/templates/application.hbs +++ b/addon/templates/application.hbs @@ -1,29 +1,32 @@ - Dashboard + Dashboard + - - Invoices - Transactions - + + Invoices + Transactions + - - Wallets - + + Wallets + - - Journal Entries - Chart of Accounts - + + Journal Entries + Chart of Accounts + - Reports + + Reports + - - Payment Gateways - + + Payment Gateways {{outlet}} + From a675a65b9c93802fee8d4fccbf1f3558df0e981a Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Sun, 1 Mar 2026 15:23:06 +0800 Subject: [PATCH 012/209] fix template --- addon/templates/application.hbs | 6 ------ addon/templates/home.hbs | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/addon/templates/application.hbs b/addon/templates/application.hbs index c521253..e6860bc 100644 --- a/addon/templates/application.hbs +++ b/addon/templates/application.hbs @@ -2,25 +2,20 @@ Dashboard - Invoices Transactions - Wallets - Journal Entries Chart of Accounts - Reports - Payment Gateways @@ -29,4 +24,3 @@ {{outlet}} - diff --git a/addon/templates/home.hbs b/addon/templates/home.hbs index bf01036..9c47311 100644 --- a/addon/templates/home.hbs +++ b/addon/templates/home.hbs @@ -1,4 +1,4 @@ - +{{!--
{{! KPI Row }} @@ -54,4 +54,4 @@ {{! Recent Activity }}
-
+ --}} From 5ab86f248d09c9591b9abc44188c8d23f5dca77f Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 02:34:25 -0500 Subject: [PATCH 013/209] fix(frontend): add adapters, correct dashboard widget system, fix sidebar panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapters: - Add addon/adapters/ledger.js base adapter with namespace 'ledger/int/v1' - Add per-model adapters for account, invoice, transaction, wallet, wallet-transaction, journal, gateway — each re-exporting ledger base adapter - Add app/adapters/ re-exports for all adapters Dashboard widget system (correct implementation): - Rewrite extension.js: use universe/menu-service and universe/widget-service, call widgetService.registerDashboard('ledger') and widgetService.registerWidgets('ledger', widgets) with 7 widget definitions (5 default: overview, revenue-chart, invoice-summary, wallet-balances, activity-feed; 2 optional: ar-aging, top-wallets) - Rewrite home.hbs: use inside with and {{outlet}} - Remove old addon/components/dashboard/ namespace (kpi-metric, revenue-chart, invoice-summary, wallet-balances, activity-feed) — replaced by widget/ - Create addon/components/widget/ with 7 widget components (JS + HBS each): overview, revenue-chart, invoice-summary, wallet-balances, activity-feed, ar-aging, top-wallets — each fetches its own data via fetch service - Add app/components/widget/ re-exports for all 7 widget components - Simplify home route — Dashboard component handles all data fetching via widgets --- addon/adapters/account.js | 1 + addon/adapters/gateway.js | 1 + addon/adapters/invoice.js | 1 + addon/adapters/journal.js | 1 + addon/adapters/ledger.js | 5 + addon/adapters/transaction.js | 1 + addon/adapters/wallet-transaction.js | 1 + addon/adapters/wallet.js | 1 + addon/components/dashboard/activity-feed.hbs | 19 ---- .../components/dashboard/invoice-summary.hbs | 13 --- addon/components/dashboard/kpi-metric.hbs | 17 ---- addon/components/dashboard/kpi-metric.js | 25 ----- addon/components/dashboard/revenue-chart.hbs | 12 --- addon/components/dashboard/revenue-chart.js | 43 --------- .../components/dashboard/wallet-balances.hbs | 13 --- addon/components/widget/activity-feed.hbs | 18 ++++ addon/components/widget/activity-feed.js | 23 +++++ addon/components/widget/ar-aging.hbs | 14 +++ addon/components/widget/ar-aging.js | 23 +++++ addon/components/widget/invoice-summary.hbs | 14 +++ addon/components/widget/invoice-summary.js | 23 +++++ addon/components/widget/overview.hbs | 26 ++++++ addon/components/widget/overview.js | 23 +++++ addon/components/widget/revenue-chart.hbs | 19 ++++ addon/components/widget/revenue-chart.js | 23 +++++ addon/components/widget/top-wallets.hbs | 17 ++++ addon/components/widget/top-wallets.js | 23 +++++ addon/components/widget/wallet-balances.hbs | 14 +++ addon/components/widget/wallet-balances.js | 23 +++++ addon/extension.js | 92 ++++++++++++++++--- addon/routes/home.js | 14 +-- addon/templates/home.hbs | 67 ++------------ app/adapters/account.js | 1 + app/adapters/gateway.js | 1 + app/adapters/invoice.js | 1 + app/adapters/journal.js | 1 + app/adapters/ledger.js | 1 + app/adapters/transaction.js | 1 + app/adapters/wallet-transaction.js | 1 + app/adapters/wallet.js | 1 + app/components/widget/activity-feed.js | 1 + app/components/widget/ar-aging.js | 1 + app/components/widget/invoice-summary.js | 1 + app/components/widget/overview.js | 1 + app/components/widget/revenue-chart.js | 1 + app/components/widget/top-wallets.js | 1 + app/components/widget/wallet-balances.js | 1 + 47 files changed, 402 insertions(+), 223 deletions(-) create mode 100644 addon/adapters/account.js create mode 100644 addon/adapters/gateway.js create mode 100644 addon/adapters/invoice.js create mode 100644 addon/adapters/journal.js create mode 100644 addon/adapters/ledger.js create mode 100644 addon/adapters/transaction.js create mode 100644 addon/adapters/wallet-transaction.js create mode 100644 addon/adapters/wallet.js delete mode 100644 addon/components/dashboard/activity-feed.hbs delete mode 100644 addon/components/dashboard/invoice-summary.hbs delete mode 100644 addon/components/dashboard/kpi-metric.hbs delete mode 100644 addon/components/dashboard/kpi-metric.js delete mode 100644 addon/components/dashboard/revenue-chart.hbs delete mode 100644 addon/components/dashboard/revenue-chart.js delete mode 100644 addon/components/dashboard/wallet-balances.hbs create mode 100644 addon/components/widget/activity-feed.hbs create mode 100644 addon/components/widget/activity-feed.js create mode 100644 addon/components/widget/ar-aging.hbs create mode 100644 addon/components/widget/ar-aging.js create mode 100644 addon/components/widget/invoice-summary.hbs create mode 100644 addon/components/widget/invoice-summary.js create mode 100644 addon/components/widget/overview.hbs create mode 100644 addon/components/widget/overview.js create mode 100644 addon/components/widget/revenue-chart.hbs create mode 100644 addon/components/widget/revenue-chart.js create mode 100644 addon/components/widget/top-wallets.hbs create mode 100644 addon/components/widget/top-wallets.js create mode 100644 addon/components/widget/wallet-balances.hbs create mode 100644 addon/components/widget/wallet-balances.js create mode 100644 app/adapters/account.js create mode 100644 app/adapters/gateway.js create mode 100644 app/adapters/invoice.js create mode 100644 app/adapters/journal.js create mode 100644 app/adapters/ledger.js create mode 100644 app/adapters/transaction.js create mode 100644 app/adapters/wallet-transaction.js create mode 100644 app/adapters/wallet.js create mode 100644 app/components/widget/activity-feed.js create mode 100644 app/components/widget/ar-aging.js create mode 100644 app/components/widget/invoice-summary.js create mode 100644 app/components/widget/overview.js create mode 100644 app/components/widget/revenue-chart.js create mode 100644 app/components/widget/top-wallets.js create mode 100644 app/components/widget/wallet-balances.js diff --git a/addon/adapters/account.js b/addon/adapters/account.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/adapters/account.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/adapters/gateway.js b/addon/adapters/gateway.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/adapters/gateway.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/adapters/invoice.js b/addon/adapters/invoice.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/adapters/invoice.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/adapters/journal.js b/addon/adapters/journal.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/adapters/journal.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/adapters/ledger.js b/addon/adapters/ledger.js new file mode 100644 index 0000000..3d28e83 --- /dev/null +++ b/addon/adapters/ledger.js @@ -0,0 +1,5 @@ +import ApplicationAdapter from '@fleetbase/ember-core/adapters/application'; + +export default class LedgerAdapter extends ApplicationAdapter { + namespace = 'ledger/int/v1'; +} diff --git a/addon/adapters/transaction.js b/addon/adapters/transaction.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/adapters/transaction.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/adapters/wallet-transaction.js b/addon/adapters/wallet-transaction.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/adapters/wallet-transaction.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/adapters/wallet.js b/addon/adapters/wallet.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/adapters/wallet.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/components/dashboard/activity-feed.hbs b/addon/components/dashboard/activity-feed.hbs deleted file mode 100644 index bb90e11..0000000 --- a/addon/components/dashboard/activity-feed.hbs +++ /dev/null @@ -1,19 +0,0 @@ -
-

Recent Journal Entries

-
- {{#each @entries as |entry|}} -
-
- {{entry.description}} - DR: {{entry.debit_account_name}} / CR: {{entry.credit_account_name}} -
-
- {{entry.formatted_amount}} - {{format-date entry.date format="MMM d"}} -
-
- {{else}} -

No recent journal entries

- {{/each}} -
-
diff --git a/addon/components/dashboard/invoice-summary.hbs b/addon/components/dashboard/invoice-summary.hbs deleted file mode 100644 index 1d7cbd5..0000000 --- a/addon/components/dashboard/invoice-summary.hbs +++ /dev/null @@ -1,13 +0,0 @@ -
-

Invoices

-
- {{#each-in @data as |status count|}} -
- {{status}} - {{count}} -
- {{else}} -

No invoice data

- {{/each-in}} -
-
diff --git a/addon/components/dashboard/kpi-metric.hbs b/addon/components/dashboard/kpi-metric.hbs deleted file mode 100644 index 265c68f..0000000 --- a/addon/components/dashboard/kpi-metric.hbs +++ /dev/null @@ -1,17 +0,0 @@ -
-
- {{@title}} - {{#if @icon}} - - {{/if}} -
-
- {{this.formattedValue}} -
- {{#if this.changeLabel}} -
- {{this.changeLabel}} - vs last period -
- {{/if}} -
diff --git a/addon/components/dashboard/kpi-metric.js b/addon/components/dashboard/kpi-metric.js deleted file mode 100644 index 2a061af..0000000 --- a/addon/components/dashboard/kpi-metric.js +++ /dev/null @@ -1,25 +0,0 @@ -import Component from '@glimmer/component'; -import { computed } from '@ember/object'; - -export default class DashboardKpiMetricComponent extends Component { - get formattedValue() { - const { value, currency } = this.args; - if (value === undefined || value === null) return '—'; - const amount = value / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency || 'USD' }).format(amount); - } - - get changeLabel() { - const change = this.args.change; - if (change === undefined || change === null) return null; - const sign = change >= 0 ? '+' : ''; - return `${sign}${change.toFixed(1)}%`; - } - - get changeColor() { - const change = this.args.change; - if (change === undefined || change === null) return 'gray'; - const positive = change >= 0; - return this.args.inverse ? (positive ? 'red' : 'green') : (positive ? 'green' : 'red'); - } -} diff --git a/addon/components/dashboard/revenue-chart.hbs b/addon/components/dashboard/revenue-chart.hbs deleted file mode 100644 index 08a1013..0000000 --- a/addon/components/dashboard/revenue-chart.hbs +++ /dev/null @@ -1,12 +0,0 @@ -
-

Revenue Trend

-
- {{#if @data}} - - {{else}} -
- No revenue data available -
- {{/if}} -
-
diff --git a/addon/components/dashboard/revenue-chart.js b/addon/components/dashboard/revenue-chart.js deleted file mode 100644 index e113aaf..0000000 --- a/addon/components/dashboard/revenue-chart.js +++ /dev/null @@ -1,43 +0,0 @@ -import Component from '@glimmer/component'; -import { tracked } from '@glimmer/tracking'; -import { action } from '@ember/object'; - -export default class DashboardRevenueChartComponent extends Component { - @tracked chartData = null; - - @action - setupChart(element) { - const data = this.args.data || []; - const labels = data.map((d) => d.date); - const values = data.map((d) => (d.amount || 0) / 100); - - this.chartData = { labels, values }; - - if (typeof window !== 'undefined' && window.Chart) { - new window.Chart(element, { - type: 'line', - data: { - labels, - datasets: [ - { - label: 'Revenue', - data: values, - borderColor: 'rgb(59, 130, 246)', - backgroundColor: 'rgba(59, 130, 246, 0.1)', - tension: 0.4, - fill: true, - }, - ], - }, - options: { - responsive: true, - maintainAspectRatio: false, - plugins: { legend: { display: false } }, - scales: { - y: { beginAtZero: true, ticks: { callback: (v) => '$' + v.toLocaleString() } }, - }, - }, - }); - } - } -} diff --git a/addon/components/dashboard/wallet-balances.hbs b/addon/components/dashboard/wallet-balances.hbs deleted file mode 100644 index ede6cb1..0000000 --- a/addon/components/dashboard/wallet-balances.hbs +++ /dev/null @@ -1,13 +0,0 @@ -
-

Wallet Balances

-
- {{#each @data as |item|}} -
- {{item.currency}} - {{item.formatted_total}} -
- {{else}} -

No wallet data

- {{/each}} -
-
diff --git a/addon/components/widget/activity-feed.hbs b/addon/components/widget/activity-feed.hbs new file mode 100644 index 0000000..25a7a59 --- /dev/null +++ b/addon/components/widget/activity-feed.hbs @@ -0,0 +1,18 @@ +
+ {{#if this.loadData.isRunning}} +
+ {{else if this.entries.length}} + {{#each this.entries as |entry|}} +
+ +
+

{{entry.description}}

+

{{entry.created_at}}

+
+ {{entry.amount}} +
+ {{/each}} + {{else}} +
No recent journal entries.
+ {{/if}} +
diff --git a/addon/components/widget/activity-feed.js b/addon/components/widget/activity-feed.js new file mode 100644 index 0000000..05f21be --- /dev/null +++ b/addon/components/widget/activity-feed.js @@ -0,0 +1,23 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WidgetActivityFeedComponent extends Component { + @service fetch; + @tracked entries = []; + + constructor() { + super(...arguments); + this.loadData.perform(); + } + + @task *loadData() { + try { + const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + this.entries = response?.data?.recent_journals ?? []; + } catch { + this.entries = []; + } + } +} diff --git a/addon/components/widget/ar-aging.hbs b/addon/components/widget/ar-aging.hbs new file mode 100644 index 0000000..90db3e4 --- /dev/null +++ b/addon/components/widget/ar-aging.hbs @@ -0,0 +1,14 @@ +
+ {{#if this.loadData.isRunning}} +
+ {{else if this.buckets}} + {{#each-in this.buckets as |bucket total|}} +
+ {{bucket}} + {{total}} +
+ {{/each-in}} + {{else}} +
No AR aging data.
+ {{/if}} +
diff --git a/addon/components/widget/ar-aging.js b/addon/components/widget/ar-aging.js new file mode 100644 index 0000000..45ee1d2 --- /dev/null +++ b/addon/components/widget/ar-aging.js @@ -0,0 +1,23 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WidgetArAgingComponent extends Component { + @service fetch; + @tracked buckets = null; + + constructor() { + super(...arguments); + this.loadData.perform(); + } + + @task *loadData() { + try { + const response = yield this.fetch.get('reports/ar-aging', { namespace: 'ledger/int/v1' }); + this.buckets = response?.data?.summary ?? null; + } catch { + this.buckets = null; + } + } +} diff --git a/addon/components/widget/invoice-summary.hbs b/addon/components/widget/invoice-summary.hbs new file mode 100644 index 0000000..24c9860 --- /dev/null +++ b/addon/components/widget/invoice-summary.hbs @@ -0,0 +1,14 @@ +
+ {{#if this.loadData.isRunning}} +
+ {{else if this.counts}} + {{#each-in this.counts as |status count|}} +
+ {{status}} + {{count}} +
+ {{/each-in}} + {{else}} +
No invoice data.
+ {{/if}} +
diff --git a/addon/components/widget/invoice-summary.js b/addon/components/widget/invoice-summary.js new file mode 100644 index 0000000..5e3a61e --- /dev/null +++ b/addon/components/widget/invoice-summary.js @@ -0,0 +1,23 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WidgetInvoiceSummaryComponent extends Component { + @service fetch; + @tracked counts = null; + + constructor() { + super(...arguments); + this.loadData.perform(); + } + + @task *loadData() { + try { + const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + this.counts = response?.data?.invoice_counts ?? null; + } catch { + this.counts = null; + } + } +} diff --git a/addon/components/widget/overview.hbs b/addon/components/widget/overview.hbs new file mode 100644 index 0000000..2467c5d --- /dev/null +++ b/addon/components/widget/overview.hbs @@ -0,0 +1,26 @@ +
+ {{#if this.loadData.isRunning}} +
+ +
+ {{else if this.data}} +
+ Revenue + {{this.data.revenue.current}} +
+
+ Expenses + {{this.data.expenses.current}} +
+
+ Net Income + {{this.data.net_income.current}} +
+
+ Outstanding AR + {{this.data.outstanding_ar}} +
+ {{else}} +
No data available.
+ {{/if}} +
diff --git a/addon/components/widget/overview.js b/addon/components/widget/overview.js new file mode 100644 index 0000000..e08c9ad --- /dev/null +++ b/addon/components/widget/overview.js @@ -0,0 +1,23 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WidgetOverviewComponent extends Component { + @service fetch; + @tracked data = null; + + constructor() { + super(...arguments); + this.loadData.perform(); + } + + @task *loadData() { + try { + const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + this.data = response?.data ?? null; + } catch { + this.data = null; + } + } +} diff --git a/addon/components/widget/revenue-chart.hbs b/addon/components/widget/revenue-chart.hbs new file mode 100644 index 0000000..fb73e14 --- /dev/null +++ b/addon/components/widget/revenue-chart.hbs @@ -0,0 +1,19 @@ +
+ {{#if this.loadData.isRunning}} +
+ {{else if this.data.length}} +
+ {{#each this.data as |day|}} +
+ {{day.date}} +
+
+
+ {{day.amount}} +
+ {{/each}} +
+ {{else}} +
No revenue data for this period.
+ {{/if}} +
diff --git a/addon/components/widget/revenue-chart.js b/addon/components/widget/revenue-chart.js new file mode 100644 index 0000000..2c96f9e --- /dev/null +++ b/addon/components/widget/revenue-chart.js @@ -0,0 +1,23 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WidgetRevenueChartComponent extends Component { + @service fetch; + @tracked data = []; + + constructor() { + super(...arguments); + this.loadData.perform(); + } + + @task *loadData() { + try { + const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + this.data = response?.data?.daily_revenue ?? []; + } catch { + this.data = []; + } + } +} diff --git a/addon/components/widget/top-wallets.hbs b/addon/components/widget/top-wallets.hbs new file mode 100644 index 0000000..a0f80d8 --- /dev/null +++ b/addon/components/widget/top-wallets.hbs @@ -0,0 +1,17 @@ +
+ {{#if this.loadData.isRunning}} +
+ {{else if this.wallets.length}} + {{#each this.wallets as |wallet index|}} +
+ {{add index 1}} +
+

{{wallet.owner_name}}

+
+ {{wallet.formatted_balance}} +
+ {{/each}} + {{else}} +
No wallet data.
+ {{/if}} +
diff --git a/addon/components/widget/top-wallets.js b/addon/components/widget/top-wallets.js new file mode 100644 index 0000000..63c9598 --- /dev/null +++ b/addon/components/widget/top-wallets.js @@ -0,0 +1,23 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WidgetTopWalletsComponent extends Component { + @service fetch; + @tracked wallets = []; + + constructor() { + super(...arguments); + this.loadData.perform(); + } + + @task *loadData() { + try { + const response = yield this.fetch.get('reports/wallet-summary', { namespace: 'ledger/int/v1' }); + this.wallets = response?.data?.top_driver_wallets ?? []; + } catch { + this.wallets = []; + } + } +} diff --git a/addon/components/widget/wallet-balances.hbs b/addon/components/widget/wallet-balances.hbs new file mode 100644 index 0000000..91fc9b3 --- /dev/null +++ b/addon/components/widget/wallet-balances.hbs @@ -0,0 +1,14 @@ +
+ {{#if this.loadData.isRunning}} +
+ {{else if this.totals}} + {{#each-in this.totals as |currency total|}} +
+ {{currency}} + {{total}} +
+ {{/each-in}} + {{else}} +
No wallet data.
+ {{/if}} +
diff --git a/addon/components/widget/wallet-balances.js b/addon/components/widget/wallet-balances.js new file mode 100644 index 0000000..f334d1e --- /dev/null +++ b/addon/components/widget/wallet-balances.js @@ -0,0 +1,23 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; + +export default class WidgetWalletBalancesComponent extends Component { + @service fetch; + @tracked totals = null; + + constructor() { + super(...arguments); + this.loadData.perform(); + } + + @task *loadData() { + try { + const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + this.totals = response?.data?.wallet_totals ?? null; + } catch { + this.totals = null; + } + } +} diff --git a/addon/extension.js b/addon/extension.js index fd5ca41..719684f 100644 --- a/addon/extension.js +++ b/addon/extension.js @@ -2,25 +2,95 @@ import { Widget, ExtensionComponent } from '@fleetbase/ember-core/contracts'; export default { setupExtension(app, universe) { - const menuService = universe.getService('menu'); - const widgetService = universe.getService('widget'); + const menuService = universe.getService('universe/menu-service'); + const widgetService = universe.getService('universe/widget-service'); // Register Ledger in the console header navigation menuService.registerHeaderMenuItem('Ledger', 'console.ledger', { icon: 'calculator', priority: 4 }); - // Register dashboard widget + // Register dashboard and widgets + this.registerWidgets(widgetService); + }, + + registerWidgets(widgetService) { const widgets = [ new Widget({ - id: 'ledger-financial-summary-widget', - name: 'Financial Summary', - description: 'Key financial metrics including revenue, expenses, and outstanding invoices.', - icon: 'calculator', - component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/financial-summary'), - grid_options: { w: 6, h: 8, minW: 6, minH: 8 }, - options: { title: 'Financial Summary' }, + id: 'ledger-overview', + name: 'Financial Overview', + description: 'Key financial KPIs: revenue, expenses, net income, and outstanding AR for the current period.', + icon: 'gauge-high', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/overview'), + grid_options: { w: 12, h: 4, minW: 8, minH: 3 }, + options: { title: 'Financial Overview' }, + default: true, + }), + + new Widget({ + id: 'ledger-revenue-chart', + name: 'Revenue Chart', + description: 'Daily revenue trend chart for the current period.', + icon: 'chart-line', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/revenue-chart'), + grid_options: { w: 8, h: 6, minW: 6, minH: 5 }, + options: { title: 'Revenue Chart' }, + default: true, + }), + + new Widget({ + id: 'ledger-invoice-summary', + name: 'Invoice Summary', + description: 'Breakdown of invoices by status: draft, sent, paid, overdue, and cancelled.', + icon: 'file-invoice-dollar', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/invoice-summary'), + grid_options: { w: 4, h: 6, minW: 3, minH: 5 }, + options: { title: 'Invoice Summary' }, + default: true, + }), + + new Widget({ + id: 'ledger-wallet-balances', + name: 'Wallet Balances', + description: 'Total wallet balances grouped by currency across all driver and customer wallets.', + icon: 'wallet', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/wallet-balances'), + grid_options: { w: 4, h: 5, minW: 3, minH: 4 }, + options: { title: 'Wallet Balances' }, + default: true, + }), + + new Widget({ + id: 'ledger-activity-feed', + name: 'Recent Journal Entries', + description: 'Live feed of the most recent double-entry journal entries in the ledger.', + icon: 'book', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/activity-feed'), + grid_options: { w: 8, h: 6, minW: 6, minH: 5 }, + options: { title: 'Recent Journal Entries' }, + default: true, + }), + + new Widget({ + id: 'ledger-ar-aging', + name: 'AR Aging Summary', + description: 'Accounts receivable aging buckets: current, 1–30, 31–60, 61–90, and 90+ days overdue.', + icon: 'clock', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/ar-aging'), + grid_options: { w: 6, h: 5, minW: 5, minH: 4 }, + options: { title: 'AR Aging Summary' }, + }), + + new Widget({ + id: 'ledger-top-wallets', + name: 'Top Driver Wallets', + description: 'Leaderboard of the top 10 driver wallets by current balance.', + icon: 'ranking-star', + component: new ExtensionComponent('@fleetbase/ledger-engine', 'widget/top-wallets'), + grid_options: { w: 6, h: 6, minW: 4, minH: 5 }, + options: { title: 'Top Driver Wallets' }, }), ]; - widgetService.registerWidgets('dashboard', widgets); + widgetService.registerDashboard('ledger'); + widgetService.registerWidgets('ledger', widgets); }, }; diff --git a/addon/routes/home.js b/addon/routes/home.js index 16a3bb7..f9ee296 100644 --- a/addon/routes/home.js +++ b/addon/routes/home.js @@ -1,15 +1,3 @@ import Route from '@ember/routing/route'; -import { inject as service } from '@ember/service'; -export default class HomeRoute extends Route { - @service fetch; - - async model() { - try { - const response = await this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); - return response?.data ?? {}; - } catch { - return {}; - } - } -} +export default class HomeRoute extends Route {} diff --git a/addon/templates/home.hbs b/addon/templates/home.hbs index 9c47311..4e49f67 100644 --- a/addon/templates/home.hbs +++ b/addon/templates/home.hbs @@ -1,57 +1,10 @@ -{{!-- - -
- {{! KPI Row }} -
- - - - -
- - {{! Charts & Summary Row }} -
-
- -
-
- - -
-
- - {{! Recent Activity }} - -
-
--}} + + + + {{outlet}} + diff --git a/app/adapters/account.js b/app/adapters/account.js new file mode 100644 index 0000000..089fb2c --- /dev/null +++ b/app/adapters/account.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/account'; diff --git a/app/adapters/gateway.js b/app/adapters/gateway.js new file mode 100644 index 0000000..dc351d0 --- /dev/null +++ b/app/adapters/gateway.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/gateway'; diff --git a/app/adapters/invoice.js b/app/adapters/invoice.js new file mode 100644 index 0000000..0a9d19b --- /dev/null +++ b/app/adapters/invoice.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/invoice'; diff --git a/app/adapters/journal.js b/app/adapters/journal.js new file mode 100644 index 0000000..c169a25 --- /dev/null +++ b/app/adapters/journal.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/journal'; diff --git a/app/adapters/ledger.js b/app/adapters/ledger.js new file mode 100644 index 0000000..3a6267f --- /dev/null +++ b/app/adapters/ledger.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger'; diff --git a/app/adapters/transaction.js b/app/adapters/transaction.js new file mode 100644 index 0000000..43249bb --- /dev/null +++ b/app/adapters/transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/transaction'; diff --git a/app/adapters/wallet-transaction.js b/app/adapters/wallet-transaction.js new file mode 100644 index 0000000..9d59331 --- /dev/null +++ b/app/adapters/wallet-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/wallet-transaction'; diff --git a/app/adapters/wallet.js b/app/adapters/wallet.js new file mode 100644 index 0000000..e377864 --- /dev/null +++ b/app/adapters/wallet.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/wallet'; diff --git a/app/components/widget/activity-feed.js b/app/components/widget/activity-feed.js new file mode 100644 index 0000000..fef087f --- /dev/null +++ b/app/components/widget/activity-feed.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/widget/activity-feed'; diff --git a/app/components/widget/ar-aging.js b/app/components/widget/ar-aging.js new file mode 100644 index 0000000..355f185 --- /dev/null +++ b/app/components/widget/ar-aging.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/widget/ar-aging'; diff --git a/app/components/widget/invoice-summary.js b/app/components/widget/invoice-summary.js new file mode 100644 index 0000000..dc3d96d --- /dev/null +++ b/app/components/widget/invoice-summary.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/widget/invoice-summary'; diff --git a/app/components/widget/overview.js b/app/components/widget/overview.js new file mode 100644 index 0000000..6e5feec --- /dev/null +++ b/app/components/widget/overview.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/widget/overview'; diff --git a/app/components/widget/revenue-chart.js b/app/components/widget/revenue-chart.js new file mode 100644 index 0000000..e00f0f8 --- /dev/null +++ b/app/components/widget/revenue-chart.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/widget/revenue-chart'; diff --git a/app/components/widget/top-wallets.js b/app/components/widget/top-wallets.js new file mode 100644 index 0000000..61f7a39 --- /dev/null +++ b/app/components/widget/top-wallets.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/widget/top-wallets'; diff --git a/app/components/widget/wallet-balances.js b/app/components/widget/wallet-balances.js new file mode 100644 index 0000000..627ebc3 --- /dev/null +++ b/app/components/widget/wallet-balances.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/components/widget/wallet-balances'; From a781afe0d573ca6453f7ac9feab71f227ab2d34b Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 02:40:25 -0500 Subject: [PATCH 014/209] fix(frontend): correct fetch service call signature to use 3 args (uri, params, options) All fetch.get calls were incorrectly passing namespace in the params argument: fetch.get('url', { namespace: 'ledger/int/v1' }) Fixed to use the correct 3-argument signature: fetch.get('url', {}, { namespace: 'ledger/int/v1' }) Files fixed: - addon/components/widget/overview.js - addon/components/widget/revenue-chart.js - addon/components/widget/invoice-summary.js - addon/components/widget/wallet-balances.js - addon/components/widget/activity-feed.js - addon/components/widget/ar-aging.js - addon/components/widget/top-wallets.js - addon/controllers/reports/index.js (params now passed as 2nd arg) - addon/controllers/settings/gateways/index.js --- addon/components/widget/activity-feed.js | 2 +- addon/components/widget/ar-aging.js | 2 +- addon/components/widget/invoice-summary.js | 2 +- addon/components/widget/overview.js | 2 +- addon/components/widget/revenue-chart.js | 2 +- addon/components/widget/top-wallets.js | 2 +- addon/components/widget/wallet-balances.js | 2 +- addon/controllers/reports/index.js | 2 +- addon/controllers/settings/gateways/index.js | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/addon/components/widget/activity-feed.js b/addon/components/widget/activity-feed.js index 05f21be..8a9f26d 100644 --- a/addon/components/widget/activity-feed.js +++ b/addon/components/widget/activity-feed.js @@ -14,7 +14,7 @@ export default class WidgetActivityFeedComponent extends Component { @task *loadData() { try { - const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + const response = yield this.fetch.get('reports/dashboard', {}, { namespace: 'ledger/int/v1' }); this.entries = response?.data?.recent_journals ?? []; } catch { this.entries = []; diff --git a/addon/components/widget/ar-aging.js b/addon/components/widget/ar-aging.js index 45ee1d2..57ffd8d 100644 --- a/addon/components/widget/ar-aging.js +++ b/addon/components/widget/ar-aging.js @@ -14,7 +14,7 @@ export default class WidgetArAgingComponent extends Component { @task *loadData() { try { - const response = yield this.fetch.get('reports/ar-aging', { namespace: 'ledger/int/v1' }); + const response = yield this.fetch.get('reports/ar-aging', {}, { namespace: 'ledger/int/v1' }); this.buckets = response?.data?.summary ?? null; } catch { this.buckets = null; diff --git a/addon/components/widget/invoice-summary.js b/addon/components/widget/invoice-summary.js index 5e3a61e..8c03918 100644 --- a/addon/components/widget/invoice-summary.js +++ b/addon/components/widget/invoice-summary.js @@ -14,7 +14,7 @@ export default class WidgetInvoiceSummaryComponent extends Component { @task *loadData() { try { - const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + const response = yield this.fetch.get('reports/dashboard', {}, { namespace: 'ledger/int/v1' }); this.counts = response?.data?.invoice_counts ?? null; } catch { this.counts = null; diff --git a/addon/components/widget/overview.js b/addon/components/widget/overview.js index e08c9ad..def3fa3 100644 --- a/addon/components/widget/overview.js +++ b/addon/components/widget/overview.js @@ -14,7 +14,7 @@ export default class WidgetOverviewComponent extends Component { @task *loadData() { try { - const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + const response = yield this.fetch.get('reports/dashboard', {}, { namespace: 'ledger/int/v1' }); this.data = response?.data ?? null; } catch { this.data = null; diff --git a/addon/components/widget/revenue-chart.js b/addon/components/widget/revenue-chart.js index 2c96f9e..302a1ad 100644 --- a/addon/components/widget/revenue-chart.js +++ b/addon/components/widget/revenue-chart.js @@ -14,7 +14,7 @@ export default class WidgetRevenueChartComponent extends Component { @task *loadData() { try { - const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + const response = yield this.fetch.get('reports/dashboard', {}, { namespace: 'ledger/int/v1' }); this.data = response?.data?.daily_revenue ?? []; } catch { this.data = []; diff --git a/addon/components/widget/top-wallets.js b/addon/components/widget/top-wallets.js index 63c9598..19ea7d5 100644 --- a/addon/components/widget/top-wallets.js +++ b/addon/components/widget/top-wallets.js @@ -14,7 +14,7 @@ export default class WidgetTopWalletsComponent extends Component { @task *loadData() { try { - const response = yield this.fetch.get('reports/wallet-summary', { namespace: 'ledger/int/v1' }); + const response = yield this.fetch.get('reports/wallet-summary', {}, { namespace: 'ledger/int/v1' }); this.wallets = response?.data?.top_driver_wallets ?? []; } catch { this.wallets = []; diff --git a/addon/components/widget/wallet-balances.js b/addon/components/widget/wallet-balances.js index f334d1e..2da69ab 100644 --- a/addon/components/widget/wallet-balances.js +++ b/addon/components/widget/wallet-balances.js @@ -14,7 +14,7 @@ export default class WidgetWalletBalancesComponent extends Component { @task *loadData() { try { - const response = yield this.fetch.get('reports/dashboard', { namespace: 'ledger/int/v1' }); + const response = yield this.fetch.get('reports/dashboard', {}, { namespace: 'ledger/int/v1' }); this.totals = response?.data?.wallet_totals ?? null; } catch { this.totals = null; diff --git a/addon/controllers/reports/index.js b/addon/controllers/reports/index.js index 9b06dff..719ace7 100644 --- a/addon/controllers/reports/index.js +++ b/addon/controllers/reports/index.js @@ -36,7 +36,7 @@ export default class ReportsIndexController extends Controller { 'ar-aging': 'reports/ar-aging', }; - const result = yield this.fetch.get(endpointMap[this.activeReport], { namespace: 'ledger/int/v1', params }); + const result = yield this.fetch.get(endpointMap[this.activeReport], params, { namespace: 'ledger/int/v1' }); this.reportData = result?.data ?? null; } catch { this.reportData = null; diff --git a/addon/controllers/settings/gateways/index.js b/addon/controllers/settings/gateways/index.js index d0a6945..8d0e62e 100644 --- a/addon/controllers/settings/gateways/index.js +++ b/addon/controllers/settings/gateways/index.js @@ -34,7 +34,7 @@ export default class SettingsGatewaysIndexController extends Controller { @task *loadDrivers() { try { - const result = yield this.fetch.get('gateways/drivers', { namespace: 'ledger/int/v1' }); + const result = yield this.fetch.get('gateways/drivers', {}, { namespace: 'ledger/int/v1' }); this.availableDrivers = result?.data ?? []; } catch { this.availableDrivers = []; From d0f919f334a18c36975cde6d8442e03280e41269 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 02:54:12 -0500 Subject: [PATCH 015/209] Fix: add TYPE_* constants to Account model (resolves undefined constant error in LedgerService) --- server/src/Models/Account.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server/src/Models/Account.php b/server/src/Models/Account.php index 5d728e2..7138e82 100644 --- a/server/src/Models/Account.php +++ b/server/src/Models/Account.php @@ -23,6 +23,15 @@ class Account extends Model use Searchable; use SoftDeletes; + /** + * Account type constants. + */ + const TYPE_ASSET = 'asset'; + const TYPE_LIABILITY = 'liability'; + const TYPE_EQUITY = 'equity'; + const TYPE_REVENUE = 'revenue'; + const TYPE_EXPENSE = 'expense'; + /** * The database table used by the model. * From 67b7e5508b54c8cad57fe15e34fd06f1a971015f Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 02:58:52 -0500 Subject: [PATCH 016/209] Fix: remove namespace from all route model() store.query/findRecord calls (namespace belongs in adapter, not params) --- addon/routes/accounting/accounts/index.js | 2 +- addon/routes/accounting/accounts/index/details.js | 4 +--- addon/routes/accounting/journal/index.js | 2 +- addon/routes/accounting/journal/index/details.js | 4 +--- addon/routes/billing/invoices/index.js | 2 +- addon/routes/billing/invoices/index/details.js | 4 +--- addon/routes/billing/transactions/index.js | 2 +- addon/routes/billing/transactions/index/details.js | 4 +--- addon/routes/settings/gateways/index.js | 2 +- addon/routes/settings/gateways/index/details.js | 4 +--- addon/routes/wallets/index.js | 2 +- addon/routes/wallets/index/details.js | 4 +--- 12 files changed, 12 insertions(+), 24 deletions(-) diff --git a/addon/routes/accounting/accounts/index.js b/addon/routes/accounting/accounts/index.js index 18206a4..72440ca 100644 --- a/addon/routes/accounting/accounts/index.js +++ b/addon/routes/accounting/accounts/index.js @@ -13,6 +13,6 @@ export default class AccountingAccountsIndexRoute extends Route { }; model(params) { - return this.store.query('account', { ...params, namespace: 'ledger/int/v1' }); + return this.store.query('account', params); } } diff --git a/addon/routes/accounting/accounts/index/details.js b/addon/routes/accounting/accounts/index/details.js index adf9990..d80f3ae 100644 --- a/addon/routes/accounting/accounts/index/details.js +++ b/addon/routes/accounting/accounts/index/details.js @@ -5,8 +5,6 @@ export default class AccountingAccountsIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('account', id, { - adapterOptions: { namespace: 'ledger/int/v1' }, - }); + return this.store.findRecord('account', id); } } diff --git a/addon/routes/accounting/journal/index.js b/addon/routes/accounting/journal/index.js index 5f8ef48..fba9524 100644 --- a/addon/routes/accounting/journal/index.js +++ b/addon/routes/accounting/journal/index.js @@ -13,6 +13,6 @@ export default class AccountingJournalIndexRoute extends Route { }; model(params) { - return this.store.query('journal', { ...params, namespace: 'ledger/int/v1' }); + return this.store.query('journal', params); } } diff --git a/addon/routes/accounting/journal/index/details.js b/addon/routes/accounting/journal/index/details.js index 1fc3e24..b6b130d 100644 --- a/addon/routes/accounting/journal/index/details.js +++ b/addon/routes/accounting/journal/index/details.js @@ -5,8 +5,6 @@ export default class AccountingJournalIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('journal', id, { - adapterOptions: { namespace: 'ledger/int/v1' }, - }); + return this.store.findRecord('journal', id); } } diff --git a/addon/routes/billing/invoices/index.js b/addon/routes/billing/invoices/index.js index 7bd8401..e744804 100644 --- a/addon/routes/billing/invoices/index.js +++ b/addon/routes/billing/invoices/index.js @@ -13,6 +13,6 @@ export default class BillingInvoicesIndexRoute extends Route { }; model(params) { - return this.store.query('invoice', { ...params, namespace: 'ledger/int/v1' }); + return this.store.query('invoice', params); } } diff --git a/addon/routes/billing/invoices/index/details.js b/addon/routes/billing/invoices/index/details.js index 971a439..c76bdda 100644 --- a/addon/routes/billing/invoices/index/details.js +++ b/addon/routes/billing/invoices/index/details.js @@ -5,8 +5,6 @@ export default class BillingInvoicesIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('invoice', id, { - adapterOptions: { namespace: 'ledger/int/v1' }, - }); + return this.store.findRecord('invoice', id); } } diff --git a/addon/routes/billing/transactions/index.js b/addon/routes/billing/transactions/index.js index 31ccaf4..d60d443 100644 --- a/addon/routes/billing/transactions/index.js +++ b/addon/routes/billing/transactions/index.js @@ -13,6 +13,6 @@ export default class BillingTransactionsIndexRoute extends Route { }; model(params) { - return this.store.query('transaction', { ...params, namespace: 'ledger/int/v1' }); + return this.store.query('transaction', params); } } diff --git a/addon/routes/billing/transactions/index/details.js b/addon/routes/billing/transactions/index/details.js index 5cd1c8d..cd9431c 100644 --- a/addon/routes/billing/transactions/index/details.js +++ b/addon/routes/billing/transactions/index/details.js @@ -5,8 +5,6 @@ export default class BillingTransactionsIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('transaction', id, { - adapterOptions: { namespace: 'ledger/int/v1' }, - }); + return this.store.findRecord('transaction', id); } } diff --git a/addon/routes/settings/gateways/index.js b/addon/routes/settings/gateways/index.js index 1ca1617..880fee2 100644 --- a/addon/routes/settings/gateways/index.js +++ b/addon/routes/settings/gateways/index.js @@ -5,6 +5,6 @@ export default class SettingsGatewaysIndexRoute extends Route { @service store; model() { - return this.store.query('gateway', { namespace: 'ledger/int/v1' }); + return this.store.query('gateway'); } } diff --git a/addon/routes/settings/gateways/index/details.js b/addon/routes/settings/gateways/index/details.js index 95c3695..ef53bc9 100644 --- a/addon/routes/settings/gateways/index/details.js +++ b/addon/routes/settings/gateways/index/details.js @@ -5,8 +5,6 @@ export default class SettingsGatewaysIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('gateway', id, { - adapterOptions: { namespace: 'ledger/int/v1' }, - }); + return this.store.findRecord('gateway', id); } } diff --git a/addon/routes/wallets/index.js b/addon/routes/wallets/index.js index 0f8d96a..6c64b57 100644 --- a/addon/routes/wallets/index.js +++ b/addon/routes/wallets/index.js @@ -13,6 +13,6 @@ export default class WalletsIndexRoute extends Route { }; model(params) { - return this.store.query('wallet', { ...params, namespace: 'ledger/int/v1' }); + return this.store.query('wallet', params); } } diff --git a/addon/routes/wallets/index/details.js b/addon/routes/wallets/index/details.js index 24ad14f..6f5ae1c 100644 --- a/addon/routes/wallets/index/details.js +++ b/addon/routes/wallets/index/details.js @@ -5,8 +5,6 @@ export default class WalletsIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('wallet', id, { - adapterOptions: { namespace: 'ledger/int/v1' }, - }); + return this.store.findRecord('wallet', id); } } From 8e8aad74e7d5ad509615876634630edb1e6ae06a Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 03:15:10 -0500 Subject: [PATCH 017/209] Refactor: adopt HasApiControllerBehavior pattern for all internal controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add LedgerController base class extending FleetbaseController (sets namespace) - Remove all hand-rolled query/find/create/update/delete methods from every internal v1 controller; CRUD is now handled by HasApiControllerBehavior (queryRecord, findRecord, createRecord, updateRecord, deleteRecord) - Add Filter classes for every resource (Account, Invoice, Journal, Wallet, WalletTransaction, Gateway, GatewayTransaction) — auto-resolved by Resolve::httpFilterForModel(); each filter implements queryForInternal() for company scoping and individual param methods (type, status, query, etc.) - Add missing resources: Journal, GatewayTransaction, Transaction - Rewrite routes.php to use fleetbaseRoutes() for all resources; only custom action routes (charge, refund, transfer, freeze, etc.) are declared manually inside the fleetbaseRoutes callback - TransactionController overrides findRecord() to append journal entry data - JournalController keeps createManual() as a custom action (service-layer orchestration required); standard createRecord() still available for simple creates --- .../Internal/v1/AccountController.php | 172 +-------- .../Internal/v1/GatewayController.php | 255 ++----------- .../Internal/v1/InvoiceController.php | 243 +----------- .../Internal/v1/JournalController.php | 139 +------ .../Internal/v1/TransactionController.php | 101 ++--- .../Internal/v1/WalletController.php | 360 ++++-------------- .../v1/WalletTransactionController.php | 55 +-- .../src/Http/Controllers/LedgerController.php | 13 + server/src/Http/Filter/AccountFilter.php | 56 +++ server/src/Http/Filter/GatewayFilter.php | 51 +++ .../Http/Filter/GatewayTransactionFilter.php | 59 +++ server/src/Http/Filter/InvoiceFilter.php | 63 +++ server/src/Http/Filter/JournalFilter.php | 64 ++++ server/src/Http/Filter/WalletFilter.php | 61 +++ .../Http/Filter/WalletTransactionFilter.php | 64 ++++ .../Http/Resources/v1/GatewayTransaction.php | 39 ++ server/src/Http/Resources/v1/Journal.php | 41 ++ server/src/Http/Resources/v1/Transaction.php | 47 +++ server/src/routes.php | 232 +++++------ 19 files changed, 816 insertions(+), 1299 deletions(-) create mode 100644 server/src/Http/Controllers/LedgerController.php create mode 100644 server/src/Http/Filter/AccountFilter.php create mode 100644 server/src/Http/Filter/GatewayFilter.php create mode 100644 server/src/Http/Filter/GatewayTransactionFilter.php create mode 100644 server/src/Http/Filter/InvoiceFilter.php create mode 100644 server/src/Http/Filter/JournalFilter.php create mode 100644 server/src/Http/Filter/WalletFilter.php create mode 100644 server/src/Http/Filter/WalletTransactionFilter.php create mode 100644 server/src/Http/Resources/v1/GatewayTransaction.php create mode 100644 server/src/Http/Resources/v1/Journal.php create mode 100644 server/src/Http/Resources/v1/Transaction.php diff --git a/server/src/Http/Controllers/Internal/v1/AccountController.php b/server/src/Http/Controllers/Internal/v1/AccountController.php index 334062a..1999b14 100644 --- a/server/src/Http/Controllers/Internal/v1/AccountController.php +++ b/server/src/Http/Controllers/Internal/v1/AccountController.php @@ -2,14 +2,14 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Ledger\Http\Controllers\LedgerController; use Fleetbase\Ledger\Http\Resources\v1\Account as AccountResource; use Fleetbase\Ledger\Models\Account; use Fleetbase\Ledger\Services\LedgerService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -class AccountController extends Controller +class AccountController extends LedgerController { /** * The resource to query. @@ -18,163 +18,13 @@ class AccountController extends Controller */ public $resource = 'account'; - /** - * The model to query. - * - * @var Account - */ - public $model = Account::class; - - /** - * The ledger service instance. - */ - protected LedgerService $ledgerService; - - /** - * Create a new AccountController instance. - */ - public function __construct(LedgerService $ledgerService) - { - $this->ledgerService = $ledgerService; - } - - /** - * Query for accounts. - * - * @return \Illuminate\Http\Response - */ - public function query(Request $request) - { - $results = Account::where('company_uuid', session('company')) - ->when($request->filled('type'), function ($query) use ($request) { - $query->where('type', $request->input('type')); - }) - ->when($request->filled('status'), function ($query) use ($request) { - $query->where('status', $request->input('status')); - }) - ->when($request->filled('search'), function ($query) use ($request) { - $search = $request->input('search'); - $query->where(function ($q) use ($search) { - $q->where('name', 'like', "%{$search}%") - ->orWhere('code', 'like', "%{$search}%") - ->orWhere('description', 'like', "%{$search}%"); - }); - }) - ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) - ->paginate($request->input('limit', 15)); - - return AccountResource::collection($results); - } - - /** - * Find a single account. - * - * @return \Illuminate\Http\Response - */ - public function find($id, Request $request) - { - $account = Account::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); - - return new AccountResource($account); - } - - /** - * Create a new account. - * - * @return \Illuminate\Http\Response - */ - public function create(Request $request) - { - $request->validate([ - 'name' => 'required|string|max:191', - 'code' => 'nullable|string|max:191', - 'type' => 'required|in:asset,liability,equity,revenue,expense', - 'description' => 'nullable|string', - 'currency' => 'nullable|string|size:3', - ]); - - $account = Account::create([ - 'company_uuid' => session('company'), - 'name' => $request->input('name'), - 'code' => $request->input('code'), - 'type' => $request->input('type'), - 'description' => $request->input('description'), - 'currency' => $request->input('currency', 'USD'), - 'status' => 'active', - ]); - - return new AccountResource($account); - } - - /** - * Update an account. - * - * @return \Illuminate\Http\Response - */ - public function update($id, Request $request) - { - $account = Account::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); - - $request->validate([ - 'name' => 'sometimes|required|string|max:191', - 'code' => 'sometimes|nullable|string|max:191', - 'type' => 'sometimes|required|in:asset,liability,equity,revenue,expense', - 'description' => 'nullable|string', - 'status' => 'sometimes|in:active,inactive', - ]); - - $account->update($request->only([ - 'name', - 'code', - 'type', - 'description', - 'status', - ])); - - return new AccountResource($account); - } - - /** - * Delete an account. - * - * @return \Illuminate\Http\Response - */ - public function delete($id, Request $request) - { - $account = Account::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); - - if ($account->is_system_account) { - return response()->json(['error' => 'Cannot delete system account'], 400); - } - - $account->delete(); - - return response()->json(['status' => 'ok']); - } - /** * Recalculate and update the balance for an account. - * - * @return \Illuminate\Http\Response */ - public function recalculateBalance($id, Request $request) + public function recalculateBalance(string $id, Request $request): AccountResource { $account = Account::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) ->firstOrFail(); $account->updateBalance(); @@ -184,22 +34,14 @@ public function recalculateBalance($id, Request $request) /** * Return the general ledger for a specific account. - * - * Returns all journal entries where this account appears on either the debit - * or credit side, ordered chronologically. Supports optional date range filtering - * via `date_from` and `date_to` query parameters. - * - * @param string $id */ - public function generalLedger($id, Request $request): JsonResponse + public function generalLedger(string $id, Request $request): JsonResponse { $account = Account::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) ->firstOrFail(); - $entries = $this->ledgerService->getGeneralLedger( + $entries = app(LedgerService::class)->getGeneralLedger( $account, $request->input('date_from'), $request->input('date_to') diff --git a/server/src/Http/Controllers/Internal/v1/GatewayController.php b/server/src/Http/Controllers/Internal/v1/GatewayController.php index 52d1800..7beffcb 100644 --- a/server/src/Http/Controllers/Internal/v1/GatewayController.php +++ b/server/src/Http/Controllers/Internal/v1/GatewayController.php @@ -2,211 +2,31 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Http\Controllers\FleetbaseController; use Fleetbase\Ledger\DTO\PurchaseRequest; use Fleetbase\Ledger\DTO\RefundRequest; -use Fleetbase\Ledger\Http\Resources\v1\Gateway as GatewayResource; +use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Resources\v1\GatewayTransaction as GatewayTransactionResource; use Fleetbase\Ledger\Models\Gateway; use Fleetbase\Ledger\Models\GatewayTransaction; use Fleetbase\Ledger\Services\PaymentService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Validator; -use Illuminate\Validation\Rule; -/** - * GatewayController. - * - * Handles all CRUD operations for payment gateways and exposes the - * driver manifest endpoint used by the frontend to render dynamic - * gateway configuration forms. - * - * Routes: - * GET /ledger/int/v1/gateways → index (list all gateways for company) - * POST /ledger/int/v1/gateways → store (create new gateway) - * GET /ledger/int/v1/gateways/{id} → show (get single gateway) - * PUT /ledger/int/v1/gateways/{id} → update (update gateway config) - * DELETE /ledger/int/v1/gateways/{id} → destroy (delete gateway) - * GET /ledger/int/v1/gateways/drivers → drivers (available driver manifest) - * POST /ledger/int/v1/gateways/{id}/charge → charge (initiate a payment) - * POST /ledger/int/v1/gateways/{id}/refund → refund (refund a transaction) - * POST /ledger/int/v1/gateways/{id}/setup-intent → setupIntent (tokenize card) - */ -class GatewayController extends FleetbaseController +class GatewayController extends LedgerController { /** - * The resource model class. - */ - protected string $resource = 'gateway'; - - /** - * The model class. - */ - protected string $model = Gateway::class; - - public function __construct( - protected PaymentService $paymentService, - ) { - } - - /** - * List all gateways for the authenticated company. - */ - public function index(Request $request): JsonResponse - { - $companyUuid = session('company'); - - $query = Gateway::where('company_uuid', $companyUuid); - - // Optional filters - if ($request->has('driver')) { - $query->where('driver', $request->input('driver')); - } - - if ($request->has('status')) { - $query->where('status', $request->input('status')); - } - - $gateways = $query->orderBy('created_at', 'desc')->get(); - - return response()->json([ - 'status' => 'ok', - 'gateways' => GatewayResource::collection($gateways), - ]); - } - - /** - * Create a new payment gateway configuration. - */ - public function store(Request $request): JsonResponse - { - $validator = Validator::make($request->all(), [ - 'name' => 'required|string|max:191', - 'driver' => ['required', 'string', Rule::in(['stripe', 'qpay', 'cash'])], - 'config' => 'required|array', - 'is_sandbox' => 'boolean', - 'status' => ['string', Rule::in(['active', 'inactive'])], - 'return_url' => 'nullable|url', - ]); - - if ($validator->fails()) { - return response()->json([ - 'error' => 'Validation failed.', - 'details' => $validator->errors(), - ], 422); - } - - $companyUuid = session('company'); - $userUuid = session('user'); - - // Resolve capabilities from the driver manifest - $manifest = collect($this->paymentService->getDriverManifest()); - $driverInfo = $manifest->firstWhere('code', $request->input('driver')); - $capabilities = $driverInfo['capabilities'] ?? []; - - $gateway = Gateway::create([ - 'company_uuid' => $companyUuid, - 'created_by_uuid' => $userUuid, - 'name' => $request->input('name'), - 'driver' => $request->input('driver'), - 'description' => $request->input('description'), - 'config' => $request->input('config'), // Encrypted at rest by model cast - 'capabilities' => $capabilities, - 'is_sandbox' => $request->boolean('is_sandbox', false), - 'status' => $request->input('status', 'active'), - 'return_url' => $request->input('return_url'), - 'webhook_url' => url('/ledger/webhooks/' . $request->input('driver')), - ]); - - return response()->json([ - 'status' => 'ok', - 'gateway' => new GatewayResource($gateway), - ], 201); - } - - /** - * Get a single gateway by UUID or public_id. - */ - public function show(string $id): JsonResponse - { - $gateway = Gateway::where('company_uuid', session('company')) - ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) - ->firstOrFail(); - - return response()->json([ - 'status' => 'ok', - 'gateway' => new GatewayResource($gateway), - ]); - } - - /** - * Update a gateway configuration. + * The resource to query. + * + * @var string */ - public function update(Request $request, string $id): JsonResponse - { - $gateway = Gateway::where('company_uuid', session('company')) - ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) - ->firstOrFail(); - - $validator = Validator::make($request->all(), [ - 'name' => 'string|max:191', - 'config' => 'array', - 'is_sandbox' => 'boolean', - 'status' => ['string', Rule::in(['active', 'inactive'])], - 'return_url' => 'nullable|url', - ]); + public $resource = 'gateway'; - if ($validator->fails()) { - return response()->json([ - 'error' => 'Validation failed.', - 'details' => $validator->errors(), - ], 422); - } - - $updateData = array_filter([ - 'name' => $request->input('name'), - 'description' => $request->input('description'), - 'is_sandbox' => $request->has('is_sandbox') ? $request->boolean('is_sandbox') : null, - 'status' => $request->input('status'), - 'return_url' => $request->input('return_url'), - ], fn ($v) => $v !== null); - - // Only update config if explicitly provided (avoid overwriting credentials with null) - if ($request->has('config') && is_array($request->input('config'))) { - $updateData['config'] = array_merge( - $gateway->decryptedConfig(), - $request->input('config') - ); - } - - $gateway->update($updateData); - - return response()->json([ - 'status' => 'ok', - 'gateway' => new GatewayResource($gateway->fresh()), - ]); - } - - /** - * Delete a gateway configuration. - */ - public function destroy(string $id): JsonResponse + public function __construct(protected PaymentService $paymentService) { - $gateway = Gateway::where('company_uuid', session('company')) - ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) - ->firstOrFail(); - - $gateway->delete(); - - return response()->json(['status' => 'ok', 'message' => 'Gateway deleted.']); } /** - * Return the full driver manifest. - * - * This endpoint is used by the frontend to dynamically render the - * "Add Gateway" configuration form. It returns each registered driver's - * code, name, capabilities, and config schema. + * Return all available payment driver manifests (name, config schema, capabilities). */ public function drivers(): JsonResponse { @@ -218,24 +38,15 @@ public function drivers(): JsonResponse /** * Initiate a payment charge through a gateway. - * - * @param string $id Gateway UUID or public_id */ public function charge(Request $request, string $id): JsonResponse { - $validator = Validator::make($request->all(), [ + $request->validate([ 'amount' => 'required|integer|min:1', 'currency' => 'required|string|size:3', 'description' => 'required|string|max:500', ]); - if ($validator->fails()) { - return response()->json([ - 'error' => 'Validation failed.', - 'details' => $validator->errors(), - ], 422); - } - $purchaseRequest = new PurchaseRequest( amount: $request->integer('amount'), currency: strtoupper($request->input('currency')), @@ -253,34 +64,25 @@ public function charge(Request $request, string $id): JsonResponse $response = $this->paymentService->charge($id, $purchaseRequest); return response()->json([ - 'status' => $response->status, - 'successful' => $response->successful, - 'gateway_transaction_id' => $response->gatewayTransactionId, - 'message' => $response->message, - 'data' => $response->data, + 'status' => $response->status, + 'successful' => $response->successful, + 'gateway_transaction_id' => $response->gatewayTransactionId, + 'message' => $response->message, + 'data' => $response->data, ], $response->isSuccessful() ? 200 : 422); } /** * Refund a previously captured transaction. - * - * @param string $id Gateway UUID or public_id */ public function refund(Request $request, string $id): JsonResponse { - $validator = Validator::make($request->all(), [ + $request->validate([ 'gateway_transaction_id' => 'required|string', 'amount' => 'required|integer|min:1', 'currency' => 'required|string|size:3', ]); - if ($validator->fails()) { - return response()->json([ - 'error' => 'Validation failed.', - 'details' => $validator->errors(), - ], 422); - } - $refundRequest = new RefundRequest( gatewayTransactionId: $request->input('gateway_transaction_id'), amount: $request->integer('amount'), @@ -301,9 +103,7 @@ public function refund(Request $request, string $id): JsonResponse } /** - * Create a setup intent for payment method tokenization (e.g., Stripe SetupIntent). - * - * @param string $id Gateway UUID or public_id + * Create a setup intent for payment method tokenization (e.g. Stripe SetupIntent). */ public function setupIntent(Request $request, string $id): JsonResponse { @@ -319,28 +119,19 @@ public function setupIntent(Request $request, string $id): JsonResponse /** * List gateway transactions for a specific gateway. - * - * @param string $id Gateway UUID or public_id */ - public function transactions(Request $request, string $id): JsonResponse + public function transactions(Request $request, string $id): \Illuminate\Http\Resources\Json\AnonymousResourceCollection { $gateway = Gateway::where('company_uuid', session('company')) ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) ->firstOrFail(); - $query = GatewayTransaction::where('gateway_uuid', $gateway->uuid); - - if ($request->has('type')) { - $query->where('type', $request->input('type')); - } - - if ($request->has('status')) { - $query->where('status', $request->input('status')); - } - - $transactions = $query->orderBy('created_at', 'desc') + $transactions = GatewayTransaction::where('gateway_uuid', $gateway->uuid) + ->when($request->filled('type'), fn ($q) => $q->where('type', $request->input('type'))) + ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) + ->orderBy('created_at', 'desc') ->paginate($request->integer('per_page', 25)); - return response()->json($transactions); + return GatewayTransactionResource::collection($transactions); } } diff --git a/server/src/Http/Controllers/Internal/v1/InvoiceController.php b/server/src/Http/Controllers/Internal/v1/InvoiceController.php index c886da8..2f3652e 100644 --- a/server/src/Http/Controllers/Internal/v1/InvoiceController.php +++ b/server/src/Http/Controllers/Internal/v1/InvoiceController.php @@ -2,16 +2,13 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\FleetOps\Models\Order; -use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Ledger\Http\Controllers\LedgerController; use Fleetbase\Ledger\Http\Resources\v1\Invoice as InvoiceResource; use Fleetbase\Ledger\Models\Invoice; -use Fleetbase\Ledger\Models\InvoiceItem; use Fleetbase\Ledger\Services\InvoiceService; use Illuminate\Http\Request; -use Illuminate\Support\Facades\DB; -class InvoiceController extends Controller +class InvoiceController extends LedgerController { /** * The resource to query. @@ -21,237 +18,48 @@ class InvoiceController extends Controller public $resource = 'invoice'; /** - * The model to query. - * - * @var Invoice - */ - public $model = Invoice::class; - - /** - * Query for invoices. - * - * @return \Illuminate\Http\Response - */ - public function query(Request $request) - { - $results = Invoice::where('company_uuid', session('company')) - ->with(['customer', 'items']) - ->when($request->filled('status'), function ($query) use ($request) { - $query->where('status', $request->input('status')); - }) - ->when($request->filled('customer'), function ($query) use ($request) { - $query->where('customer_uuid', $request->input('customer')); - }) - ->when($request->filled('search'), function ($query) use ($request) { - $search = $request->input('search'); - $query->where(function ($q) use ($search) { - $q->where('number', 'like', "%{$search}%") - ->orWhere('public_id', 'like', "%{$search}%"); - }); - }) - ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) - ->paginate($request->input('limit', 15)); - - return InvoiceResource::collection($results); - } - - /** - * Find a single invoice. - * - * @return \Illuminate\Http\Response - */ - public function find($id, Request $request) - { - $invoice = Invoice::where('company_uuid', session('company')) - ->with(['customer', 'items', 'order']) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id)->orWhere('number', $id); - }) - ->firstOrFail(); - - return new InvoiceResource($invoice); - } - - /** - * Create a new invoice. - * - * @return \Illuminate\Http\Response - */ - public function create(Request $request) - { - $request->validate([ - 'customer_uuid' => 'required|string', - 'customer_type' => 'required|string', - 'date' => 'required|date', - 'due_date' => 'nullable|date', - 'items' => 'required|array|min:1', - 'items.*.description' => 'required|string', - 'items.*.quantity' => 'required|integer|min:1', - 'items.*.unit_price' => 'required|integer|min:0', - ]); - - return DB::transaction(function () use ($request) { - $invoice = Invoice::create([ - 'company_uuid' => session('company'), - 'customer_uuid' => $request->input('customer_uuid'), - 'customer_type' => $request->input('customer_type'), - 'order_uuid' => $request->input('order_uuid'), - 'number' => Invoice::generateNumber(), - 'date' => $request->input('date'), - 'due_date' => $request->input('due_date'), - 'currency' => $request->input('currency', 'USD'), - 'status' => 'draft', - 'notes' => $request->input('notes'), - 'terms' => $request->input('terms'), - ]); - - // Create invoice items - foreach ($request->input('items', []) as $itemData) { - $item = new InvoiceItem([ - 'description' => $itemData['description'], - 'quantity' => $itemData['quantity'], - 'unit_price' => $itemData['unit_price'], - 'tax_rate' => $itemData['tax_rate'] ?? 0, - ]); - $item->calculateAmount(); - $invoice->items()->save($item); - } - - // Calculate totals - $invoice->calculateTotals(); - $invoice->save(); - - return new InvoiceResource($invoice->load(['customer', 'items'])); - }); - } - - /** - * Update an invoice. - * - * @return \Illuminate\Http\Response - */ - public function update($id, Request $request) - { - $invoice = Invoice::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); - - return DB::transaction(function () use ($invoice, $request) { - $invoice->update($request->only([ - 'customer_uuid', - 'customer_type', - 'date', - 'due_date', - 'notes', - 'terms', - 'status', - ])); - - // Update items if provided - if ($request->has('items')) { - // Delete existing items - $invoice->items()->delete(); - - // Create new items - foreach ($request->input('items', []) as $itemData) { - $item = new InvoiceItem([ - 'description' => $itemData['description'], - 'quantity' => $itemData['quantity'], - 'unit_price' => $itemData['unit_price'], - 'tax_rate' => $itemData['tax_rate'] ?? 0, - ]); - $item->calculateAmount(); - $invoice->items()->save($item); - } - - // Recalculate totals - $invoice->calculateTotals(); - $invoice->save(); - } - - return new InvoiceResource($invoice->load(['customer', 'items'])); - }); - } - - /** - * Delete an invoice. - * - * @return \Illuminate\Http\Response - */ - public function delete($id, Request $request) - { - $invoice = Invoice::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); - - if ($invoice->status === 'paid') { - return response()->json(['error' => 'Cannot delete paid invoice'], 400); - } - - $invoice->delete(); - - return response()->json(['status' => 'ok']); - } - - /** - * Create an invoice from an order. - * - * @return \Illuminate\Http\Response + * Create an invoice from an existing order. */ - public function createFromOrder(Request $request) + public function createFromOrder(Request $request): InvoiceResource { $request->validate([ 'order_uuid' => 'required|string|exists:orders,uuid', ]); - $order = Order::where('company_uuid', session('company')) + $order = \Fleetbase\FleetOps\Models\Order::where('company_uuid', session('company')) ->where('uuid', $request->input('order_uuid')) ->firstOrFail(); - $invoiceService = app(InvoiceService::class); - $invoice = $invoiceService->createFromOrder($order); + $invoice = app(InvoiceService::class)->createFromOrder($order); return new InvoiceResource($invoice->load(['customer', 'items'])); } /** - * Record a payment for an invoice. - * - * @return \Illuminate\Http\Response + * Record a payment against an invoice. */ - public function recordPayment($id, Request $request) + public function recordPayment(string $id, Request $request): InvoiceResource { $request->validate([ 'amount' => 'required|integer|min:1', ]); $invoice = Invoice::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) ->firstOrFail(); - $invoiceService = app(InvoiceService::class); - $invoice = $invoiceService->recordPayment($invoice, $request->input('amount')); + $invoice = app(InvoiceService::class)->recordPayment($invoice, $request->input('amount')); return new InvoiceResource($invoice->load(['customer', 'items'])); } /** - * Mark an invoice as sent. - * - * @return \Illuminate\Http\Response + * Mark an invoice as sent (without dispatching a notification). */ - public function markAsSent($id, Request $request) + public function markAsSent(string $id, Request $request): InvoiceResource { $invoice = Invoice::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) ->firstOrFail(); $invoice->markAsSent(); @@ -260,39 +68,22 @@ public function markAsSent($id, Request $request) } /** - * Send an invoice to the customer via email. - * - * Marks the invoice as sent and dispatches a notification to the customer's - * email address. If the invoice has no customer or the customer has no email, - * a 422 error is returned. - * - * @param string $id - * - * @return \Illuminate\Http\Response + * Send an invoice to the customer via email and mark it as sent. */ - public function send($id, Request $request) + public function send(string $id, Request $request): InvoiceResource { $invoice = Invoice::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) + ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) ->with('customer') ->firstOrFail(); - // Validate that the invoice has a sendable customer if (!$invoice->customer || !$invoice->customer->email) { - return response()->json( - ['error' => 'Invoice customer does not have a valid email address.'], - 422 - ); + abort(422, 'Invoice customer does not have a valid email address.'); } - // Mark as sent $invoice->markAsSent(); // TODO (M5): Dispatch InvoiceSentNotification to $invoice->customer->email - // \Illuminate\Support\Facades\Notification::route('mail', $invoice->customer->email) - // ->notify(new \Fleetbase\Ledger\Notifications\InvoiceSentNotification($invoice)); return new InvoiceResource($invoice->load(['customer', 'items'])); } diff --git a/server/src/Http/Controllers/Internal/v1/JournalController.php b/server/src/Http/Controllers/Internal/v1/JournalController.php index e7e5e7a..5c4287f 100644 --- a/server/src/Http/Controllers/Internal/v1/JournalController.php +++ b/server/src/Http/Controllers/Internal/v1/JournalController.php @@ -2,103 +2,31 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Resources\v1\Journal as JournalResource; use Fleetbase\Ledger\Models\Journal; use Fleetbase\Ledger\Services\LedgerService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -class JournalController extends Controller +class JournalController extends LedgerController { /** - * The ledger service instance. - */ - protected LedgerService $ledgerService; - - /** - * Create a new JournalController instance. - */ - public function __construct(LedgerService $ledgerService) - { - $this->ledgerService = $ledgerService; - } - - /** - * Query journal entries for the authenticated company. + * The resource to query. * - * Supports filtering by: - * - debit_account_uuid — entries where this account was debited - * - credit_account_uuid — entries where this account was credited - * - account_uuid — entries where this account appears on either side - * - date_from — inclusive start date (ISO format) - * - date_to — inclusive end date (ISO format) - * - search — partial match on description - */ - public function query(Request $request): JsonResponse - { - $query = Journal::with(['transaction', 'debitAccount', 'creditAccount']) - ->where('company_uuid', session('company')); - - // Filter by a specific account on either side of the entry - if ($request->filled('account_uuid')) { - $accountUuid = $request->input('account_uuid'); - $query->where(function ($q) use ($accountUuid) { - $q->where('debit_account_uuid', $accountUuid) - ->orWhere('credit_account_uuid', $accountUuid); - }); - } - - if ($request->filled('debit_account_uuid')) { - $query->where('debit_account_uuid', $request->input('debit_account_uuid')); - } - - if ($request->filled('credit_account_uuid')) { - $query->where('credit_account_uuid', $request->input('credit_account_uuid')); - } - - if ($request->filled('date_from')) { - $query->where('date', '>=', $request->input('date_from')); - } - - if ($request->filled('date_to')) { - $query->where('date', '<=', $request->input('date_to')); - } - - if ($request->filled('search')) { - $search = $request->input('search'); - $query->where('description', 'like', "%{$search}%"); - } - - $results = $query - ->orderBy($request->input('sort', 'date'), $request->input('order', 'desc')) - ->orderBy('created_at', 'desc') - ->paginate($request->input('limit', 15)); - - return response()->json($results); - } - - /** - * Find a single journal entry by UUID or public_id. + * @var string */ - public function find(string $id, Request $request): JsonResponse - { - $journal = Journal::with(['transaction', 'debitAccount', 'creditAccount']) - ->where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); - - return response()->json($journal); - } + public $resource = 'journal'; /** * Create a manual journal entry. * * Manual entries allow operators to record adjustments, corrections, or * opening balances that are not generated automatically by system events. + * This action supplements the standard createRecord() provided by the trait + * because it requires custom validation and service-layer orchestration. */ - public function create(Request $request): JsonResponse + public function createManual(Request $request): JsonResponse { $request->validate([ 'debit_account_uuid' => 'required|uuid|exists:ledger_accounts,uuid', @@ -109,7 +37,7 @@ public function create(Request $request): JsonResponse 'date' => 'nullable|date', ]); - $debitAccount = \Fleetbase\Ledger\Models\Account::where('company_uuid', session('company')) + $debitAccount = \Fleetbase\Ledger\Models\Account::where('company_uuid', session('company')) ->where('uuid', $request->input('debit_account_uuid')) ->firstOrFail(); @@ -117,7 +45,7 @@ public function create(Request $request): JsonResponse ->where('uuid', $request->input('credit_account_uuid')) ->firstOrFail(); - $journal = $this->ledgerService->createJournalEntry( + $journal = app(LedgerService::class)->createJournalEntry( $debitAccount, $creditAccount, (int) $request->input('amount'), @@ -130,46 +58,9 @@ public function create(Request $request): JsonResponse ] ); - return response()->json($journal->load(['transaction', 'debitAccount', 'creditAccount']), 201); - } - - /** - * Delete a journal entry. - * - * Only non-system-generated entries (type = 'manual_entry') may be deleted. - * Deleting a journal entry does not reverse the associated Transaction record - * but does recalculate the affected account balances. - */ - public function delete(string $id, Request $request): JsonResponse - { - $journal = Journal::where('company_uuid', session('company')) - ->where(function ($query) use ($id) { - $query->where('uuid', $id)->orWhere('public_id', $id); - }) - ->firstOrFail(); - - // Prevent deletion of system-generated entries - if ($journal->transaction && $journal->transaction->type !== 'manual_entry') { - return response()->json( - ['error' => 'Only manual journal entries may be deleted. System-generated entries are immutable.'], - 422 - ); - } - - // Capture accounts before deletion so we can recalculate their balances - $debitAccount = $journal->debitAccount; - $creditAccount = $journal->creditAccount; - - $journal->delete(); - - // Recalculate balances on both affected accounts - if ($debitAccount) { - $debitAccount->updateBalance(); - } - if ($creditAccount) { - $creditAccount->updateBalance(); - } - - return response()->json(['status' => 'ok']); + return response()->json( + new JournalResource($journal->load(['debitAccount', 'creditAccount'])), + 201 + ); } } diff --git a/server/src/Http/Controllers/Internal/v1/TransactionController.php b/server/src/Http/Controllers/Internal/v1/TransactionController.php index 4bfca7c..3095d7e 100644 --- a/server/src/Http/Controllers/Internal/v1/TransactionController.php +++ b/server/src/Http/Controllers/Internal/v1/TransactionController.php @@ -2,13 +2,20 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Http\Controllers\Controller; -use Fleetbase\Http\Resources\v1\Transaction as TransactionResource; +use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Resources\v1\Transaction as TransactionResource; use Fleetbase\Ledger\Models\Journal; use Fleetbase\Models\Transaction; use Illuminate\Http\Request; -class TransactionController extends Controller +/** + * TransactionController. + * + * Read-only view of core-api Transaction records scoped to the authenticated + * company. The findRecord() method is overridden to append the related journal + * entry when present. + */ +class TransactionController extends LedgerController { /** * The resource to query. @@ -18,86 +25,34 @@ class TransactionController extends Controller public $resource = 'transaction'; /** - * The model to query. - * - * @var Transaction - */ - public $model = Transaction::class; - - /** - * Query for transactions system-wide. - * - * @return \Illuminate\Http\Response - */ - public function query(Request $request) - { - $results = Transaction::where('company_uuid', session('company')) - ->with(['customer', 'items']) - ->when($request->filled('type'), function ($query) use ($request) { - $query->where('type', $request->input('type')); - }) - ->when($request->filled('status'), function ($query) use ($request) { - $query->where('status', $request->input('status')); - }) - ->when($request->filled('gateway'), function ($query) use ($request) { - $query->where('gateway', $request->input('gateway')); - }) - ->when($request->filled('customer'), function ($query) use ($request) { - $query->where('customer_uuid', $request->input('customer')); - }) - ->when($request->filled('search'), function ($query) use ($request) { - $search = $request->input('search'); - $query->where(function ($q) use ($search) { - $q->where('gateway_transaction_id', 'like', "%{$search}%") - ->orWhere('public_id', 'like', "%{$search}%") - ->orWhere('description', 'like', "%{$search}%"); - }); - }) - ->when($request->filled('start_date'), function ($query) use ($request) { - $query->where('created_at', '>=', $request->input('start_date')); - }) - ->when($request->filled('end_date'), function ($query) use ($request) { - $query->where('created_at', '<=', $request->input('end_date')); - }) - ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) - ->paginate($request->input('limit', 15)); - - return TransactionResource::collection($results); - } - - /** - * Find a single transaction. - * - * @return \Illuminate\Http\Response + * Find a single transaction and append its journal entry if one exists. */ - public function find($id, Request $request) + public function findRecord(string $id, Request $request) { $transaction = Transaction::where('company_uuid', session('company')) ->with(['customer', 'items']) - ->where(function ($query) use ($id) { - $query->where('uuid', $id) - ->orWhere('public_id', $id) - ->orWhere('gateway_transaction_id', $id); - }) + ->where(fn ($q) => $q->where('uuid', $id) + ->orWhere('public_id', $id) + ->orWhere('gateway_transaction_id', $id)) ->firstOrFail(); - // Load the journal entry if it exists - $journal = Journal::where('transaction_uuid', $transaction->uuid)->first(); + $journal = Journal::where('transaction_uuid', $transaction->uuid) + ->with(['debitAccount', 'creditAccount']) + ->first(); - $response = new TransactionResource($transaction); - $data = $response->toArray(request()); + $data = (new TransactionResource($transaction))->toArray($request); if ($journal) { $data['journal'] = [ - 'uuid' => $journal->uuid, - 'debit_account_uuid' => $journal->debit_account_uuid, - 'credit_account_uuid' => $journal->credit_account_uuid, - 'amount' => $journal->amount, - 'currency' => $journal->currency, - 'description' => $journal->description, - 'date' => $journal->date, - 'debit_account' => $journal->debitAccount, - 'credit_account' => $journal->creditAccount, + 'uuid' => $journal->uuid, + 'debit_account_uuid' => $journal->debit_account_uuid, + 'credit_account_uuid' => $journal->credit_account_uuid, + 'amount' => $journal->amount, + 'currency' => $journal->currency, + 'description' => $journal->description, + 'date' => $journal->date, + 'debit_account' => $journal->debitAccount, + 'credit_account' => $journal->creditAccount, ]; } diff --git a/server/src/Http/Controllers/Internal/v1/WalletController.php b/server/src/Http/Controllers/Internal/v1/WalletController.php index fc90024..fb35e8a 100644 --- a/server/src/Http/Controllers/Internal/v1/WalletController.php +++ b/server/src/Http/Controllers/Internal/v1/WalletController.php @@ -2,7 +2,7 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Ledger\Http\Controllers\LedgerController; use Fleetbase\Ledger\Http\Resources\v1\Wallet as WalletResource; use Fleetbase\Ledger\Http\Resources\v1\WalletTransaction as WalletTransactionResource; use Fleetbase\Ledger\Models\Wallet; @@ -12,308 +12,88 @@ use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; -/** - * WalletController. - * - * Handles all internal (authenticated) wallet operations for the Ledger extension. - * - * All monetary amounts in requests and responses are in the smallest currency - * unit (cents) unless otherwise noted. - */ -class WalletController extends Controller +class WalletController extends LedgerController { /** * The resource to query. + * + * @var string */ public $resource = 'wallet'; - /** - * The model to query. - */ - public $model = Wallet::class; - - /** - * The WalletService instance. - */ - protected WalletService $walletService; - - public function __construct(WalletService $walletService) + public function __construct(protected WalletService $walletService) { - $this->walletService = $walletService; } // ========================================================================= - // CRUD + // Financial Operations // ========================================================================= /** - * Query wallets for the authenticated company. - * - * Supports filtering by: status, subject_type, search (public_id) - * Supports sorting by any column. - */ - public function query(Request $request): AnonymousResourceCollection - { - $results = Wallet::where('company_uuid', session('company')) - ->with(['subject']) - ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) - ->when($request->filled('subject_type'), fn ($q) => $q->where('subject_type', $request->input('subject_type'))) - ->when($request->filled('type'), function ($q) use ($request) { - // Filter by inferred type (driver/customer/company) via subject_type LIKE - $type = $request->input('type'); - $q->where('subject_type', 'like', "%{$type}%"); - }) - ->when($request->filled('search'), function ($q) use ($request) { - $search = $request->input('search'); - $q->where('public_id', 'like', "%{$search}%"); - }) - ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) - ->paginate($request->input('limit', 15)); - - return WalletResource::collection($results); - } - - /** - * Find a single wallet by UUID or public_id. - */ - public function find(string $id, Request $request): WalletResource - { - $wallet = Wallet::where('company_uuid', session('company')) - ->with(['subject']) - ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) - ->firstOrFail(); - - return new WalletResource($wallet); - } - - /** - * Create a new wallet for a subject. - */ - public function create(Request $request): WalletResource - { - $request->validate([ - 'subject_uuid' => 'required|string', - 'subject_type' => 'required|string', - 'currency' => 'nullable|string|size:3', - ]); - - $wallet = Wallet::create([ - 'company_uuid' => session('company'), - 'subject_uuid' => $request->input('subject_uuid'), - 'subject_type' => $request->input('subject_type'), - 'currency' => strtoupper($request->input('currency', 'USD')), - 'balance' => 0, - 'status' => Wallet::STATUS_ACTIVE, - ]); - - return new WalletResource($wallet->load('subject')); - } - - /** - * Update wallet metadata (status only — balance changes go through dedicated endpoints). - */ - public function update(string $id, Request $request): WalletResource - { - $wallet = $this->resolveWallet($id); - - $request->validate([ - 'status' => 'sometimes|in:active,frozen,closed', - ]); - - $wallet->update($request->only(['status'])); - - return new WalletResource($wallet->fresh('subject')); - } - - /** - * Delete a wallet. Only allowed if balance is zero. - */ - public function delete(string $id, Request $request): JsonResponse - { - $wallet = $this->resolveWallet($id); - - if ($wallet->balance !== 0) { - return response()->json([ - 'error' => "Cannot delete wallet [{$wallet->public_id}] with non-zero balance ({$wallet->balance} {$wallet->currency}).", - ], 422); - } - - $wallet->delete(); - - return response()->json(['status' => 'ok', 'message' => 'Wallet deleted successfully.']); - } - - // ========================================================================= - // Balance Operations - // ========================================================================= - - /** - * Manually deposit funds into a wallet (operator action). - * - * Request body: - * - amount (int, required) Amount in cents - * - description (string) - * - reference (string) Optional external reference + * Transfer funds between two wallets. */ - public function deposit(string $id, Request $request): JsonResponse + public function transfer(string $id, Request $request): JsonResponse { $request->validate([ - 'amount' => 'required|integer|min:1', - 'description' => 'nullable|string|max:500', - 'reference' => 'nullable|string|max:191', + 'to_wallet_uuid' => 'required|uuid', + 'amount' => 'required|integer|min:1', + 'description' => 'nullable|string|max:500', ]); - $wallet = $this->resolveWallet($id); - - try { - $transaction = $this->walletService->deposit( - wallet: $wallet, - amount: $request->integer('amount'), - description: $request->input('description', ''), - type: WalletTransaction::TYPE_DEPOSIT, - options: ['reference' => $request->input('reference')] - ); - - return response()->json([ - 'wallet' => new WalletResource($wallet->fresh()), - 'transaction' => new WalletTransactionResource($transaction), - ]); - } catch (\Exception $e) { - return response()->json(['error' => $e->getMessage()], 422); - } - } - - /** - * Manually withdraw funds from a wallet (operator action). - * - * Request body: - * - amount (int, required) Amount in cents - * - description (string) - * - reference (string) Optional external reference - */ - public function withdraw(string $id, Request $request): JsonResponse - { - $request->validate([ - 'amount' => 'required|integer|min:1', - 'description' => 'nullable|string|max:500', - 'reference' => 'nullable|string|max:191', - ]); + $fromWallet = $this->resolveWallet($id); + $toWallet = $this->resolveWallet($request->input('to_wallet_uuid')); - $wallet = $this->resolveWallet($id); + $result = $this->walletService->transfer( + from: $fromWallet, + to: $toWallet, + amount: $request->integer('amount'), + description: $request->input('description', 'Wallet transfer') + ); - try { - $transaction = $this->walletService->withdraw( - wallet: $wallet, - amount: $request->integer('amount'), - description: $request->input('description', ''), - type: WalletTransaction::TYPE_WITHDRAWAL, - options: ['reference' => $request->input('reference')] - ); - - return response()->json([ - 'wallet' => new WalletResource($wallet->fresh()), - 'transaction' => new WalletTransactionResource($transaction), - ]); - } catch (\Exception $e) { - return response()->json(['error' => $e->getMessage()], 422); - } - } - - /** - * Transfer funds between two wallets. - * - * Request body: - * - from_wallet (string, required) UUID or public_id of source wallet - * - to_wallet (string, required) UUID or public_id of destination wallet - * - amount (int, required) Amount in cents - * - description (string) - */ - public function transfer(Request $request): JsonResponse - { - $request->validate([ - 'from_wallet' => 'required|string', - 'to_wallet' => 'required|string', - 'amount' => 'required|integer|min:1', - 'description' => 'nullable|string|max:500', + return response()->json([ + 'from_wallet' => new WalletResource($fromWallet->fresh()), + 'to_wallet' => new WalletResource($toWallet->fresh()), + 'transaction' => new WalletTransactionResource($result), ]); - - $fromWallet = $this->resolveWallet($request->input('from_wallet')); - $toWallet = $this->resolveWallet($request->input('to_wallet')); - - try { - $result = $this->walletService->transfer( - fromWallet: $fromWallet, - toWallet: $toWallet, - amount: $request->integer('amount'), - description: $request->input('description', '') - ); - - return response()->json([ - 'from_wallet' => new WalletResource($fromWallet->fresh()), - 'to_wallet' => new WalletResource($toWallet->fresh()), - 'from_transaction' => new WalletTransactionResource($result['from']), - 'to_transaction' => new WalletTransactionResource($result['to']), - ]); - } catch (\Exception $e) { - return response()->json(['error' => $e->getMessage()], 422); - } } /** - * Top up a wallet by charging a payment gateway. - * - * Request body: - * - gateway (string, required) Gateway UUID or public_id - * - amount (int, required) Amount in cents - * - description (string) - * - payment_method_token (string) Stripe payment method token (pm_xxx) - * - customer_id (string) Gateway customer ID - * - customer_email (string) + * Top up a wallet via a payment gateway. */ public function topUp(string $id, Request $request): JsonResponse { $request->validate([ - 'gateway' => 'required|string', - 'amount' => 'required|integer|min:1', - 'description' => 'nullable|string|max:500', - 'payment_method_token' => 'nullable|string', - 'customer_id' => 'nullable|string', - 'customer_email' => 'nullable|email', + 'amount' => 'required|integer|min:1', + 'gateway_uuid' => 'required|uuid', + 'payment_method_token' => 'required|string', + 'description' => 'nullable|string|max:500', ]); $wallet = $this->resolveWallet($id); - try { - $result = $this->walletService->topUp( - wallet: $wallet, - amount: $request->integer('amount'), - gatewayUuid: $request->input('gateway'), - paymentData: $request->only(['payment_method_token', 'customer_id', 'customer_email']), - description: $request->input('description', '') - ); - - $response = [ - 'wallet' => new WalletResource($result['wallet']), - 'gateway_response' => $result['gateway_response'], - ]; - - if ($result['transaction']) { - $response['transaction'] = new WalletTransactionResource($result['transaction']); - } - - return response()->json($response); - } catch (\Exception $e) { - return response()->json(['error' => $e->getMessage()], 422); + $result = $this->walletService->topUp( + wallet: $wallet, + amount: $request->integer('amount'), + gatewayUuid: $request->input('gateway_uuid'), + paymentMethodToken: $request->input('payment_method_token'), + description: $request->input('description', 'Wallet top-up') + ); + + $response = [ + 'wallet' => new WalletResource($wallet->fresh()), + 'status' => $result['status'], + 'gateway_response' => $result['gateway_response'], + ]; + + if ($result['transaction']) { + $response['transaction'] = new WalletTransactionResource($result['transaction']); } + + return response()->json($response); } /** - * Process a payout from a wallet (driver earnings withdrawal). - * - * Request body: - * - amount (int, required) Amount in cents - * - description (string) - * - reference (string) Optional external reference (bank transfer ID, etc.) + * Process a payout from a wallet (e.g. driver earnings withdrawal). */ public function payout(string $id, Request $request): JsonResponse { @@ -325,22 +105,18 @@ public function payout(string $id, Request $request): JsonResponse $wallet = $this->resolveWallet($id); - try { - $transaction = $this->walletService->withdraw( - wallet: $wallet, - amount: $request->integer('amount'), - description: $request->input('description', 'Driver payout'), - type: WalletTransaction::TYPE_PAYOUT, - options: ['reference' => $request->input('reference')] - ); - - return response()->json([ - 'wallet' => new WalletResource($wallet->fresh()), - 'transaction' => new WalletTransactionResource($transaction), - ]); - } catch (\Exception $e) { - return response()->json(['error' => $e->getMessage()], 422); - } + $transaction = $this->walletService->withdraw( + wallet: $wallet, + amount: $request->integer('amount'), + description: $request->input('description', 'Driver payout'), + type: WalletTransaction::TYPE_PAYOUT, + options: ['reference' => $request->input('reference')] + ); + + return response()->json([ + 'wallet' => new WalletResource($wallet->fresh()), + 'transaction' => new WalletTransactionResource($transaction), + ]); } // ========================================================================= @@ -348,10 +124,7 @@ public function payout(string $id, Request $request): JsonResponse // ========================================================================= /** - * Get the transaction history for a wallet. - * - * Supports filtering by: type, direction, status, date_from, date_to - * Supports pagination via limit/page. + * Get the transaction history for a specific wallet. */ public function getTransactions(string $id, Request $request): AnonymousResourceCollection { @@ -397,14 +170,12 @@ public function unfreeze(string $id, Request $request): WalletResource /** * Recalculate and correct a wallet's balance from its transaction history. - * This is a reconciliation utility for operators. */ public function recalculate(string $id, Request $request): JsonResponse { - $wallet = $this->resolveWallet($id); - - $oldBalance = $wallet->balance; - $newBalance = $this->walletService->recalculateBalance($wallet); + $wallet = $this->resolveWallet($id); + $oldBalance = $wallet->balance; + $newBalance = $this->walletService->recalculateBalance($wallet); return response()->json([ 'wallet' => new WalletResource($wallet->fresh()), @@ -415,12 +186,9 @@ public function recalculate(string $id, Request $request): JsonResponse } // ========================================================================= - // Private Helpers + // Helpers // ========================================================================= - /** - * Resolve a wallet by UUID or public_id, scoped to the authenticated company. - */ protected function resolveWallet(string $id): Wallet { return Wallet::where('company_uuid', session('company')) diff --git a/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php b/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php index d21ac6f..7a4fce5 100644 --- a/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php +++ b/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php @@ -2,59 +2,22 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Http\Controllers\Controller; -use Fleetbase\Ledger\Http\Resources\v1\WalletTransaction as WalletTransactionResource; -use Fleetbase\Ledger\Models\WalletTransaction; -use Illuminate\Http\Request; -use Illuminate\Http\Resources\Json\AnonymousResourceCollection; +use Fleetbase\Ledger\Http\Controllers\LedgerController; /** * WalletTransactionController. * - * Provides a standalone query endpoint for wallet transactions across all wallets. - * Useful for the Ledger dashboard to show a company-wide transaction feed. + * Provides a company-scoped query/find endpoint for wallet transactions + * across all wallets. All CRUD is handled by HasApiControllerBehavior via + * LedgerController; the WalletTransactionFilter handles company scoping + * and parameter filtering automatically. */ -class WalletTransactionController extends Controller +class WalletTransactionController extends LedgerController { /** - * Query wallet transactions across all wallets for the authenticated company. + * The resource to query. * - * Supports filtering by: wallet_uuid, type, direction, status, date_from, date_to, search + * @var string */ - public function query(Request $request): AnonymousResourceCollection - { - $results = WalletTransaction::where('company_uuid', session('company')) - ->with(['wallet', 'subject']) - ->when($request->filled('wallet'), fn ($q) => $q->where('wallet_uuid', $request->input('wallet'))) - ->when($request->filled('type'), fn ($q) => $q->where('type', $request->input('type'))) - ->when($request->filled('direction'), fn ($q) => $q->where('direction', $request->input('direction'))) - ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) - ->when($request->filled('date_from'), fn ($q) => $q->whereDate('created_at', '>=', $request->input('date_from'))) - ->when($request->filled('date_to'), fn ($q) => $q->whereDate('created_at', '<=', $request->input('date_to'))) - ->when($request->filled('search'), function ($q) use ($request) { - $search = $request->input('search'); - $q->where(function ($inner) use ($search) { - $inner->where('public_id', 'like', "%{$search}%") - ->orWhere('description', 'like', "%{$search}%") - ->orWhere('reference', 'like', "%{$search}%"); - }); - }) - ->orderBy($request->input('sort', 'created_at'), $request->input('order', 'desc')) - ->paginate($request->input('limit', 25)); - - return WalletTransactionResource::collection($results); - } - - /** - * Find a single wallet transaction by UUID or public_id. - */ - public function find(string $id, Request $request): WalletTransactionResource - { - $transaction = WalletTransaction::where('company_uuid', session('company')) - ->with(['wallet', 'subject']) - ->where(fn ($q) => $q->where('uuid', $id)->orWhere('public_id', $id)) - ->firstOrFail(); - - return new WalletTransactionResource($transaction); - } + public $resource = 'wallet-transaction'; } diff --git a/server/src/Http/Controllers/LedgerController.php b/server/src/Http/Controllers/LedgerController.php new file mode 100644 index 0000000..70fac7f --- /dev/null +++ b/server/src/Http/Controllers/LedgerController.php @@ -0,0 +1,13 @@ +builder->where('company_uuid', $this->session->get('company')); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->searchWhere('name', $searchQuery) + ->orWhere('code', 'like', "%{$searchQuery}%"); + }); + } + + public function type(?string $type): void + { + $this->builder->where('type', $type); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function code(?string $code): void + { + $this->builder->searchWhere('code', $code); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } +} diff --git a/server/src/Http/Filter/GatewayFilter.php b/server/src/Http/Filter/GatewayFilter.php new file mode 100644 index 0000000..a1a29bf --- /dev/null +++ b/server/src/Http/Filter/GatewayFilter.php @@ -0,0 +1,51 @@ +builder->where('company_uuid', $this->session->get('company')); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->searchWhere('name', $searchQuery) + ->orWhere('driver', 'like', "%{$searchQuery}%"); + }); + } + + public function driver(?string $driver): void + { + $this->builder->where('driver', $driver); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } +} diff --git a/server/src/Http/Filter/GatewayTransactionFilter.php b/server/src/Http/Filter/GatewayTransactionFilter.php new file mode 100644 index 0000000..37c989b --- /dev/null +++ b/server/src/Http/Filter/GatewayTransactionFilter.php @@ -0,0 +1,59 @@ +builder + ->where('company_uuid', $this->session->get('company')) + ->with(['gateway']); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->searchWhere('gateway_transaction_id', $searchQuery) + ->orWhere('description', 'like', "%{$searchQuery}%") + ->orWhere('public_id', 'like', "%{$searchQuery}%"); + }); + } + + public function type(?string $type): void + { + $this->builder->where('type', $type); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function gateway(?string $gateway): void + { + $this->builder->where('gateway_uuid', $gateway); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } +} diff --git a/server/src/Http/Filter/InvoiceFilter.php b/server/src/Http/Filter/InvoiceFilter.php new file mode 100644 index 0000000..2339782 --- /dev/null +++ b/server/src/Http/Filter/InvoiceFilter.php @@ -0,0 +1,63 @@ +builder + ->where('company_uuid', $this->session->get('company')) + ->with(['customer', 'items']); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->searchWhere('number', $searchQuery) + ->orWhere('notes', 'like', "%{$searchQuery}%"); + }); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function customer(?string $customer): void + { + $this->builder->where('customer_uuid', $customer); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } + + public function dueDate($dueDate): void + { + $dueDate = \Fleetbase\Support\Utils::dateRange($dueDate); + if (is_array($dueDate)) { + $this->builder->whereBetween('due_date', $dueDate); + } else { + $this->builder->whereDate('due_date', $dueDate); + } + } +} diff --git a/server/src/Http/Filter/JournalFilter.php b/server/src/Http/Filter/JournalFilter.php new file mode 100644 index 0000000..4282400 --- /dev/null +++ b/server/src/Http/Filter/JournalFilter.php @@ -0,0 +1,64 @@ +builder + ->where('company_uuid', $this->session->get('company')) + ->with(['debitAccount', 'creditAccount']); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->searchWhere('memo', $searchQuery) + ->orWhere('reference', 'like', "%{$searchQuery}%") + ->orWhere('public_id', 'like', "%{$searchQuery}%"); + }); + } + + public function type(?string $type): void + { + $this->builder->where('type', $type); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function debitAccount(?string $account): void + { + $this->builder->where('debit_account_uuid', $account); + } + + public function creditAccount(?string $account): void + { + $this->builder->where('credit_account_uuid', $account); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } +} diff --git a/server/src/Http/Filter/WalletFilter.php b/server/src/Http/Filter/WalletFilter.php new file mode 100644 index 0000000..ca9d563 --- /dev/null +++ b/server/src/Http/Filter/WalletFilter.php @@ -0,0 +1,61 @@ +builder->where('company_uuid', $this->session->get('company')); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->searchWhere('name', $searchQuery) + ->orWhere('public_id', 'like', "%{$searchQuery}%"); + }); + } + + public function type(?string $type): void + { + $this->builder->where('type', $type); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function currency(?string $currency): void + { + $this->builder->where('currency', strtoupper($currency)); + } + + public function owner(?string $owner): void + { + $this->builder->where('owner_uuid', $owner); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } +} diff --git a/server/src/Http/Filter/WalletTransactionFilter.php b/server/src/Http/Filter/WalletTransactionFilter.php new file mode 100644 index 0000000..8163928 --- /dev/null +++ b/server/src/Http/Filter/WalletTransactionFilter.php @@ -0,0 +1,64 @@ +builder + ->where('company_uuid', $this->session->get('company')) + ->with(['wallet']); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->searchWhere('description', $searchQuery) + ->orWhere('reference', 'like', "%{$searchQuery}%") + ->orWhere('public_id', 'like', "%{$searchQuery}%"); + }); + } + + public function type(?string $type): void + { + $this->builder->where('type', $type); + } + + public function direction(?string $direction): void + { + $this->builder->where('direction', $direction); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function wallet(?string $wallet): void + { + $this->builder->where('wallet_uuid', $wallet); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } +} diff --git a/server/src/Http/Resources/v1/GatewayTransaction.php b/server/src/Http/Resources/v1/GatewayTransaction.php new file mode 100644 index 0000000..efd2ff5 --- /dev/null +++ b/server/src/Http/Resources/v1/GatewayTransaction.php @@ -0,0 +1,39 @@ + $this->when(Http::isInternalRequest(), $this->id, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id), + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), + 'gateway_uuid' => $this->when(Http::isInternalRequest(), $this->gateway_uuid), + 'gateway' => $this->whenLoaded('gateway', fn () => new Gateway($this->gateway)), + 'gateway_transaction_id' => $this->gateway_transaction_id, + 'type' => $this->type, + 'status' => $this->status, + 'amount' => $this->amount, + 'currency' => $this->currency, + 'description' => $this->description, + 'customer_uuid' => $this->when(Http::isInternalRequest(), $this->customer_uuid), + 'invoice_uuid' => $this->when(Http::isInternalRequest(), $this->invoice_uuid), + 'meta' => $this->meta, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/Http/Resources/v1/Journal.php b/server/src/Http/Resources/v1/Journal.php new file mode 100644 index 0000000..cf6ac57 --- /dev/null +++ b/server/src/Http/Resources/v1/Journal.php @@ -0,0 +1,41 @@ + $this->when(Http::isInternalRequest(), $this->id, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id), + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), + 'transaction_uuid' => $this->when(Http::isInternalRequest(), $this->transaction_uuid), + 'debit_account_uuid' => $this->when(Http::isInternalRequest(), $this->debit_account_uuid), + 'credit_account_uuid' => $this->when(Http::isInternalRequest(), $this->credit_account_uuid), + 'debit_account' => $this->whenLoaded('debitAccount', fn () => new Account($this->debitAccount)), + 'credit_account' => $this->whenLoaded('creditAccount', fn () => new Account($this->creditAccount)), + 'amount' => $this->amount, + 'currency' => $this->currency, + 'type' => $this->type, + 'status' => $this->status, + 'memo' => $this->memo, + 'reference' => $this->reference, + 'date' => $this->date, + 'meta' => $this->meta, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/Http/Resources/v1/Transaction.php b/server/src/Http/Resources/v1/Transaction.php new file mode 100644 index 0000000..feb4e21 --- /dev/null +++ b/server/src/Http/Resources/v1/Transaction.php @@ -0,0 +1,47 @@ + $this->when(Http::isInternalRequest(), $this->id, $this->public_id), + 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), + 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id), + 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), + 'owner_uuid' => $this->when(Http::isInternalRequest(), $this->owner_uuid), + 'owner_type' => $this->when(Http::isInternalRequest(), $this->owner_type), + 'customer_uuid' => $this->when(Http::isInternalRequest(), $this->customer_uuid), + 'customer_type' => $this->when(Http::isInternalRequest(), $this->customer_type), + 'gateway_transaction_id' => $this->gateway_transaction_id, + 'gateway' => $this->gateway, + 'gateway_uuid' => $this->when(Http::isInternalRequest(), $this->gateway_uuid), + 'amount' => $this->amount, + 'currency' => $this->currency, + 'description' => $this->description, + 'type' => $this->type, + 'status' => $this->status, + 'meta' => $this->meta, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/server/src/routes.php b/server/src/routes.php index 3ce30f1..828f66f 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -12,7 +12,6 @@ | valid Fleetbase session or API key. | */ - Route::prefix(config('ledger.api.routing.prefix', 'ledger'))->namespace('Fleetbase\Ledger\Http\Controllers')->group( function ($router) { /* @@ -25,8 +24,6 @@ function ($router) { | performs its own signature verification internally. | | Route: POST /ledger/webhooks/{driver} - | Example: POST /ledger/webhooks/stripe - | POST /ledger/webhooks/qpay */ $router->post('webhooks/{driver}', 'WebhookController@handle'); @@ -34,24 +31,12 @@ function ($router) { |-------------------------------------------------------------------------- | Public API Routes (Authenticated via API Key — Customer / Driver facing) |-------------------------------------------------------------------------- - | - | These routes are accessible to Fleetbase API consumers (customers, drivers) - | authenticated via their API key. Each consumer can only access their own wallet. - | - | Prefix: /ledger/v1/... */ $router->prefix(config('ledger.api.routing.version_prefix', 'v1'))->group( function ($router) { $router->group( ['middleware' => ['fleetbase.api']], function ($router) { - // ------------------------------------------------------------ - // Wallet — Public (Customer / Driver) - // ------------------------------------------------------------ - // GET /ledger/v1/wallet — Get own wallet (auto-provisions if needed) - // GET /ledger/v1/wallet/balance — Get own wallet balance - // GET /ledger/v1/wallet/transactions — Get own wallet transaction history - // POST /ledger/v1/wallet/topup — Top up own wallet via payment gateway $router->get('wallet', 'Api\v1\WalletApiController@getWallet'); $router->get('wallet/balance', 'Api\v1\WalletApiController@getBalance'); $router->get('wallet/transactions', 'Api\v1\WalletApiController@getTransactions'); @@ -63,132 +48,105 @@ function ($router) { /* |-------------------------------------------------------------------------- - | Internal Ledger API Routes + | Internal Routes (Authenticated via Fleetbase Session — Console) |-------------------------------------------------------------------------- - | - | These routes are consumed by the Fleetbase console frontend (Ember engine). - | They are protected and require an authenticated session. */ - $router->prefix(config('ledger.api.routing.internal_prefix', 'int'))->group( + $router->prefix(config('ledger.api.routing.internal_prefix', 'int'))->namespace('Internal')->group( function ($router) { - $router->group( - ['prefix' => 'v1', 'middleware' => ['fleetbase.protected']], + $router->prefix(config('ledger.api.routing.version_prefix', 'v1'))->namespace('v1')->group( function ($router) { - // ------------------------------------------------------------ - // Accounts (Chart of Accounts) - // ------------------------------------------------------------ - $router->get('accounts', 'Internal\v1\AccountController@query'); - $router->get('accounts/{id}', 'Internal\v1\AccountController@find'); - $router->post('accounts', 'Internal\v1\AccountController@create'); - $router->put('accounts/{id}', 'Internal\v1\AccountController@update'); - $router->delete('accounts/{id}', 'Internal\v1\AccountController@delete'); - $router->post('accounts/{id}/recalculate-balance', 'Internal\v1\AccountController@recalculateBalance'); - - // General ledger for a specific account (all journal entries for that account) - $router->get('accounts/{id}/ledger', 'Internal\v1\AccountController@generalLedger'); - - // ------------------------------------------------------------ - // Journal Entries - // ------------------------------------------------------------ - $router->get('journals', 'Internal\v1\JournalController@query'); - $router->get('journals/{id}', 'Internal\v1\JournalController@find'); - $router->post('journals', 'Internal\v1\JournalController@create'); - $router->delete('journals/{id}', 'Internal\v1\JournalController@delete'); - - // ------------------------------------------------------------ - // Invoices - // ------------------------------------------------------------ - $router->get('invoices', 'Internal\v1\InvoiceController@query'); - $router->get('invoices/{id}', 'Internal\v1\InvoiceController@find'); - $router->post('invoices', 'Internal\v1\InvoiceController@create'); - $router->put('invoices/{id}', 'Internal\v1\InvoiceController@update'); - $router->delete('invoices/{id}', 'Internal\v1\InvoiceController@delete'); - $router->post('invoices/from-order', 'Internal\v1\InvoiceController@createFromOrder'); - $router->post('invoices/{id}/record-payment', 'Internal\v1\InvoiceController@recordPayment'); - $router->post('invoices/{id}/mark-as-sent', 'Internal\v1\InvoiceController@markAsSent'); - $router->post('invoices/{id}/send', 'Internal\v1\InvoiceController@send'); - - // ------------------------------------------------------------ - // Wallets — Internal (Operator / Admin) - // ------------------------------------------------------------ - $router->get('wallets', 'Internal\v1\WalletController@query'); - $router->get('wallets/{id}', 'Internal\v1\WalletController@find'); - $router->post('wallets', 'Internal\v1\WalletController@create'); - $router->put('wallets/{id}', 'Internal\v1\WalletController@update'); - $router->delete('wallets/{id}', 'Internal\v1\WalletController@delete'); - - // Balance operations - $router->post('wallets/{id}/deposit', 'Internal\v1\WalletController@deposit'); - $router->post('wallets/{id}/withdraw', 'Internal\v1\WalletController@withdraw'); - $router->post('wallets/transfer', 'Internal\v1\WalletController@transfer'); - $router->post('wallets/{id}/topup', 'Internal\v1\WalletController@topUp'); - $router->post('wallets/{id}/payout', 'Internal\v1\WalletController@payout'); - - // State management - $router->post('wallets/{id}/freeze', 'Internal\v1\WalletController@freeze'); - $router->post('wallets/{id}/unfreeze', 'Internal\v1\WalletController@unfreeze'); - $router->post('wallets/{id}/recalculate', 'Internal\v1\WalletController@recalculate'); - - // Transaction history for a specific wallet - $router->get('wallets/{id}/transactions', 'Internal\v1\WalletController@getTransactions'); - - // ------------------------------------------------------------ - // Wallet Transactions — Internal (standalone query endpoint) - // ------------------------------------------------------------ - $router->get('wallet-transactions', 'Internal\v1\WalletTransactionController@query'); - $router->get('wallet-transactions/{id}', 'Internal\v1\WalletTransactionController@find'); - - // ------------------------------------------------------------ - // Transactions (read-only view of core-api Transaction records) - // ------------------------------------------------------------ - $router->get('transactions', 'Internal\v1\TransactionController@query'); - $router->get('transactions/{id}', 'Internal\v1\TransactionController@find'); - - // ------------------------------------------------------------ - // Payment Gateways - // ------------------------------------------------------------ - // Driver manifest — returns all available drivers with config schemas - // Must be registered BEFORE the {id} route to avoid route conflicts - $router->get('gateways/drivers', 'Internal\v1\GatewayController@drivers'); - - // Gateway CRUD - $router->get('gateways', 'Internal\v1\GatewayController@index'); - $router->post('gateways', 'Internal\v1\GatewayController@store'); - $router->get('gateways/{id}', 'Internal\v1\GatewayController@show'); - $router->put('gateways/{id}', 'Internal\v1\GatewayController@update'); - $router->delete('gateways/{id}', 'Internal\v1\GatewayController@destroy'); - - // Gateway payment operations - $router->post('gateways/{id}/charge', 'Internal\v1\GatewayController@charge'); - $router->post('gateways/{id}/refund', 'Internal\v1\GatewayController@refund'); - $router->post('gateways/{id}/setup-intent', 'Internal\v1\GatewayController@setupIntent'); - - // Gateway transaction history - $router->get('gateways/{id}/transactions', 'Internal\v1\GatewayController@transactions'); - - // ------------------------------------------------------------ - // Reports & Financial Statements - // ------------------------------------------------------------ - // Dashboard — KPIs, revenue trend, recent journals, invoice counts - $router->get('reports/dashboard', 'Internal\v1\ReportController@dashboard'); - - // Trial Balance — all accounts with debit/credit totals as of a date - $router->get('reports/trial-balance', 'Internal\v1\ReportController@trialBalance'); - - // Balance Sheet — Assets = Liabilities + Equity as of a date - $router->get('reports/balance-sheet', 'Internal\v1\ReportController@balanceSheet'); - - // Income Statement (P&L) — Revenue - Expenses = Net Income for a period - $router->get('reports/income-statement', 'Internal\v1\ReportController@incomeStatement'); - - // Cash Flow Summary — Operating / Financing / Investing activities for a period - $router->get('reports/cash-flow', 'Internal\v1\ReportController@cashFlow'); - - // AR Aging — Outstanding invoices bucketed by days overdue - $router->get('reports/ar-aging', 'Internal\v1\ReportController@arAging'); - - // Wallet Summary — wallet counts, balances, period stats, top wallets - $router->get('reports/wallet-summary', 'Internal\v1\ReportController@walletSummary'); + $router->group( + ['middleware' => ['fleetbase.protected']], + function ($router) { + // ---------------------------------------------------------------- + // Chart of Accounts + // ---------------------------------------------------------------- + $router->fleetbaseRoutes( + 'accounts', + function ($router, $controller) { + $router->get('{id}/general-ledger', $controller('generalLedger')); + $router->post('{id}/recalculate-balance', $controller('recalculateBalance')); + } + ); + + // ---------------------------------------------------------------- + // Invoices + // ---------------------------------------------------------------- + $router->fleetbaseRoutes( + 'invoices', + function ($router, $controller) { + $router->post('create-from-order', $controller('createFromOrder')); + $router->post('{id}/record-payment', $controller('recordPayment')); + $router->post('{id}/mark-as-sent', $controller('markAsSent')); + $router->post('{id}/send', $controller('send')); + } + ); + + // ---------------------------------------------------------------- + // Journal Entries + // ---------------------------------------------------------------- + $router->fleetbaseRoutes( + 'journals', + function ($router, $controller) { + $router->post('manual', $controller('createManual')); + } + ); + + // ---------------------------------------------------------------- + // Wallets + // ---------------------------------------------------------------- + $router->fleetbaseRoutes( + 'wallets', + function ($router, $controller) { + $router->post('{id}/transfer', $controller('transfer')); + $router->post('{id}/topup', $controller('topUp')); + $router->post('{id}/payout', $controller('payout')); + $router->post('{id}/freeze', $controller('freeze')); + $router->post('{id}/unfreeze', $controller('unfreeze')); + $router->post('{id}/recalculate', $controller('recalculate')); + $router->get('{id}/transactions', $controller('getTransactions')); + } + ); + + // ---------------------------------------------------------------- + // Wallet Transactions (company-wide read-only feed) + // ---------------------------------------------------------------- + $router->fleetbaseRoutes('wallet-transactions'); + + // ---------------------------------------------------------------- + // Transactions (core-api Transaction records — read-only) + // ---------------------------------------------------------------- + $router->fleetbaseRoutes('transactions'); + + // ---------------------------------------------------------------- + // Payment Gateways + // ---------------------------------------------------------------- + // The 'drivers' static route must be registered BEFORE fleetbaseRoutes + // to avoid being swallowed by the /{id} find route. + $router->get('gateways/drivers', 'GatewayController@drivers'); + + $router->fleetbaseRoutes( + 'gateways', + function ($router, $controller) { + $router->post('{id}/charge', $controller('charge')); + $router->post('{id}/refund', $controller('refund')); + $router->post('{id}/setup-intent', $controller('setupIntent')); + $router->get('{id}/transactions', $controller('transactions')); + } + ); + + // ---------------------------------------------------------------- + // Reports & Financial Statements + // ---------------------------------------------------------------- + $router->get('reports/dashboard', 'ReportController@dashboard'); + $router->get('reports/trial-balance', 'ReportController@trialBalance'); + $router->get('reports/balance-sheet', 'ReportController@balanceSheet'); + $router->get('reports/income-statement', 'ReportController@incomeStatement'); + $router->get('reports/cash-flow', 'ReportController@cashFlow'); + $router->get('reports/ar-aging', 'ReportController@arAging'); + $router->get('reports/wallet-summary', 'ReportController@walletSummary'); + } + ); } ); } From d5cfb7e990155eb8872b535486168b85fe9e5126 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 03:27:33 -0500 Subject: [PATCH 018/209] Fix: extend core-api Transaction model in Ledger; remove findRecord override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Fleetbase\Ledger\Models\Transaction extending core-api Transaction with a journal() hasOne relationship — journal data is now available on the model itself, no controller override needed - Add TransactionFilter with queryForInternal() eager-loading journal entries - Update Transaction resource to use whenLoaded('journal') for clean serialization - Simplify TransactionController to a pure LedgerController stub (no overrides) - Update Journal model to reference Fleetbase\Ledger\Models\Transaction instead of the core-api Transaction so the inverse relationship resolves correctly Fixes: Declaration of findRecord() must be compatible with FleetbaseController --- .../Internal/v1/TransactionController.php | 47 ++------------ server/src/Http/Filter/TransactionFilter.php | 64 +++++++++++++++++++ server/src/Http/Resources/v1/Transaction.php | 5 +- server/src/Models/Journal.php | 2 +- server/src/Models/Transaction.php | 24 +++++++ 5 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 server/src/Http/Filter/TransactionFilter.php create mode 100644 server/src/Models/Transaction.php diff --git a/server/src/Http/Controllers/Internal/v1/TransactionController.php b/server/src/Http/Controllers/Internal/v1/TransactionController.php index 3095d7e..a6f9e8e 100644 --- a/server/src/Http/Controllers/Internal/v1/TransactionController.php +++ b/server/src/Http/Controllers/Internal/v1/TransactionController.php @@ -3,17 +3,15 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; use Fleetbase\Ledger\Http\Controllers\LedgerController; -use Fleetbase\Ledger\Http\Resources\v1\Transaction as TransactionResource; -use Fleetbase\Ledger\Models\Journal; -use Fleetbase\Models\Transaction; -use Illuminate\Http\Request; /** * TransactionController. * - * Read-only view of core-api Transaction records scoped to the authenticated - * company. The findRecord() method is overridden to append the related journal - * entry when present. + * Read-only view of Ledger Transaction records (which extend the core-api + * Transaction model with a journal relationship). All CRUD and filtering is + * handled by HasApiControllerBehavior via LedgerController. The TransactionFilter + * applies company scoping. The Transaction resource includes the journal + * relationship via whenLoaded(). */ class TransactionController extends LedgerController { @@ -23,39 +21,4 @@ class TransactionController extends LedgerController * @var string */ public $resource = 'transaction'; - - /** - * Find a single transaction and append its journal entry if one exists. - */ - public function findRecord(string $id, Request $request) - { - $transaction = Transaction::where('company_uuid', session('company')) - ->with(['customer', 'items']) - ->where(fn ($q) => $q->where('uuid', $id) - ->orWhere('public_id', $id) - ->orWhere('gateway_transaction_id', $id)) - ->firstOrFail(); - - $journal = Journal::where('transaction_uuid', $transaction->uuid) - ->with(['debitAccount', 'creditAccount']) - ->first(); - - $data = (new TransactionResource($transaction))->toArray($request); - - if ($journal) { - $data['journal'] = [ - 'uuid' => $journal->uuid, - 'debit_account_uuid' => $journal->debit_account_uuid, - 'credit_account_uuid' => $journal->credit_account_uuid, - 'amount' => $journal->amount, - 'currency' => $journal->currency, - 'description' => $journal->description, - 'date' => $journal->date, - 'debit_account' => $journal->debitAccount, - 'credit_account' => $journal->creditAccount, - ]; - } - - return response()->json($data); - } } diff --git a/server/src/Http/Filter/TransactionFilter.php b/server/src/Http/Filter/TransactionFilter.php new file mode 100644 index 0000000..b873e65 --- /dev/null +++ b/server/src/Http/Filter/TransactionFilter.php @@ -0,0 +1,64 @@ +builder + ->where('company_uuid', $this->session->get('company')) + ->with(['journal.debitAccount', 'journal.creditAccount']); + } + + public function queryForPublic(): void + { + $this->builder->where('company_uuid', $this->session->get('company')); + } + + public function query(?string $searchQuery): void + { + $this->builder->where(function ($q) use ($searchQuery) { + $q->where('gateway_transaction_id', 'like', "%{$searchQuery}%") + ->orWhere('public_id', 'like', "%{$searchQuery}%") + ->orWhere('description', 'like', "%{$searchQuery}%"); + }); + } + + public function type(?string $type): void + { + $this->builder->where('type', $type); + } + + public function status(?string $status): void + { + $this->builder->where('status', $status); + } + + public function gateway(?string $gateway): void + { + $this->builder->where('gateway', $gateway); + } + + public function customer(?string $customer): void + { + $this->builder->where('customer_uuid', $customer); + } + + public function publicId(?string $publicId): void + { + $this->builder->searchWhere('public_id', $publicId); + } + + public function createdAt($createdAt): void + { + $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); + if (is_array($createdAt)) { + $this->builder->whereBetween('created_at', $createdAt); + } else { + $this->builder->whereDate('created_at', $createdAt); + } + } +} diff --git a/server/src/Http/Resources/v1/Transaction.php b/server/src/Http/Resources/v1/Transaction.php index feb4e21..1edac5f 100644 --- a/server/src/Http/Resources/v1/Transaction.php +++ b/server/src/Http/Resources/v1/Transaction.php @@ -8,8 +8,8 @@ /** * Transaction Resource. * - * Serializes the core-api Transaction model for Ledger API responses. - * This is a read-only view — Ledger does not create or mutate Transaction records directly. + * Serializes the Ledger Transaction model (which extends the core-api Transaction) + * for Ledger API responses. The journal relationship is included when loaded. */ class Transaction extends FleetbaseResource { @@ -40,6 +40,7 @@ public function toArray($request): array 'type' => $this->type, 'status' => $this->status, 'meta' => $this->meta, + 'journal' => $this->whenLoaded('journal', fn () => new Journal($this->journal)), 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; diff --git a/server/src/Models/Journal.php b/server/src/Models/Journal.php index 97f6343..eead600 100644 --- a/server/src/Models/Journal.php +++ b/server/src/Models/Journal.php @@ -4,7 +4,7 @@ use Fleetbase\Casts\Json; use Fleetbase\Models\Model; -use Fleetbase\Models\Transaction; +use Fleetbase\Ledger\Models\Transaction; use Fleetbase\Traits\HasApiModelBehavior; use Fleetbase\Traits\HasMetaAttributes; use Fleetbase\Traits\HasPublicId; diff --git a/server/src/Models/Transaction.php b/server/src/Models/Transaction.php new file mode 100644 index 0000000..511036d --- /dev/null +++ b/server/src/Models/Transaction.php @@ -0,0 +1,24 @@ +hasOne(Journal::class, 'transaction_uuid', 'uuid'); + } +} From 5c7b7b209354fb52fd6120c29a336903f8de3ff9 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 09:57:09 -0500 Subject: [PATCH 019/209] Fix: remove duplicate unique index declarations from all migrations Every migration declared ->unique() inline on the uuid/public_id column AND then repeated $table->unique(['uuid']) as a standalone call at the bottom of the same Schema::create block. MySQL creates the index on the first declaration and then throws: SQLSTATE[42000]: Duplicate key name 'ledger_accounts_uuid_unique' when the second call tries to add an identical index. Removed the redundant standalone $table->unique(['uuid']) lines from: - 2024_01_01_000001_create_ledger_accounts_table - 2024_01_01_000002_create_ledger_journals_table - 2024_01_01_000003_create_ledger_invoices_table - 2024_01_01_000004_create_ledger_invoice_items_table - 2024_01_01_000005_create_ledger_wallets_table - 2024_01_01_000007_create_ledger_gateways_table - 2024_01_01_000008_create_ledger_gateway_transactions_table Also removed redundant ->index() chained after ->unique() on public_id columns (a UNIQUE constraint already implies an index in MySQL). --- .../2024_01_01_000001_create_ledger_accounts_table.php | 1 - .../2024_01_01_000002_create_ledger_journals_table.php | 1 - .../2024_01_01_000003_create_ledger_invoices_table.php | 1 - .../2024_01_01_000004_create_ledger_invoice_items_table.php | 1 - .../2024_01_01_000005_create_ledger_wallets_table.php | 1 - .../2024_01_01_000007_create_ledger_gateways_table.php | 2 +- ...24_01_01_000008_create_ledger_gateway_transactions_table.php | 2 +- 7 files changed, 2 insertions(+), 7 deletions(-) diff --git a/server/migrations/2024_01_01_000001_create_ledger_accounts_table.php b/server/migrations/2024_01_01_000001_create_ledger_accounts_table.php index 7ad10d5..059ba00 100644 --- a/server/migrations/2024_01_01_000001_create_ledger_accounts_table.php +++ b/server/migrations/2024_01_01_000001_create_ledger_accounts_table.php @@ -34,7 +34,6 @@ public function up() $table->timestamp('created_at')->nullable()->index(); $table->timestamp('updated_at')->nullable(); - $table->unique(['uuid']); $table->unique(['company_uuid', 'code']); }); } diff --git a/server/migrations/2024_01_01_000002_create_ledger_journals_table.php b/server/migrations/2024_01_01_000002_create_ledger_journals_table.php index 0b31db9..6ef9da5 100644 --- a/server/migrations/2024_01_01_000002_create_ledger_journals_table.php +++ b/server/migrations/2024_01_01_000002_create_ledger_journals_table.php @@ -29,7 +29,6 @@ public function up() $table->timestamp('created_at')->nullable()->index(); $table->timestamp('updated_at')->nullable(); - $table->unique(['uuid']); }); } diff --git a/server/migrations/2024_01_01_000003_create_ledger_invoices_table.php b/server/migrations/2024_01_01_000003_create_ledger_invoices_table.php index 9830463..8133b52 100644 --- a/server/migrations/2024_01_01_000003_create_ledger_invoices_table.php +++ b/server/migrations/2024_01_01_000003_create_ledger_invoices_table.php @@ -45,7 +45,6 @@ public function up() $table->timestamp('viewed_at')->nullable(); $table->timestamp('paid_at')->nullable(); - $table->unique(['uuid']); }); } diff --git a/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php b/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php index 4a1c1e3..30cda90 100644 --- a/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php +++ b/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php @@ -28,7 +28,6 @@ public function up() $table->timestamp('created_at')->nullable()->index(); $table->timestamp('updated_at')->nullable(); - $table->unique(['uuid']); }); } diff --git a/server/migrations/2024_01_01_000005_create_ledger_wallets_table.php b/server/migrations/2024_01_01_000005_create_ledger_wallets_table.php index 27b378b..d43bbbf 100644 --- a/server/migrations/2024_01_01_000005_create_ledger_wallets_table.php +++ b/server/migrations/2024_01_01_000005_create_ledger_wallets_table.php @@ -31,7 +31,6 @@ public function up() $table->timestamp('created_at')->nullable()->index(); $table->timestamp('updated_at')->nullable(); - $table->unique(['uuid']); $table->unique(['subject_uuid', 'subject_type']); }); } diff --git a/server/migrations/2024_01_01_000007_create_ledger_gateways_table.php b/server/migrations/2024_01_01_000007_create_ledger_gateways_table.php index 13bc9d9..1be1b4c 100644 --- a/server/migrations/2024_01_01_000007_create_ledger_gateways_table.php +++ b/server/migrations/2024_01_01_000007_create_ledger_gateways_table.php @@ -18,7 +18,7 @@ public function up(): void Schema::create('ledger_gateways', function (Blueprint $table) { $table->bigIncrements('id'); $table->char('uuid', 36)->unique(); - $table->string('public_id', 191)->nullable()->unique()->index(); + $table->string('public_id', 191)->nullable()->unique(); $table->char('company_uuid', 36)->nullable()->index(); $table->char('created_by_uuid', 36)->nullable()->index(); diff --git a/server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php b/server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php index 89955ec..92eaf25 100644 --- a/server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php +++ b/server/migrations/2024_01_01_000008_create_ledger_gateway_transactions_table.php @@ -25,7 +25,7 @@ public function up(): void Schema::create('ledger_gateway_transactions', function (Blueprint $table) { $table->bigIncrements('id'); $table->char('uuid', 36)->unique(); - $table->string('public_id', 191)->nullable()->unique()->index(); + $table->string('public_id', 191)->nullable()->unique(); $table->char('company_uuid', 36)->nullable()->index(); // Relations From 52b2f1d8e1766b8c0fbc0b657bb7a484e587b2cd Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 10:01:07 -0500 Subject: [PATCH 020/209] Fix: add softDeletes to all ledger tables and models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrations missing softDeletes() (deleted_at column): - ledger_journals — caused 'Unknown column deleted_at' when eager-loading journal entries via the Transaction -> journal() hasOne relationship - ledger_invoice_items Models missing SoftDeletes trait (import + use): - Gateway - GatewayTransaction - InvoiceItem - Journal Fleetbase\Ledger\Models\Transaction extends BaseTransaction which already uses SoftDeletes via the core-api model — no change needed there. --- .../2024_01_01_000002_create_ledger_journals_table.php | 1 + .../2024_01_01_000004_create_ledger_invoice_items_table.php | 1 + server/src/Models/Gateway.php | 2 ++ server/src/Models/GatewayTransaction.php | 2 ++ server/src/Models/InvoiceItem.php | 2 ++ server/src/Models/Journal.php | 2 ++ 6 files changed, 10 insertions(+) diff --git a/server/migrations/2024_01_01_000002_create_ledger_journals_table.php b/server/migrations/2024_01_01_000002_create_ledger_journals_table.php index 6ef9da5..375f555 100644 --- a/server/migrations/2024_01_01_000002_create_ledger_journals_table.php +++ b/server/migrations/2024_01_01_000002_create_ledger_journals_table.php @@ -26,6 +26,7 @@ public function up() $table->text('description')->nullable(); $table->date('date')->index(); $table->json('meta')->nullable(); + $table->softDeletes(); $table->timestamp('created_at')->nullable()->index(); $table->timestamp('updated_at')->nullable(); diff --git a/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php b/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php index 30cda90..382ff69 100644 --- a/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php +++ b/server/migrations/2024_01_01_000004_create_ledger_invoice_items_table.php @@ -25,6 +25,7 @@ public function up() $table->decimal('tax_rate', 5, 2)->default(0.00); // percentage $table->integer('tax_amount')->default(0); // stored in cents $table->json('meta')->nullable(); + $table->softDeletes(); $table->timestamp('created_at')->nullable()->index(); $table->timestamp('updated_at')->nullable(); diff --git a/server/src/Models/Gateway.php b/server/src/Models/Gateway.php index 9ee69b3..0afdd93 100644 --- a/server/src/Models/Gateway.php +++ b/server/src/Models/Gateway.php @@ -6,6 +6,7 @@ use Fleetbase\Traits\HasApiModelBehavior; use Fleetbase\Traits\HasPublicId; use Fleetbase\Traits\HasUuid; +use Illuminate\Database\Eloquent\SoftDeletes; /** * Gateway Model. @@ -32,6 +33,7 @@ class Gateway extends Model use HasUuid; use HasPublicId; use HasApiModelBehavior; + use SoftDeletes; /** * The database table used by the model. diff --git a/server/src/Models/GatewayTransaction.php b/server/src/Models/GatewayTransaction.php index c17d041..ef0f8e5 100644 --- a/server/src/Models/GatewayTransaction.php +++ b/server/src/Models/GatewayTransaction.php @@ -6,6 +6,7 @@ use Fleetbase\Traits\HasApiModelBehavior; use Fleetbase\Traits\HasPublicId; use Fleetbase\Traits\HasUuid; +use Illuminate\Database\Eloquent\SoftDeletes; /** * GatewayTransaction Model. @@ -37,6 +38,7 @@ class GatewayTransaction extends Model use HasUuid; use HasPublicId; use HasApiModelBehavior; + use SoftDeletes; /** * The database table used by the model. diff --git a/server/src/Models/InvoiceItem.php b/server/src/Models/InvoiceItem.php index 70d20f9..054453b 100644 --- a/server/src/Models/InvoiceItem.php +++ b/server/src/Models/InvoiceItem.php @@ -6,11 +6,13 @@ use Fleetbase\Models\Model; use Fleetbase\Traits\HasMetaAttributes; use Fleetbase\Traits\HasUuid; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; class InvoiceItem extends Model { use HasUuid; + use SoftDeletes; use HasMetaAttributes; /** diff --git a/server/src/Models/Journal.php b/server/src/Models/Journal.php index eead600..86c8e61 100644 --- a/server/src/Models/Journal.php +++ b/server/src/Models/Journal.php @@ -10,6 +10,7 @@ use Fleetbase\Traits\HasPublicId; use Fleetbase\Traits\HasUuid; use Fleetbase\Traits\TracksApiCredential; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Journal extends Model @@ -19,6 +20,7 @@ class Journal extends Model use HasApiModelBehavior; use HasMetaAttributes; use TracksApiCredential; + use SoftDeletes; /** * The prefix used when auto-generating public IDs for journal entries. From e6d271b51d390009f8b94ec2484d44ffc44e246c Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 19:23:39 -0500 Subject: [PATCH 021/209] Refactor: prefix all Ember models/adapters with ledger-, add serializer layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Models renamed (prevents collision with core-api models in Ember Data store): account -> ledger-account invoice -> ledger-invoice journal -> ledger-journal wallet -> ledger-wallet wallet-transaction -> ledger-wallet-transaction gateway -> ledger-gateway transaction -> ledger-transaction Adapters renamed to match (all still re-export from adapters/ledger.js base). Base adapter (adapters/ledger.js): - Add pathForType(modelName) that strips 'ledger-' prefix before pluralizing so 'ledger-account' -> GET /ledger/int/v1/accounts (not /ledger-accounts) New serializer layer (serializers/): - serializers/ledger.js — base LedgerSerializer extending ApplicationSerializer with EmbeddedRecordsMixin (classic extend() required for mixin compat) - modelNameFromPayloadKey: prepends 'ledger-' so payload 'account' resolves to the Ledger model, not any core-api model with the same name - payloadKeyFromModelName: strips 'ledger_' prefix and lowercases so 'ledger-wallet-transaction' -> 'wallet_transaction' in request payloads - Per-model stubs (serializers/ledger-*.js) re-export the base serializer All store.query/findRecord/createRecord calls updated to use prefixed names. --- .../{account.js => ledger-account.js} | 0 .../{gateway.js => ledger-gateway.js} | 0 .../{invoice.js => ledger-invoice.js} | 0 .../{journal.js => ledger-journal.js} | 0 .../{transaction.js => ledger-transaction.js} | 0 ...action.js => ledger-wallet-transaction.js} | 0 .../adapters/{wallet.js => ledger-wallet.js} | 0 addon/adapters/ledger.js | 10 ++++++ .../models/{account.js => ledger-account.js} | 0 .../models/{gateway.js => ledger-gateway.js} | 0 .../models/{invoice.js => ledger-invoice.js} | 0 .../models/{journal.js => ledger-journal.js} | 0 .../{transaction.js => ledger-transaction.js} | 0 ...action.js => ledger-wallet-transaction.js} | 0 addon/models/{wallet.js => ledger-wallet.js} | 0 addon/serializers/ledger-account.js | 1 + addon/serializers/ledger-gateway.js | 1 + addon/serializers/ledger-invoice.js | 1 + addon/serializers/ledger-journal.js | 1 + addon/serializers/ledger-transaction.js | 1 + .../serializers/ledger-wallet-transaction.js | 1 + addon/serializers/ledger-wallet.js | 1 + addon/serializers/ledger.js | 36 +++++++++++++++++++ 23 files changed, 53 insertions(+) rename addon/adapters/{account.js => ledger-account.js} (100%) rename addon/adapters/{gateway.js => ledger-gateway.js} (100%) rename addon/adapters/{invoice.js => ledger-invoice.js} (100%) rename addon/adapters/{journal.js => ledger-journal.js} (100%) rename addon/adapters/{transaction.js => ledger-transaction.js} (100%) rename addon/adapters/{wallet-transaction.js => ledger-wallet-transaction.js} (100%) rename addon/adapters/{wallet.js => ledger-wallet.js} (100%) rename addon/models/{account.js => ledger-account.js} (100%) rename addon/models/{gateway.js => ledger-gateway.js} (100%) rename addon/models/{invoice.js => ledger-invoice.js} (100%) rename addon/models/{journal.js => ledger-journal.js} (100%) rename addon/models/{transaction.js => ledger-transaction.js} (100%) rename addon/models/{wallet-transaction.js => ledger-wallet-transaction.js} (100%) rename addon/models/{wallet.js => ledger-wallet.js} (100%) create mode 100644 addon/serializers/ledger-account.js create mode 100644 addon/serializers/ledger-gateway.js create mode 100644 addon/serializers/ledger-invoice.js create mode 100644 addon/serializers/ledger-journal.js create mode 100644 addon/serializers/ledger-transaction.js create mode 100644 addon/serializers/ledger-wallet-transaction.js create mode 100644 addon/serializers/ledger-wallet.js create mode 100644 addon/serializers/ledger.js diff --git a/addon/adapters/account.js b/addon/adapters/ledger-account.js similarity index 100% rename from addon/adapters/account.js rename to addon/adapters/ledger-account.js diff --git a/addon/adapters/gateway.js b/addon/adapters/ledger-gateway.js similarity index 100% rename from addon/adapters/gateway.js rename to addon/adapters/ledger-gateway.js diff --git a/addon/adapters/invoice.js b/addon/adapters/ledger-invoice.js similarity index 100% rename from addon/adapters/invoice.js rename to addon/adapters/ledger-invoice.js diff --git a/addon/adapters/journal.js b/addon/adapters/ledger-journal.js similarity index 100% rename from addon/adapters/journal.js rename to addon/adapters/ledger-journal.js diff --git a/addon/adapters/transaction.js b/addon/adapters/ledger-transaction.js similarity index 100% rename from addon/adapters/transaction.js rename to addon/adapters/ledger-transaction.js diff --git a/addon/adapters/wallet-transaction.js b/addon/adapters/ledger-wallet-transaction.js similarity index 100% rename from addon/adapters/wallet-transaction.js rename to addon/adapters/ledger-wallet-transaction.js diff --git a/addon/adapters/wallet.js b/addon/adapters/ledger-wallet.js similarity index 100% rename from addon/adapters/wallet.js rename to addon/adapters/ledger-wallet.js diff --git a/addon/adapters/ledger.js b/addon/adapters/ledger.js index 3d28e83..19f8c1a 100644 --- a/addon/adapters/ledger.js +++ b/addon/adapters/ledger.js @@ -1,5 +1,15 @@ import ApplicationAdapter from '@fleetbase/ember-core/adapters/application'; +import { pluralize } from 'ember-inflector'; +import { dasherize } from '@ember/string'; export default class LedgerAdapter extends ApplicationAdapter { namespace = 'ledger/int/v1'; + + /** + * Strip the 'ledger-' prefix from the model name before building the URL path. + * e.g. 'ledger-account' -> 'accounts', 'ledger-wallet-transaction' -> 'wallet-transactions' + */ + pathForType(modelName) { + return pluralize(dasherize(modelName)).replace('ledger-', ''); + } } diff --git a/addon/models/account.js b/addon/models/ledger-account.js similarity index 100% rename from addon/models/account.js rename to addon/models/ledger-account.js diff --git a/addon/models/gateway.js b/addon/models/ledger-gateway.js similarity index 100% rename from addon/models/gateway.js rename to addon/models/ledger-gateway.js diff --git a/addon/models/invoice.js b/addon/models/ledger-invoice.js similarity index 100% rename from addon/models/invoice.js rename to addon/models/ledger-invoice.js diff --git a/addon/models/journal.js b/addon/models/ledger-journal.js similarity index 100% rename from addon/models/journal.js rename to addon/models/ledger-journal.js diff --git a/addon/models/transaction.js b/addon/models/ledger-transaction.js similarity index 100% rename from addon/models/transaction.js rename to addon/models/ledger-transaction.js diff --git a/addon/models/wallet-transaction.js b/addon/models/ledger-wallet-transaction.js similarity index 100% rename from addon/models/wallet-transaction.js rename to addon/models/ledger-wallet-transaction.js diff --git a/addon/models/wallet.js b/addon/models/ledger-wallet.js similarity index 100% rename from addon/models/wallet.js rename to addon/models/ledger-wallet.js diff --git a/addon/serializers/ledger-account.js b/addon/serializers/ledger-account.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/serializers/ledger-account.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/serializers/ledger-gateway.js b/addon/serializers/ledger-gateway.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/serializers/ledger-gateway.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/serializers/ledger-invoice.js b/addon/serializers/ledger-invoice.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/serializers/ledger-invoice.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/serializers/ledger-journal.js b/addon/serializers/ledger-journal.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/serializers/ledger-journal.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/serializers/ledger-transaction.js b/addon/serializers/ledger-transaction.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/serializers/ledger-transaction.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/serializers/ledger-wallet-transaction.js b/addon/serializers/ledger-wallet-transaction.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/serializers/ledger-wallet-transaction.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/serializers/ledger-wallet.js b/addon/serializers/ledger-wallet.js new file mode 100644 index 0000000..35354ab --- /dev/null +++ b/addon/serializers/ledger-wallet.js @@ -0,0 +1 @@ +export { default } from './ledger'; diff --git a/addon/serializers/ledger.js b/addon/serializers/ledger.js new file mode 100644 index 0000000..a9bbb3d --- /dev/null +++ b/addon/serializers/ledger.js @@ -0,0 +1,36 @@ +import ApplicationSerializer from '@fleetbase/ember-core/serializers/application'; +import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest'; +import { underscore } from '@ember/string'; + +// EmbeddedRecordsMixin must be applied via classic extend() syntax +const LedgerSerializerBase = ApplicationSerializer.extend(EmbeddedRecordsMixin); + +/** + * Base serializer for all Ledger models. + * + * Handles the bidirectional mapping between the `ledger-` prefixed Ember model + * names and the unprefixed snake_case payload keys the backend returns. + * + * Payload key -> Ember model name: 'account' -> 'ledger-account' + * Ember model name -> payload key: 'ledger-account' -> 'account' + * 'ledger-wallet-transaction' -> 'wallet_transaction' + */ +export default class LedgerSerializer extends LedgerSerializerBase { + /** + * Called when Ember Data receives a payload and needs to determine which + * model class to use. Prepend 'ledger-' so it resolves to our prefixed models. + */ + modelNameFromPayloadKey(key) { + const modelName = super.modelNameFromPayloadKey(key); + return `ledger-${modelName}`; + } + + /** + * Called when Ember Data builds a request payload and needs to know what + * key to use for the model. Strip the 'ledger-' prefix and convert to + * snake_case to match what the backend expects. + */ + payloadKeyFromModelName(modelName) { + return underscore(modelName).replace(/^ledger_/, '').toLowerCase(); + } +} From 66ee35910908f10b82e9216a1e6270966c5d3cf6 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 19:23:45 -0500 Subject: [PATCH 022/209] Fix: update all store.query/findRecord/createRecord to use ledger- prefixed model names --- addon/controllers/settings/gateways/index.js | 2 +- addon/routes/accounting/accounts/index.js | 2 +- addon/routes/accounting/accounts/index/details.js | 2 +- addon/routes/accounting/journal/index.js | 2 +- addon/routes/accounting/journal/index/details.js | 2 +- addon/routes/billing/invoices/index.js | 2 +- addon/routes/billing/invoices/index/details.js | 2 +- addon/routes/billing/transactions/index.js | 2 +- addon/routes/billing/transactions/index/details.js | 2 +- addon/routes/settings/gateways/index.js | 2 +- addon/routes/settings/gateways/index/details.js | 2 +- addon/routes/wallets/index.js | 2 +- addon/routes/wallets/index/details.js | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/addon/controllers/settings/gateways/index.js b/addon/controllers/settings/gateways/index.js index 8d0e62e..039db5d 100644 --- a/addon/controllers/settings/gateways/index.js +++ b/addon/controllers/settings/gateways/index.js @@ -50,7 +50,7 @@ export default class SettingsGatewaysIndexController extends Controller { modal.startLoading(); try { const gateway = modal.getOption('gateway'); - const record = this.store.createRecord('gateway', gateway); + const record = this.store.createRecord('ledger-gateway', gateway); await record.save(); this.notifications.success('Gateway added.'); this.hostRouter.refresh(); diff --git a/addon/routes/accounting/accounts/index.js b/addon/routes/accounting/accounts/index.js index 72440ca..b7ffb49 100644 --- a/addon/routes/accounting/accounts/index.js +++ b/addon/routes/accounting/accounts/index.js @@ -13,6 +13,6 @@ export default class AccountingAccountsIndexRoute extends Route { }; model(params) { - return this.store.query('account', params); + return this.store.query('ledger-account', params); } } diff --git a/addon/routes/accounting/accounts/index/details.js b/addon/routes/accounting/accounts/index/details.js index d80f3ae..1eaa39d 100644 --- a/addon/routes/accounting/accounts/index/details.js +++ b/addon/routes/accounting/accounts/index/details.js @@ -5,6 +5,6 @@ export default class AccountingAccountsIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('account', id); + return this.store.findRecord('ledger-account', id); } } diff --git a/addon/routes/accounting/journal/index.js b/addon/routes/accounting/journal/index.js index fba9524..4c2bb56 100644 --- a/addon/routes/accounting/journal/index.js +++ b/addon/routes/accounting/journal/index.js @@ -13,6 +13,6 @@ export default class AccountingJournalIndexRoute extends Route { }; model(params) { - return this.store.query('journal', params); + return this.store.query('ledger-journal', params); } } diff --git a/addon/routes/accounting/journal/index/details.js b/addon/routes/accounting/journal/index/details.js index b6b130d..eda25cf 100644 --- a/addon/routes/accounting/journal/index/details.js +++ b/addon/routes/accounting/journal/index/details.js @@ -5,6 +5,6 @@ export default class AccountingJournalIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('journal', id); + return this.store.findRecord('ledger-journal', id); } } diff --git a/addon/routes/billing/invoices/index.js b/addon/routes/billing/invoices/index.js index e744804..b22d3cc 100644 --- a/addon/routes/billing/invoices/index.js +++ b/addon/routes/billing/invoices/index.js @@ -13,6 +13,6 @@ export default class BillingInvoicesIndexRoute extends Route { }; model(params) { - return this.store.query('invoice', params); + return this.store.query('ledger-invoice', params); } } diff --git a/addon/routes/billing/invoices/index/details.js b/addon/routes/billing/invoices/index/details.js index c76bdda..b234ff0 100644 --- a/addon/routes/billing/invoices/index/details.js +++ b/addon/routes/billing/invoices/index/details.js @@ -5,6 +5,6 @@ export default class BillingInvoicesIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('invoice', id); + return this.store.findRecord('ledger-invoice', id); } } diff --git a/addon/routes/billing/transactions/index.js b/addon/routes/billing/transactions/index.js index d60d443..50781e9 100644 --- a/addon/routes/billing/transactions/index.js +++ b/addon/routes/billing/transactions/index.js @@ -13,6 +13,6 @@ export default class BillingTransactionsIndexRoute extends Route { }; model(params) { - return this.store.query('transaction', params); + return this.store.query('ledger-transaction', params); } } diff --git a/addon/routes/billing/transactions/index/details.js b/addon/routes/billing/transactions/index/details.js index cd9431c..03321df 100644 --- a/addon/routes/billing/transactions/index/details.js +++ b/addon/routes/billing/transactions/index/details.js @@ -5,6 +5,6 @@ export default class BillingTransactionsIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('transaction', id); + return this.store.findRecord('ledger-transaction', id); } } diff --git a/addon/routes/settings/gateways/index.js b/addon/routes/settings/gateways/index.js index 880fee2..b41ccc0 100644 --- a/addon/routes/settings/gateways/index.js +++ b/addon/routes/settings/gateways/index.js @@ -5,6 +5,6 @@ export default class SettingsGatewaysIndexRoute extends Route { @service store; model() { - return this.store.query('gateway'); + return this.store.query('ledger-gateway'); } } diff --git a/addon/routes/settings/gateways/index/details.js b/addon/routes/settings/gateways/index/details.js index ef53bc9..d723e63 100644 --- a/addon/routes/settings/gateways/index/details.js +++ b/addon/routes/settings/gateways/index/details.js @@ -5,6 +5,6 @@ export default class SettingsGatewaysIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('gateway', id); + return this.store.findRecord('ledger-gateway', id); } } diff --git a/addon/routes/wallets/index.js b/addon/routes/wallets/index.js index 6c64b57..be121a5 100644 --- a/addon/routes/wallets/index.js +++ b/addon/routes/wallets/index.js @@ -13,6 +13,6 @@ export default class WalletsIndexRoute extends Route { }; model(params) { - return this.store.query('wallet', params); + return this.store.query('ledger-wallet', params); } } diff --git a/addon/routes/wallets/index/details.js b/addon/routes/wallets/index/details.js index 6f5ae1c..62b4e96 100644 --- a/addon/routes/wallets/index/details.js +++ b/addon/routes/wallets/index/details.js @@ -5,6 +5,6 @@ export default class WalletsIndexDetailsRoute extends Route { @service store; model({ id }) { - return this.store.findRecord('wallet', id); + return this.store.findRecord('ledger-wallet', id); } } From 19c7984a0139449d0e0711bf67242f718065f4b1 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 20:22:16 -0500 Subject: [PATCH 023/209] refactor: restructure navigation to Receivables/Payments/Accounting/Reports/Settings Navigation changes: - Dashboard is now a standalone sidebar item (no panel wrapper) - 'Billing' renamed to 'Receivables' (Invoices only) - New 'Payments' panel: Transactions, Wallets, Gateways - billing/transactions -> payments/transactions - wallets -> payments/wallets - settings/gateways -> payments/gateways - 'Accounting' adds General Ledger item - 'Reports' expands to 6 individual report routes (Income Statement, Balance Sheet, Trial Balance, Cash Flow, AR Aging, Wallet Summary) - 'Settings' expands to 3 sub-sections (Invoice Settings, Payment Settings, Accounting Settings) App re-exports: - Removed old unprefixed app/models/*.js re-exports - Created ledger- prefixed re-exports for all 7 models, adapters, serializers - Created app/serializers/ directory with all 8 re-exports (7 models + base) Route/template/controller files reorganised to match new structure. --- addon/routes.js | 58 +++++++++++-------- addon/templates/accounting/general-ledger.hbs | 4 ++ addon/templates/application.hbs | 35 +++++++---- .../{settings => payments}/gateways.hbs | 0 .../{settings => payments}/gateways/index.hbs | 0 .../gateways/index/details.hbs | 2 +- .../gateways/index/details/index.hbs | 0 .../gateways/index/details/webhooks.hbs | 0 .../{billing => payments}/transactions.hbs | 0 .../transactions/index.hbs | 0 .../transactions/index/details.hbs | 2 +- .../transactions/index/details/index.hbs | 0 addon/templates/{ => payments}/wallets.hbs | 0 .../{ => payments}/wallets/index.hbs | 0 .../{ => payments}/wallets/index/details.hbs | 2 +- .../wallets/index/details/index.hbs | 0 .../wallets/index/details/transactions.hbs | 0 .../{billing => receivables}/invoices.hbs | 0 .../invoices/index.hbs | 0 .../invoices/index/details.hbs | 2 +- .../invoices/index/details/index.hbs | 0 .../invoices/index/details/line-items.hbs | 0 .../invoices/index/details/transactions.hbs | 0 addon/templates/reports/ar-aging.hbs | 4 ++ addon/templates/reports/balance-sheet.hbs | 4 ++ addon/templates/reports/cash-flow.hbs | 4 ++ addon/templates/reports/income-statement.hbs | 4 ++ addon/templates/reports/trial-balance.hbs | 4 ++ addon/templates/reports/wallet-summary.hbs | 4 ++ addon/templates/settings/accounting.hbs | 4 ++ addon/templates/settings/invoice.hbs | 4 ++ addon/templates/settings/payment.hbs | 4 ++ app/adapters/account.js | 1 - app/adapters/gateway.js | 1 - app/adapters/invoice.js | 1 - app/adapters/journal.js | 1 - app/adapters/ledger-account.js | 1 + app/adapters/ledger-gateway.js | 1 + app/adapters/ledger-invoice.js | 1 + app/adapters/ledger-journal.js | 1 + app/adapters/ledger-transaction.js | 1 + app/adapters/ledger-wallet-transaction.js | 1 + app/adapters/ledger-wallet.js | 1 + app/adapters/transaction.js | 1 - app/adapters/wallet-transaction.js | 1 - app/adapters/wallet.js | 1 - .../{settings => payments}/gateways/index.js | 0 .../gateways/index/details.js | 0 .../transactions/index.js | 0 .../transactions/index/details.js | 0 .../ledger/{ => payments}/wallets/index.js | 0 .../{ => payments}/wallets/index/details.js | 0 .../invoices/index.js | 0 .../invoices/index/details.js | 0 app/models/account.js | 1 - app/models/gateway.js | 1 - app/models/invoice.js | 1 - app/models/journal.js | 1 - app/models/ledger-account.js | 1 + app/models/ledger-gateway.js | 1 + app/models/ledger-invoice.js | 1 + app/models/ledger-journal.js | 1 + app/models/ledger-transaction.js | 1 + app/models/ledger-wallet-transaction.js | 1 + app/models/ledger-wallet.js | 1 + app/models/transaction.js | 1 - app/models/wallet-transaction.js | 1 - app/models/wallet.js | 1 - .../ledger/accounting/general-ledger.js | 1 + .../ledger/{settings => payments}/gateways.js | 0 .../{settings => payments}/gateways/index.js | 0 .../gateways/index/details.js | 0 .../gateways/index/details/index.js | 0 .../gateways/index/details/webhooks.js | 0 .../{billing => payments}/transactions.js | 0 .../transactions/index.js | 0 .../transactions/index/details.js | 0 .../transactions/index/details/index.js | 0 app/routes/ledger/{ => payments}/wallets.js | 0 .../ledger/{ => payments}/wallets/index.js | 0 .../{ => payments}/wallets/index/details.js | 0 .../wallets/index/details/index.js | 0 .../wallets/index/details/transactions.js | 0 .../{billing => receivables}/invoices.js | 0 .../invoices/index.js | 0 .../invoices/index/details.js | 0 .../invoices/index/details/index.js | 0 .../invoices/index/details/line-items.js | 0 .../invoices/index/details/transactions.js | 0 app/routes/ledger/reports/ar-aging.js | 1 + app/routes/ledger/reports/balance-sheet.js | 1 + app/routes/ledger/reports/cash-flow.js | 1 + app/routes/ledger/reports/income-statement.js | 1 + app/routes/ledger/reports/trial-balance.js | 1 + app/routes/ledger/reports/wallet-summary.js | 1 + app/routes/ledger/settings/accounting.js | 1 + app/routes/ledger/settings/invoice.js | 1 + app/routes/ledger/settings/payment.js | 1 + app/serializers/ledger-account.js | 1 + app/serializers/ledger-gateway.js | 1 + app/serializers/ledger-invoice.js | 1 + app/serializers/ledger-journal.js | 1 + app/serializers/ledger-transaction.js | 1 + app/serializers/ledger-wallet-transaction.js | 1 + app/serializers/ledger-wallet.js | 1 + app/serializers/ledger.js | 1 + 106 files changed, 133 insertions(+), 54 deletions(-) create mode 100644 addon/templates/accounting/general-ledger.hbs rename addon/templates/{settings => payments}/gateways.hbs (100%) rename addon/templates/{settings => payments}/gateways/index.hbs (100%) rename addon/templates/{settings => payments}/gateways/index/details.hbs (81%) rename addon/templates/{settings => payments}/gateways/index/details/index.hbs (100%) rename addon/templates/{settings => payments}/gateways/index/details/webhooks.hbs (100%) rename addon/templates/{billing => payments}/transactions.hbs (100%) rename addon/templates/{billing => payments}/transactions/index.hbs (100%) rename addon/templates/{billing => payments}/transactions/index/details.hbs (80%) rename addon/templates/{billing => payments}/transactions/index/details/index.hbs (100%) rename addon/templates/{ => payments}/wallets.hbs (100%) rename addon/templates/{ => payments}/wallets/index.hbs (100%) rename addon/templates/{ => payments}/wallets/index/details.hbs (81%) rename addon/templates/{ => payments}/wallets/index/details/index.hbs (100%) rename addon/templates/{ => payments}/wallets/index/details/transactions.hbs (100%) rename addon/templates/{billing => receivables}/invoices.hbs (100%) rename addon/templates/{billing => receivables}/invoices/index.hbs (100%) rename addon/templates/{billing => receivables}/invoices/index/details.hbs (81%) rename addon/templates/{billing => receivables}/invoices/index/details/index.hbs (100%) rename addon/templates/{billing => receivables}/invoices/index/details/line-items.hbs (100%) rename addon/templates/{billing => receivables}/invoices/index/details/transactions.hbs (100%) create mode 100644 addon/templates/reports/ar-aging.hbs create mode 100644 addon/templates/reports/balance-sheet.hbs create mode 100644 addon/templates/reports/cash-flow.hbs create mode 100644 addon/templates/reports/income-statement.hbs create mode 100644 addon/templates/reports/trial-balance.hbs create mode 100644 addon/templates/reports/wallet-summary.hbs create mode 100644 addon/templates/settings/accounting.hbs create mode 100644 addon/templates/settings/invoice.hbs create mode 100644 addon/templates/settings/payment.hbs delete mode 100644 app/adapters/account.js delete mode 100644 app/adapters/gateway.js delete mode 100644 app/adapters/invoice.js delete mode 100644 app/adapters/journal.js create mode 100644 app/adapters/ledger-account.js create mode 100644 app/adapters/ledger-gateway.js create mode 100644 app/adapters/ledger-invoice.js create mode 100644 app/adapters/ledger-journal.js create mode 100644 app/adapters/ledger-transaction.js create mode 100644 app/adapters/ledger-wallet-transaction.js create mode 100644 app/adapters/ledger-wallet.js delete mode 100644 app/adapters/transaction.js delete mode 100644 app/adapters/wallet-transaction.js delete mode 100644 app/adapters/wallet.js rename app/controllers/ledger/{settings => payments}/gateways/index.js (100%) rename app/controllers/ledger/{settings => payments}/gateways/index/details.js (100%) rename app/controllers/ledger/{billing => payments}/transactions/index.js (100%) rename app/controllers/ledger/{billing => payments}/transactions/index/details.js (100%) rename app/controllers/ledger/{ => payments}/wallets/index.js (100%) rename app/controllers/ledger/{ => payments}/wallets/index/details.js (100%) rename app/controllers/ledger/{billing => receivables}/invoices/index.js (100%) rename app/controllers/ledger/{billing => receivables}/invoices/index/details.js (100%) delete mode 100644 app/models/account.js delete mode 100644 app/models/gateway.js delete mode 100644 app/models/invoice.js delete mode 100644 app/models/journal.js create mode 100644 app/models/ledger-account.js create mode 100644 app/models/ledger-gateway.js create mode 100644 app/models/ledger-invoice.js create mode 100644 app/models/ledger-journal.js create mode 100644 app/models/ledger-transaction.js create mode 100644 app/models/ledger-wallet-transaction.js create mode 100644 app/models/ledger-wallet.js delete mode 100644 app/models/transaction.js delete mode 100644 app/models/wallet-transaction.js delete mode 100644 app/models/wallet.js create mode 100644 app/routes/ledger/accounting/general-ledger.js rename app/routes/ledger/{settings => payments}/gateways.js (100%) rename app/routes/ledger/{settings => payments}/gateways/index.js (100%) rename app/routes/ledger/{settings => payments}/gateways/index/details.js (100%) rename app/routes/ledger/{settings => payments}/gateways/index/details/index.js (100%) rename app/routes/ledger/{settings => payments}/gateways/index/details/webhooks.js (100%) rename app/routes/ledger/{billing => payments}/transactions.js (100%) rename app/routes/ledger/{billing => payments}/transactions/index.js (100%) rename app/routes/ledger/{billing => payments}/transactions/index/details.js (100%) rename app/routes/ledger/{billing => payments}/transactions/index/details/index.js (100%) rename app/routes/ledger/{ => payments}/wallets.js (100%) rename app/routes/ledger/{ => payments}/wallets/index.js (100%) rename app/routes/ledger/{ => payments}/wallets/index/details.js (100%) rename app/routes/ledger/{ => payments}/wallets/index/details/index.js (100%) rename app/routes/ledger/{ => payments}/wallets/index/details/transactions.js (100%) rename app/routes/ledger/{billing => receivables}/invoices.js (100%) rename app/routes/ledger/{billing => receivables}/invoices/index.js (100%) rename app/routes/ledger/{billing => receivables}/invoices/index/details.js (100%) rename app/routes/ledger/{billing => receivables}/invoices/index/details/index.js (100%) rename app/routes/ledger/{billing => receivables}/invoices/index/details/line-items.js (100%) rename app/routes/ledger/{billing => receivables}/invoices/index/details/transactions.js (100%) create mode 100644 app/routes/ledger/reports/ar-aging.js create mode 100644 app/routes/ledger/reports/balance-sheet.js create mode 100644 app/routes/ledger/reports/cash-flow.js create mode 100644 app/routes/ledger/reports/income-statement.js create mode 100644 app/routes/ledger/reports/trial-balance.js create mode 100644 app/routes/ledger/reports/wallet-summary.js create mode 100644 app/routes/ledger/settings/accounting.js create mode 100644 app/routes/ledger/settings/invoice.js create mode 100644 app/routes/ledger/settings/payment.js create mode 100644 app/serializers/ledger-account.js create mode 100644 app/serializers/ledger-gateway.js create mode 100644 app/serializers/ledger-invoice.js create mode 100644 app/serializers/ledger-journal.js create mode 100644 app/serializers/ledger-transaction.js create mode 100644 app/serializers/ledger-wallet-transaction.js create mode 100644 app/serializers/ledger-wallet.js create mode 100644 app/serializers/ledger.js diff --git a/addon/routes.js b/addon/routes.js index 798e649..d78b57b 100644 --- a/addon/routes.js +++ b/addon/routes.js @@ -1,11 +1,10 @@ import buildRoutes from 'ember-engines/routes'; - export default buildRoutes(function () { // Dashboard this.route('home', { path: '/' }); - // Billing - this.route('billing', function () { + // Receivables + this.route('receivables', function () { this.route('invoices', function () { this.route('index', { path: '/' }, function () { this.route('new'); @@ -16,6 +15,10 @@ export default buildRoutes(function () { }); }); }); + }); + + // Payments + this.route('payments', function () { this.route('transactions', function () { this.route('index', { path: '/' }, function () { this.route('details', { path: '/:id' }, function () { @@ -23,54 +26,61 @@ export default buildRoutes(function () { }); }); }); - }); - - // Wallets - this.route('wallets', function () { - this.route('index', { path: '/' }, function () { - this.route('details', { path: '/:id' }, function () { - this.route('index', { path: '/' }); - this.route('transactions'); + this.route('wallets', function () { + this.route('index', { path: '/' }, function () { + this.route('details', { path: '/:id' }, function () { + this.route('index', { path: '/' }); + this.route('transactions'); + }); + }); + }); + this.route('gateways', function () { + this.route('index', { path: '/' }, function () { + this.route('new'); + this.route('details', { path: '/:id' }, function () { + this.route('index', { path: '/' }); + this.route('webhooks'); + }); }); }); }); // Accounting this.route('accounting', function () { - this.route('journal', function () { + this.route('accounts', function () { this.route('index', { path: '/' }, function () { this.route('new'); this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); + this.route('ledger'); }); }); }); - this.route('accounts', function () { + this.route('journal', function () { this.route('index', { path: '/' }, function () { this.route('new'); this.route('details', { path: '/:id' }, function () { this.route('index', { path: '/' }); - this.route('ledger'); }); }); }); + this.route('general-ledger'); }); // Reports this.route('reports', function () { - this.route('index', { path: '/' }); + this.route('income-statement'); + this.route('balance-sheet'); + this.route('trial-balance'); + this.route('cash-flow'); + this.route('ar-aging'); + this.route('wallet-summary'); }); // Settings this.route('settings', function () { - this.route('gateways', function () { - this.route('index', { path: '/' }, function () { - this.route('new'); - this.route('details', { path: '/:id' }, function () { - this.route('index', { path: '/' }); - this.route('webhooks'); - }); - }); - }); + this.route('invoice'); + this.route('payment'); + this.route('accounting'); }); }); diff --git a/addon/templates/accounting/general-ledger.hbs b/addon/templates/accounting/general-ledger.hbs new file mode 100644 index 0000000..992ad2d --- /dev/null +++ b/addon/templates/accounting/general-ledger.hbs @@ -0,0 +1,4 @@ + + + {{outlet}} + diff --git a/addon/templates/application.hbs b/addon/templates/application.hbs index e6860bc..f1503a2 100644 --- a/addon/templates/application.hbs +++ b/addon/templates/application.hbs @@ -1,26 +1,37 @@ - - Dashboard - - - Invoices - Transactions + Dashboard + + + Invoices - - Wallets + + + Transactions + Wallets + Gateways + - Journal Entries Chart of Accounts + Journal Entries + General Ledger + - Reports + Income Statement + Balance Sheet + Trial Balance + Cash Flow + AR Aging + Wallet Summary + - Payment Gateways + Invoice Settings + Payment Settings + Accounting Settings - {{outlet}} diff --git a/addon/templates/settings/gateways.hbs b/addon/templates/payments/gateways.hbs similarity index 100% rename from addon/templates/settings/gateways.hbs rename to addon/templates/payments/gateways.hbs diff --git a/addon/templates/settings/gateways/index.hbs b/addon/templates/payments/gateways/index.hbs similarity index 100% rename from addon/templates/settings/gateways/index.hbs rename to addon/templates/payments/gateways/index.hbs diff --git a/addon/templates/settings/gateways/index/details.hbs b/addon/templates/payments/gateways/index/details.hbs similarity index 81% rename from addon/templates/settings/gateways/index/details.hbs rename to addon/templates/payments/gateways/index/details.hbs index 23beb24..fcd5f6a 100644 --- a/addon/templates/settings/gateways/index/details.hbs +++ b/addon/templates/payments/gateways/index/details.hbs @@ -1,7 +1,7 @@ <:header> diff --git a/addon/templates/settings/gateways/index/details/index.hbs b/addon/templates/payments/gateways/index/details/index.hbs similarity index 100% rename from addon/templates/settings/gateways/index/details/index.hbs rename to addon/templates/payments/gateways/index/details/index.hbs diff --git a/addon/templates/settings/gateways/index/details/webhooks.hbs b/addon/templates/payments/gateways/index/details/webhooks.hbs similarity index 100% rename from addon/templates/settings/gateways/index/details/webhooks.hbs rename to addon/templates/payments/gateways/index/details/webhooks.hbs diff --git a/addon/templates/billing/transactions.hbs b/addon/templates/payments/transactions.hbs similarity index 100% rename from addon/templates/billing/transactions.hbs rename to addon/templates/payments/transactions.hbs diff --git a/addon/templates/billing/transactions/index.hbs b/addon/templates/payments/transactions/index.hbs similarity index 100% rename from addon/templates/billing/transactions/index.hbs rename to addon/templates/payments/transactions/index.hbs diff --git a/addon/templates/billing/transactions/index/details.hbs b/addon/templates/payments/transactions/index/details.hbs similarity index 80% rename from addon/templates/billing/transactions/index/details.hbs rename to addon/templates/payments/transactions/index/details.hbs index 9b05ed6..5a5d918 100644 --- a/addon/templates/billing/transactions/index/details.hbs +++ b/addon/templates/payments/transactions/index/details.hbs @@ -1,6 +1,6 @@ <:header> diff --git a/addon/templates/billing/transactions/index/details/index.hbs b/addon/templates/payments/transactions/index/details/index.hbs similarity index 100% rename from addon/templates/billing/transactions/index/details/index.hbs rename to addon/templates/payments/transactions/index/details/index.hbs diff --git a/addon/templates/wallets.hbs b/addon/templates/payments/wallets.hbs similarity index 100% rename from addon/templates/wallets.hbs rename to addon/templates/payments/wallets.hbs diff --git a/addon/templates/wallets/index.hbs b/addon/templates/payments/wallets/index.hbs similarity index 100% rename from addon/templates/wallets/index.hbs rename to addon/templates/payments/wallets/index.hbs diff --git a/addon/templates/wallets/index/details.hbs b/addon/templates/payments/wallets/index/details.hbs similarity index 81% rename from addon/templates/wallets/index/details.hbs rename to addon/templates/payments/wallets/index/details.hbs index 93358ab..386aab5 100644 --- a/addon/templates/wallets/index/details.hbs +++ b/addon/templates/payments/wallets/index/details.hbs @@ -1,7 +1,7 @@ <:header> diff --git a/addon/templates/wallets/index/details/index.hbs b/addon/templates/payments/wallets/index/details/index.hbs similarity index 100% rename from addon/templates/wallets/index/details/index.hbs rename to addon/templates/payments/wallets/index/details/index.hbs diff --git a/addon/templates/wallets/index/details/transactions.hbs b/addon/templates/payments/wallets/index/details/transactions.hbs similarity index 100% rename from addon/templates/wallets/index/details/transactions.hbs rename to addon/templates/payments/wallets/index/details/transactions.hbs diff --git a/addon/templates/billing/invoices.hbs b/addon/templates/receivables/invoices.hbs similarity index 100% rename from addon/templates/billing/invoices.hbs rename to addon/templates/receivables/invoices.hbs diff --git a/addon/templates/billing/invoices/index.hbs b/addon/templates/receivables/invoices/index.hbs similarity index 100% rename from addon/templates/billing/invoices/index.hbs rename to addon/templates/receivables/invoices/index.hbs diff --git a/addon/templates/billing/invoices/index/details.hbs b/addon/templates/receivables/invoices/index/details.hbs similarity index 81% rename from addon/templates/billing/invoices/index/details.hbs rename to addon/templates/receivables/invoices/index/details.hbs index eeb2e5b..ebfc362 100644 --- a/addon/templates/billing/invoices/index/details.hbs +++ b/addon/templates/receivables/invoices/index/details.hbs @@ -1,7 +1,7 @@ <:header> diff --git a/addon/templates/billing/invoices/index/details/index.hbs b/addon/templates/receivables/invoices/index/details/index.hbs similarity index 100% rename from addon/templates/billing/invoices/index/details/index.hbs rename to addon/templates/receivables/invoices/index/details/index.hbs diff --git a/addon/templates/billing/invoices/index/details/line-items.hbs b/addon/templates/receivables/invoices/index/details/line-items.hbs similarity index 100% rename from addon/templates/billing/invoices/index/details/line-items.hbs rename to addon/templates/receivables/invoices/index/details/line-items.hbs diff --git a/addon/templates/billing/invoices/index/details/transactions.hbs b/addon/templates/receivables/invoices/index/details/transactions.hbs similarity index 100% rename from addon/templates/billing/invoices/index/details/transactions.hbs rename to addon/templates/receivables/invoices/index/details/transactions.hbs diff --git a/addon/templates/reports/ar-aging.hbs b/addon/templates/reports/ar-aging.hbs new file mode 100644 index 0000000..419bdf9 --- /dev/null +++ b/addon/templates/reports/ar-aging.hbs @@ -0,0 +1,4 @@ + + + + diff --git a/addon/templates/reports/balance-sheet.hbs b/addon/templates/reports/balance-sheet.hbs new file mode 100644 index 0000000..d8b4520 --- /dev/null +++ b/addon/templates/reports/balance-sheet.hbs @@ -0,0 +1,4 @@ + + + + diff --git a/addon/templates/reports/cash-flow.hbs b/addon/templates/reports/cash-flow.hbs new file mode 100644 index 0000000..3ab2afb --- /dev/null +++ b/addon/templates/reports/cash-flow.hbs @@ -0,0 +1,4 @@ + + + + diff --git a/addon/templates/reports/income-statement.hbs b/addon/templates/reports/income-statement.hbs new file mode 100644 index 0000000..a3f9d77 --- /dev/null +++ b/addon/templates/reports/income-statement.hbs @@ -0,0 +1,4 @@ + + + + diff --git a/addon/templates/reports/trial-balance.hbs b/addon/templates/reports/trial-balance.hbs new file mode 100644 index 0000000..88e50ce --- /dev/null +++ b/addon/templates/reports/trial-balance.hbs @@ -0,0 +1,4 @@ + + + {{outlet}} + diff --git a/addon/templates/reports/wallet-summary.hbs b/addon/templates/reports/wallet-summary.hbs new file mode 100644 index 0000000..d4b4ea6 --- /dev/null +++ b/addon/templates/reports/wallet-summary.hbs @@ -0,0 +1,4 @@ + + + {{outlet}} + diff --git a/addon/templates/settings/accounting.hbs b/addon/templates/settings/accounting.hbs new file mode 100644 index 0000000..cabe4a1 --- /dev/null +++ b/addon/templates/settings/accounting.hbs @@ -0,0 +1,4 @@ + + + {{outlet}} + diff --git a/addon/templates/settings/invoice.hbs b/addon/templates/settings/invoice.hbs new file mode 100644 index 0000000..627de00 --- /dev/null +++ b/addon/templates/settings/invoice.hbs @@ -0,0 +1,4 @@ + + + {{outlet}} + diff --git a/addon/templates/settings/payment.hbs b/addon/templates/settings/payment.hbs new file mode 100644 index 0000000..f2a09e6 --- /dev/null +++ b/addon/templates/settings/payment.hbs @@ -0,0 +1,4 @@ + + + {{outlet}} + diff --git a/app/adapters/account.js b/app/adapters/account.js deleted file mode 100644 index 089fb2c..0000000 --- a/app/adapters/account.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/account'; diff --git a/app/adapters/gateway.js b/app/adapters/gateway.js deleted file mode 100644 index dc351d0..0000000 --- a/app/adapters/gateway.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/gateway'; diff --git a/app/adapters/invoice.js b/app/adapters/invoice.js deleted file mode 100644 index 0a9d19b..0000000 --- a/app/adapters/invoice.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/invoice'; diff --git a/app/adapters/journal.js b/app/adapters/journal.js deleted file mode 100644 index c169a25..0000000 --- a/app/adapters/journal.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/journal'; diff --git a/app/adapters/ledger-account.js b/app/adapters/ledger-account.js new file mode 100644 index 0000000..c08585f --- /dev/null +++ b/app/adapters/ledger-account.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger-account'; diff --git a/app/adapters/ledger-gateway.js b/app/adapters/ledger-gateway.js new file mode 100644 index 0000000..77b6582 --- /dev/null +++ b/app/adapters/ledger-gateway.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger-gateway'; diff --git a/app/adapters/ledger-invoice.js b/app/adapters/ledger-invoice.js new file mode 100644 index 0000000..0c4bde5 --- /dev/null +++ b/app/adapters/ledger-invoice.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger-invoice'; diff --git a/app/adapters/ledger-journal.js b/app/adapters/ledger-journal.js new file mode 100644 index 0000000..057c423 --- /dev/null +++ b/app/adapters/ledger-journal.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger-journal'; diff --git a/app/adapters/ledger-transaction.js b/app/adapters/ledger-transaction.js new file mode 100644 index 0000000..71c3f80 --- /dev/null +++ b/app/adapters/ledger-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger-transaction'; diff --git a/app/adapters/ledger-wallet-transaction.js b/app/adapters/ledger-wallet-transaction.js new file mode 100644 index 0000000..e0eff48 --- /dev/null +++ b/app/adapters/ledger-wallet-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger-wallet-transaction'; diff --git a/app/adapters/ledger-wallet.js b/app/adapters/ledger-wallet.js new file mode 100644 index 0000000..60fccb2 --- /dev/null +++ b/app/adapters/ledger-wallet.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/adapters/ledger-wallet'; diff --git a/app/adapters/transaction.js b/app/adapters/transaction.js deleted file mode 100644 index 43249bb..0000000 --- a/app/adapters/transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/transaction'; diff --git a/app/adapters/wallet-transaction.js b/app/adapters/wallet-transaction.js deleted file mode 100644 index 9d59331..0000000 --- a/app/adapters/wallet-transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/wallet-transaction'; diff --git a/app/adapters/wallet.js b/app/adapters/wallet.js deleted file mode 100644 index e377864..0000000 --- a/app/adapters/wallet.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/wallet'; diff --git a/app/controllers/ledger/settings/gateways/index.js b/app/controllers/ledger/payments/gateways/index.js similarity index 100% rename from app/controllers/ledger/settings/gateways/index.js rename to app/controllers/ledger/payments/gateways/index.js diff --git a/app/controllers/ledger/settings/gateways/index/details.js b/app/controllers/ledger/payments/gateways/index/details.js similarity index 100% rename from app/controllers/ledger/settings/gateways/index/details.js rename to app/controllers/ledger/payments/gateways/index/details.js diff --git a/app/controllers/ledger/billing/transactions/index.js b/app/controllers/ledger/payments/transactions/index.js similarity index 100% rename from app/controllers/ledger/billing/transactions/index.js rename to app/controllers/ledger/payments/transactions/index.js diff --git a/app/controllers/ledger/billing/transactions/index/details.js b/app/controllers/ledger/payments/transactions/index/details.js similarity index 100% rename from app/controllers/ledger/billing/transactions/index/details.js rename to app/controllers/ledger/payments/transactions/index/details.js diff --git a/app/controllers/ledger/wallets/index.js b/app/controllers/ledger/payments/wallets/index.js similarity index 100% rename from app/controllers/ledger/wallets/index.js rename to app/controllers/ledger/payments/wallets/index.js diff --git a/app/controllers/ledger/wallets/index/details.js b/app/controllers/ledger/payments/wallets/index/details.js similarity index 100% rename from app/controllers/ledger/wallets/index/details.js rename to app/controllers/ledger/payments/wallets/index/details.js diff --git a/app/controllers/ledger/billing/invoices/index.js b/app/controllers/ledger/receivables/invoices/index.js similarity index 100% rename from app/controllers/ledger/billing/invoices/index.js rename to app/controllers/ledger/receivables/invoices/index.js diff --git a/app/controllers/ledger/billing/invoices/index/details.js b/app/controllers/ledger/receivables/invoices/index/details.js similarity index 100% rename from app/controllers/ledger/billing/invoices/index/details.js rename to app/controllers/ledger/receivables/invoices/index/details.js diff --git a/app/models/account.js b/app/models/account.js deleted file mode 100644 index b9decce..0000000 --- a/app/models/account.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/account'; diff --git a/app/models/gateway.js b/app/models/gateway.js deleted file mode 100644 index a0648b4..0000000 --- a/app/models/gateway.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/gateway'; diff --git a/app/models/invoice.js b/app/models/invoice.js deleted file mode 100644 index 8fc92f3..0000000 --- a/app/models/invoice.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/invoice'; diff --git a/app/models/journal.js b/app/models/journal.js deleted file mode 100644 index fc13a60..0000000 --- a/app/models/journal.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/journal'; diff --git a/app/models/ledger-account.js b/app/models/ledger-account.js new file mode 100644 index 0000000..8710f1f --- /dev/null +++ b/app/models/ledger-account.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/ledger-account'; diff --git a/app/models/ledger-gateway.js b/app/models/ledger-gateway.js new file mode 100644 index 0000000..7f819fa --- /dev/null +++ b/app/models/ledger-gateway.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/ledger-gateway'; diff --git a/app/models/ledger-invoice.js b/app/models/ledger-invoice.js new file mode 100644 index 0000000..1fddcdf --- /dev/null +++ b/app/models/ledger-invoice.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/ledger-invoice'; diff --git a/app/models/ledger-journal.js b/app/models/ledger-journal.js new file mode 100644 index 0000000..820d110 --- /dev/null +++ b/app/models/ledger-journal.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/ledger-journal'; diff --git a/app/models/ledger-transaction.js b/app/models/ledger-transaction.js new file mode 100644 index 0000000..e58f62d --- /dev/null +++ b/app/models/ledger-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/ledger-transaction'; diff --git a/app/models/ledger-wallet-transaction.js b/app/models/ledger-wallet-transaction.js new file mode 100644 index 0000000..942a445 --- /dev/null +++ b/app/models/ledger-wallet-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/ledger-wallet-transaction'; diff --git a/app/models/ledger-wallet.js b/app/models/ledger-wallet.js new file mode 100644 index 0000000..857a44d --- /dev/null +++ b/app/models/ledger-wallet.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/models/ledger-wallet'; diff --git a/app/models/transaction.js b/app/models/transaction.js deleted file mode 100644 index dd48f27..0000000 --- a/app/models/transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/transaction'; diff --git a/app/models/wallet-transaction.js b/app/models/wallet-transaction.js deleted file mode 100644 index 4b5328d..0000000 --- a/app/models/wallet-transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/wallet-transaction'; diff --git a/app/models/wallet.js b/app/models/wallet.js deleted file mode 100644 index 7414123..0000000 --- a/app/models/wallet.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/wallet'; diff --git a/app/routes/ledger/accounting/general-ledger.js b/app/routes/ledger/accounting/general-ledger.js new file mode 100644 index 0000000..8742e7a --- /dev/null +++ b/app/routes/ledger/accounting/general-ledger.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/general-ledger'; diff --git a/app/routes/ledger/settings/gateways.js b/app/routes/ledger/payments/gateways.js similarity index 100% rename from app/routes/ledger/settings/gateways.js rename to app/routes/ledger/payments/gateways.js diff --git a/app/routes/ledger/settings/gateways/index.js b/app/routes/ledger/payments/gateways/index.js similarity index 100% rename from app/routes/ledger/settings/gateways/index.js rename to app/routes/ledger/payments/gateways/index.js diff --git a/app/routes/ledger/settings/gateways/index/details.js b/app/routes/ledger/payments/gateways/index/details.js similarity index 100% rename from app/routes/ledger/settings/gateways/index/details.js rename to app/routes/ledger/payments/gateways/index/details.js diff --git a/app/routes/ledger/settings/gateways/index/details/index.js b/app/routes/ledger/payments/gateways/index/details/index.js similarity index 100% rename from app/routes/ledger/settings/gateways/index/details/index.js rename to app/routes/ledger/payments/gateways/index/details/index.js diff --git a/app/routes/ledger/settings/gateways/index/details/webhooks.js b/app/routes/ledger/payments/gateways/index/details/webhooks.js similarity index 100% rename from app/routes/ledger/settings/gateways/index/details/webhooks.js rename to app/routes/ledger/payments/gateways/index/details/webhooks.js diff --git a/app/routes/ledger/billing/transactions.js b/app/routes/ledger/payments/transactions.js similarity index 100% rename from app/routes/ledger/billing/transactions.js rename to app/routes/ledger/payments/transactions.js diff --git a/app/routes/ledger/billing/transactions/index.js b/app/routes/ledger/payments/transactions/index.js similarity index 100% rename from app/routes/ledger/billing/transactions/index.js rename to app/routes/ledger/payments/transactions/index.js diff --git a/app/routes/ledger/billing/transactions/index/details.js b/app/routes/ledger/payments/transactions/index/details.js similarity index 100% rename from app/routes/ledger/billing/transactions/index/details.js rename to app/routes/ledger/payments/transactions/index/details.js diff --git a/app/routes/ledger/billing/transactions/index/details/index.js b/app/routes/ledger/payments/transactions/index/details/index.js similarity index 100% rename from app/routes/ledger/billing/transactions/index/details/index.js rename to app/routes/ledger/payments/transactions/index/details/index.js diff --git a/app/routes/ledger/wallets.js b/app/routes/ledger/payments/wallets.js similarity index 100% rename from app/routes/ledger/wallets.js rename to app/routes/ledger/payments/wallets.js diff --git a/app/routes/ledger/wallets/index.js b/app/routes/ledger/payments/wallets/index.js similarity index 100% rename from app/routes/ledger/wallets/index.js rename to app/routes/ledger/payments/wallets/index.js diff --git a/app/routes/ledger/wallets/index/details.js b/app/routes/ledger/payments/wallets/index/details.js similarity index 100% rename from app/routes/ledger/wallets/index/details.js rename to app/routes/ledger/payments/wallets/index/details.js diff --git a/app/routes/ledger/wallets/index/details/index.js b/app/routes/ledger/payments/wallets/index/details/index.js similarity index 100% rename from app/routes/ledger/wallets/index/details/index.js rename to app/routes/ledger/payments/wallets/index/details/index.js diff --git a/app/routes/ledger/wallets/index/details/transactions.js b/app/routes/ledger/payments/wallets/index/details/transactions.js similarity index 100% rename from app/routes/ledger/wallets/index/details/transactions.js rename to app/routes/ledger/payments/wallets/index/details/transactions.js diff --git a/app/routes/ledger/billing/invoices.js b/app/routes/ledger/receivables/invoices.js similarity index 100% rename from app/routes/ledger/billing/invoices.js rename to app/routes/ledger/receivables/invoices.js diff --git a/app/routes/ledger/billing/invoices/index.js b/app/routes/ledger/receivables/invoices/index.js similarity index 100% rename from app/routes/ledger/billing/invoices/index.js rename to app/routes/ledger/receivables/invoices/index.js diff --git a/app/routes/ledger/billing/invoices/index/details.js b/app/routes/ledger/receivables/invoices/index/details.js similarity index 100% rename from app/routes/ledger/billing/invoices/index/details.js rename to app/routes/ledger/receivables/invoices/index/details.js diff --git a/app/routes/ledger/billing/invoices/index/details/index.js b/app/routes/ledger/receivables/invoices/index/details/index.js similarity index 100% rename from app/routes/ledger/billing/invoices/index/details/index.js rename to app/routes/ledger/receivables/invoices/index/details/index.js diff --git a/app/routes/ledger/billing/invoices/index/details/line-items.js b/app/routes/ledger/receivables/invoices/index/details/line-items.js similarity index 100% rename from app/routes/ledger/billing/invoices/index/details/line-items.js rename to app/routes/ledger/receivables/invoices/index/details/line-items.js diff --git a/app/routes/ledger/billing/invoices/index/details/transactions.js b/app/routes/ledger/receivables/invoices/index/details/transactions.js similarity index 100% rename from app/routes/ledger/billing/invoices/index/details/transactions.js rename to app/routes/ledger/receivables/invoices/index/details/transactions.js diff --git a/app/routes/ledger/reports/ar-aging.js b/app/routes/ledger/reports/ar-aging.js new file mode 100644 index 0000000..104babf --- /dev/null +++ b/app/routes/ledger/reports/ar-aging.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/reports/ar-aging'; diff --git a/app/routes/ledger/reports/balance-sheet.js b/app/routes/ledger/reports/balance-sheet.js new file mode 100644 index 0000000..b6990f5 --- /dev/null +++ b/app/routes/ledger/reports/balance-sheet.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/reports/balance-sheet'; diff --git a/app/routes/ledger/reports/cash-flow.js b/app/routes/ledger/reports/cash-flow.js new file mode 100644 index 0000000..3fa4f93 --- /dev/null +++ b/app/routes/ledger/reports/cash-flow.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/reports/cash-flow'; diff --git a/app/routes/ledger/reports/income-statement.js b/app/routes/ledger/reports/income-statement.js new file mode 100644 index 0000000..4774303 --- /dev/null +++ b/app/routes/ledger/reports/income-statement.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/reports/income-statement'; diff --git a/app/routes/ledger/reports/trial-balance.js b/app/routes/ledger/reports/trial-balance.js new file mode 100644 index 0000000..f7b4235 --- /dev/null +++ b/app/routes/ledger/reports/trial-balance.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/reports/trial-balance'; diff --git a/app/routes/ledger/reports/wallet-summary.js b/app/routes/ledger/reports/wallet-summary.js new file mode 100644 index 0000000..cca5edb --- /dev/null +++ b/app/routes/ledger/reports/wallet-summary.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/reports/wallet-summary'; diff --git a/app/routes/ledger/settings/accounting.js b/app/routes/ledger/settings/accounting.js new file mode 100644 index 0000000..a3e945c --- /dev/null +++ b/app/routes/ledger/settings/accounting.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/accounting'; diff --git a/app/routes/ledger/settings/invoice.js b/app/routes/ledger/settings/invoice.js new file mode 100644 index 0000000..6b6e84f --- /dev/null +++ b/app/routes/ledger/settings/invoice.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/invoice'; diff --git a/app/routes/ledger/settings/payment.js b/app/routes/ledger/settings/payment.js new file mode 100644 index 0000000..e403187 --- /dev/null +++ b/app/routes/ledger/settings/payment.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/settings/payment'; diff --git a/app/serializers/ledger-account.js b/app/serializers/ledger-account.js new file mode 100644 index 0000000..0ff8313 --- /dev/null +++ b/app/serializers/ledger-account.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger-account'; diff --git a/app/serializers/ledger-gateway.js b/app/serializers/ledger-gateway.js new file mode 100644 index 0000000..e0f3cbd --- /dev/null +++ b/app/serializers/ledger-gateway.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger-gateway'; diff --git a/app/serializers/ledger-invoice.js b/app/serializers/ledger-invoice.js new file mode 100644 index 0000000..e348760 --- /dev/null +++ b/app/serializers/ledger-invoice.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger-invoice'; diff --git a/app/serializers/ledger-journal.js b/app/serializers/ledger-journal.js new file mode 100644 index 0000000..91b284d --- /dev/null +++ b/app/serializers/ledger-journal.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger-journal'; diff --git a/app/serializers/ledger-transaction.js b/app/serializers/ledger-transaction.js new file mode 100644 index 0000000..3aafcc0 --- /dev/null +++ b/app/serializers/ledger-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger-transaction'; diff --git a/app/serializers/ledger-wallet-transaction.js b/app/serializers/ledger-wallet-transaction.js new file mode 100644 index 0000000..a77daf9 --- /dev/null +++ b/app/serializers/ledger-wallet-transaction.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger-wallet-transaction'; diff --git a/app/serializers/ledger-wallet.js b/app/serializers/ledger-wallet.js new file mode 100644 index 0000000..f480830 --- /dev/null +++ b/app/serializers/ledger-wallet.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger-wallet'; diff --git a/app/serializers/ledger.js b/app/serializers/ledger.js new file mode 100644 index 0000000..ca2e51c --- /dev/null +++ b/app/serializers/ledger.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/serializers/ledger'; From 430356611773e0596ba29684ca67760bc70037e3 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 20:24:40 -0500 Subject: [PATCH 024/209] rename: receivables -> billing throughout (future-proofs for AP/payables) --- addon/routes.js | 2 +- addon/templates/application.hbs | 4 ++-- addon/templates/{receivables => billing}/invoices.hbs | 0 addon/templates/{receivables => billing}/invoices/index.hbs | 0 .../{receivables => billing}/invoices/index/details.hbs | 2 +- .../{receivables => billing}/invoices/index/details/index.hbs | 0 .../invoices/index/details/line-items.hbs | 0 .../invoices/index/details/transactions.hbs | 0 .../ledger/{receivables => billing}/invoices/index.js | 0 .../ledger/{receivables => billing}/invoices/index/details.js | 0 app/routes/ledger/{receivables => billing}/invoices.js | 0 app/routes/ledger/{receivables => billing}/invoices/index.js | 0 .../ledger/{receivables => billing}/invoices/index/details.js | 0 .../{receivables => billing}/invoices/index/details/index.js | 0 .../invoices/index/details/line-items.js | 0 .../invoices/index/details/transactions.js | 0 16 files changed, 4 insertions(+), 4 deletions(-) rename addon/templates/{receivables => billing}/invoices.hbs (100%) rename addon/templates/{receivables => billing}/invoices/index.hbs (100%) rename addon/templates/{receivables => billing}/invoices/index/details.hbs (81%) rename addon/templates/{receivables => billing}/invoices/index/details/index.hbs (100%) rename addon/templates/{receivables => billing}/invoices/index/details/line-items.hbs (100%) rename addon/templates/{receivables => billing}/invoices/index/details/transactions.hbs (100%) rename app/controllers/ledger/{receivables => billing}/invoices/index.js (100%) rename app/controllers/ledger/{receivables => billing}/invoices/index/details.js (100%) rename app/routes/ledger/{receivables => billing}/invoices.js (100%) rename app/routes/ledger/{receivables => billing}/invoices/index.js (100%) rename app/routes/ledger/{receivables => billing}/invoices/index/details.js (100%) rename app/routes/ledger/{receivables => billing}/invoices/index/details/index.js (100%) rename app/routes/ledger/{receivables => billing}/invoices/index/details/line-items.js (100%) rename app/routes/ledger/{receivables => billing}/invoices/index/details/transactions.js (100%) diff --git a/addon/routes.js b/addon/routes.js index d78b57b..1f8d678 100644 --- a/addon/routes.js +++ b/addon/routes.js @@ -4,7 +4,7 @@ export default buildRoutes(function () { this.route('home', { path: '/' }); // Receivables - this.route('receivables', function () { + this.route('billing', function () { this.route('invoices', function () { this.route('index', { path: '/' }, function () { this.route('new'); diff --git a/addon/templates/application.hbs b/addon/templates/application.hbs index f1503a2..23e71d4 100644 --- a/addon/templates/application.hbs +++ b/addon/templates/application.hbs @@ -1,8 +1,8 @@ Dashboard - - Invoices + + Invoices diff --git a/addon/templates/receivables/invoices.hbs b/addon/templates/billing/invoices.hbs similarity index 100% rename from addon/templates/receivables/invoices.hbs rename to addon/templates/billing/invoices.hbs diff --git a/addon/templates/receivables/invoices/index.hbs b/addon/templates/billing/invoices/index.hbs similarity index 100% rename from addon/templates/receivables/invoices/index.hbs rename to addon/templates/billing/invoices/index.hbs diff --git a/addon/templates/receivables/invoices/index/details.hbs b/addon/templates/billing/invoices/index/details.hbs similarity index 81% rename from addon/templates/receivables/invoices/index/details.hbs rename to addon/templates/billing/invoices/index/details.hbs index ebfc362..eeb2e5b 100644 --- a/addon/templates/receivables/invoices/index/details.hbs +++ b/addon/templates/billing/invoices/index/details.hbs @@ -1,7 +1,7 @@ <:header> diff --git a/addon/templates/receivables/invoices/index/details/index.hbs b/addon/templates/billing/invoices/index/details/index.hbs similarity index 100% rename from addon/templates/receivables/invoices/index/details/index.hbs rename to addon/templates/billing/invoices/index/details/index.hbs diff --git a/addon/templates/receivables/invoices/index/details/line-items.hbs b/addon/templates/billing/invoices/index/details/line-items.hbs similarity index 100% rename from addon/templates/receivables/invoices/index/details/line-items.hbs rename to addon/templates/billing/invoices/index/details/line-items.hbs diff --git a/addon/templates/receivables/invoices/index/details/transactions.hbs b/addon/templates/billing/invoices/index/details/transactions.hbs similarity index 100% rename from addon/templates/receivables/invoices/index/details/transactions.hbs rename to addon/templates/billing/invoices/index/details/transactions.hbs diff --git a/app/controllers/ledger/receivables/invoices/index.js b/app/controllers/ledger/billing/invoices/index.js similarity index 100% rename from app/controllers/ledger/receivables/invoices/index.js rename to app/controllers/ledger/billing/invoices/index.js diff --git a/app/controllers/ledger/receivables/invoices/index/details.js b/app/controllers/ledger/billing/invoices/index/details.js similarity index 100% rename from app/controllers/ledger/receivables/invoices/index/details.js rename to app/controllers/ledger/billing/invoices/index/details.js diff --git a/app/routes/ledger/receivables/invoices.js b/app/routes/ledger/billing/invoices.js similarity index 100% rename from app/routes/ledger/receivables/invoices.js rename to app/routes/ledger/billing/invoices.js diff --git a/app/routes/ledger/receivables/invoices/index.js b/app/routes/ledger/billing/invoices/index.js similarity index 100% rename from app/routes/ledger/receivables/invoices/index.js rename to app/routes/ledger/billing/invoices/index.js diff --git a/app/routes/ledger/receivables/invoices/index/details.js b/app/routes/ledger/billing/invoices/index/details.js similarity index 100% rename from app/routes/ledger/receivables/invoices/index/details.js rename to app/routes/ledger/billing/invoices/index/details.js diff --git a/app/routes/ledger/receivables/invoices/index/details/index.js b/app/routes/ledger/billing/invoices/index/details/index.js similarity index 100% rename from app/routes/ledger/receivables/invoices/index/details/index.js rename to app/routes/ledger/billing/invoices/index/details/index.js diff --git a/app/routes/ledger/receivables/invoices/index/details/line-items.js b/app/routes/ledger/billing/invoices/index/details/line-items.js similarity index 100% rename from app/routes/ledger/receivables/invoices/index/details/line-items.js rename to app/routes/ledger/billing/invoices/index/details/line-items.js diff --git a/app/routes/ledger/receivables/invoices/index/details/transactions.js b/app/routes/ledger/billing/invoices/index/details/transactions.js similarity index 100% rename from app/routes/ledger/receivables/invoices/index/details/transactions.js rename to app/routes/ledger/billing/invoices/index/details/transactions.js From 5bf613737150808c55c32e470926f16ec250ec20 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 20:34:02 -0500 Subject: [PATCH 025/209] feat: add action services, fix parent templates to outlet, use Layout::Resource::Tabular on all index routes - All parent route templates (billing/invoices, payments/transactions, payments/wallets, payments/gateways, accounting/accounts, accounting/journal) now contain only {{outlet}} - All index templates replaced with Layout::Resource::Tabular using correct resource, title, search, columns, pagination, and action bindings - Created 7 dedicated action services following FleetOps ResourceActionService pattern: invoice-actions, transaction-actions, wallet-actions, gateway-actions, account-actions, journal-actions, wallet-transaction-actions - All index controllers refactored to inject their action service and define columns, actionButtons, bulkActions as getters - Added app/services/ re-exports for all 7 action services --- .../controllers/accounting/accounts/index.js | 103 +++++++---- addon/controllers/accounting/journal/index.js | 151 +++++++--------- addon/controllers/billing/invoices/index.js | 169 +++++++----------- addon/controllers/payments/gateways/index.js | 78 ++++++++ .../payments/transactions/index.js | 73 ++++++++ addon/controllers/payments/wallets/index.js | 80 +++++++++ addon/services/account-actions.js | 47 +++++ addon/services/gateway-actions.js | 47 +++++ addon/services/invoice-actions.js | 44 +++++ addon/services/journal-actions.js | 35 ++++ addon/services/transaction-actions.js | 23 +++ addon/services/wallet-actions.js | 26 +++ addon/services/wallet-transaction-actions.js | 23 +++ addon/templates/accounting/accounts.hbs | 14 -- addon/templates/accounting/accounts/index.hbs | 28 +-- addon/templates/accounting/journal.hbs | 15 -- addon/templates/accounting/journal/index.hbs | 28 +-- addon/templates/billing/invoices.hbs | 15 -- addon/templates/billing/invoices/index.hbs | 28 +-- addon/templates/payments/gateways.hbs | 14 -- addon/templates/payments/gateways/index.hbs | 24 +-- addon/templates/payments/transactions.hbs | 14 -- .../templates/payments/transactions/index.hbs | 28 +-- addon/templates/payments/wallets.hbs | 14 -- addon/templates/payments/wallets/index.hbs | 28 +-- app/services/account-actions.js | 1 + app/services/gateway-actions.js | 1 + app/services/invoice-actions.js | 1 + app/services/journal-actions.js | 1 + app/services/transaction-actions.js | 1 + app/services/wallet-actions.js | 1 + app/services/wallet-transaction-actions.js | 1 + 32 files changed, 768 insertions(+), 388 deletions(-) create mode 100644 addon/controllers/payments/gateways/index.js create mode 100644 addon/controllers/payments/transactions/index.js create mode 100644 addon/controllers/payments/wallets/index.js create mode 100644 addon/services/account-actions.js create mode 100644 addon/services/gateway-actions.js create mode 100644 addon/services/invoice-actions.js create mode 100644 addon/services/journal-actions.js create mode 100644 addon/services/transaction-actions.js create mode 100644 addon/services/wallet-actions.js create mode 100644 addon/services/wallet-transaction-actions.js create mode 100644 app/services/account-actions.js create mode 100644 app/services/gateway-actions.js create mode 100644 app/services/invoice-actions.js create mode 100644 app/services/journal-actions.js create mode 100644 app/services/transaction-actions.js create mode 100644 app/services/wallet-actions.js create mode 100644 app/services/wallet-transaction-actions.js diff --git a/addon/controllers/accounting/accounts/index.js b/addon/controllers/accounting/accounts/index.js index 85d2cf6..338dd28 100644 --- a/addon/controllers/accounting/accounts/index.js +++ b/addon/controllers/accounting/accounts/index.js @@ -1,50 +1,89 @@ import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { tracked } from '@glimmer/tracking'; -import { action } from '@ember/object'; -import { task } from 'ember-concurrency'; export default class AccountingAccountsIndexController extends Controller { - @service hostRouter; - @service notifications; - @service modalsManager; - - queryParams = ['page', 'limit', 'sort', 'query', 'type']; + @service accountActions; + @service tableContext; + @service intl; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; @tracked page = 1; - @tracked limit = 100; - @tracked sort = 'code'; + @tracked limit = null; + @tracked sort = '-created_at'; @tracked query = null; @tracked type = null; + @tracked status = null; @tracked table = null; - - columns = [ - { label: 'Code', valuePath: 'code', width: '80px', sortable: true }, - { label: 'Account Name', valuePath: 'name', width: '220px', sortable: true }, - { label: 'Type', valuePath: 'type_label', width: '100px' }, - { label: 'Balance', valuePath: 'formatted_balance', width: '140px', sortable: true }, - { label: 'Status', valuePath: 'status_label', width: '90px', component: 'table/cell/status' }, - ]; - - get actionButtons() { +get columns() { return [ - { label: 'New Account', icon: 'plus', type: 'primary', onClick: this.createAccount }, + { + sticky: true, + label: this.intl.t('column.name'), + valuePath: 'name', + cellComponent: 'table/cell/anchor', + action: this.accountActions.transition.view, + resizable: true, + sortable: true, + filterable: true, + filterParam: 'name', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.code'), + valuePath: 'code', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.type'), + valuePath: 'type', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'type', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.balance'), + valuePath: 'balance', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.status'), + valuePath: 'status', + cellComponent: 'table/cell/status', + resizable: true, + sortable: true, + }, ]; } - @task({ restartable: true }) *search(query) { - this.query = query; - } - - @action createAccount() { - this.hostRouter.transitionTo('console.ledger.accounting.accounts.index.new'); - } - - @action viewAccount(account) { - this.hostRouter.transitionTo('console.ledger.accounting.accounts.index.details', account.id); +get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.accountActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.accountActions.transition.create, + }, + ]; } - @action reload() { - return this.hostRouter.refresh(); +get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.accountActions.bulkDelete, + }, + ]; } } diff --git a/addon/controllers/accounting/journal/index.js b/addon/controllers/accounting/journal/index.js index 1a14f2f..a12af51 100644 --- a/addon/controllers/accounting/journal/index.js +++ b/addon/controllers/accounting/journal/index.js @@ -1,103 +1,88 @@ import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { tracked } from '@glimmer/tracking'; -import { action } from '@ember/object'; -import { task } from 'ember-concurrency'; export default class AccountingJournalIndexController extends Controller { - @service hostRouter; - @service notifications; - @service modalsManager; - - queryParams = ['page', 'limit', 'sort', 'query', 'type']; + @service journalActions; + @service tableContext; + @service intl; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'entry_source']; @tracked page = 1; - @tracked limit = 30; - @tracked sort = '-date'; + @tracked limit = null; + @tracked sort = '-created_at'; @tracked query = null; - @tracked type = null; + @tracked entry_source = null; @tracked table = null; - - columns = [ - { label: 'Date', valuePath: 'date', width: '120px', sortable: true, component: 'table/cell/date' }, - { label: 'Entry #', valuePath: 'number', width: '120px' }, - { label: 'Description', valuePath: 'description', width: '220px' }, - { label: 'Debit Account', valuePath: 'debit_account_name', width: '160px' }, - { label: 'Credit Account', valuePath: 'credit_account_name', width: '160px' }, - { label: 'Amount', valuePath: 'formatted_amount', width: '120px', sortable: true }, - { label: 'Source', valuePath: 'entry_source', width: '90px' }, - ]; - - get actionButtons() { +get columns() { return [ - { label: 'New Entry', icon: 'plus', type: 'primary', onClick: this.createEntry }, + { + sticky: true, + label: this.intl.t('column.id'), + valuePath: 'public_id', + cellComponent: 'table/cell/anchor', + action: this.journalActions.transition.view, + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.date'), + valuePath: 'entry_date', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.debit-account'), + valuePath: 'debit_account.name', + resizable: true, + }, + { + label: this.intl.t('column.credit-account'), + valuePath: 'credit_account.name', + resizable: true, + }, + { + label: this.intl.t('column.amount'), + valuePath: 'amount', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.source'), + valuePath: 'entry_source', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'entry_source', + filterComponent: 'filter/string', + }, ]; } - get bulkActions() { +get actionButtons() { return [ - { label: 'Delete Selected', icon: 'trash', fn: this.bulkDeleteEntries }, - ]; - } - - @task({ restartable: true }) *search(query) { - this.query = query; - } - - @action createEntry() { - this.hostRouter.transitionTo('console.ledger.accounting.journal.index.new'); - } - - @action viewEntry(entry) { - this.hostRouter.transitionTo('console.ledger.accounting.journal.index.details', entry.id); - } - - @action async deleteEntry(entry) { - if (entry.is_system_entry) { - return this.notifications.warning('System journal entries cannot be deleted.'); - } - this.modalsManager.confirm({ - title: 'Delete Journal Entry?', - body: 'This action cannot be undone.', - confirm: async (modal) => { - modal.startLoading(); - try { - await entry.destroyRecord(); - this.notifications.success('Journal entry deleted.'); - this.hostRouter.refresh(); - modal.done(); - } catch (error) { - this.notifications.serverError(error); - modal.stopLoading(); - } + { + icon: 'refresh', + onClick: this.journalActions.refresh, + helpText: this.intl.t('common.refresh'), }, - }); - } - - @action async bulkDeleteEntries(selected) { - const manual = selected.filter((e) => !e.is_system_entry); - if (!manual.length) { - return this.notifications.warning('Only manual entries can be deleted.'); - } - this.modalsManager.confirm({ - title: `Delete ${manual.length} manual entry(s)?`, - body: 'This action cannot be undone.', - confirm: async (modal) => { - modal.startLoading(); - try { - await Promise.all(manual.map((e) => e.destroyRecord())); - this.notifications.success(`${manual.length} entry(s) deleted.`); - this.hostRouter.refresh(); - modal.done(); - } catch (error) { - this.notifications.serverError(error); - modal.stopLoading(); - } + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.journalActions.transition.create, }, - }); + ]; } - @action reload() { - return this.hostRouter.refresh(); +get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.journalActions.bulkDelete, + }, + ]; } } diff --git a/addon/controllers/billing/invoices/index.js b/addon/controllers/billing/invoices/index.js index 01109bf..cf1642c 100644 --- a/addon/controllers/billing/invoices/index.js +++ b/addon/controllers/billing/invoices/index.js @@ -1,134 +1,89 @@ import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { tracked } from '@glimmer/tracking'; -import { action } from '@ember/object'; -import { task } from 'ember-concurrency'; export default class BillingInvoicesIndexController extends Controller { - @service store; - @service notifications; - @service modalsManager; + @service invoiceActions; + @service tableContext; @service intl; - @service hostRouter; - @service crud; - - queryParams = ['page', 'limit', 'sort', 'query', 'status']; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'status', 'customer_uuid']; @tracked page = 1; - @tracked limit = 30; + @tracked limit = null; @tracked sort = '-created_at'; @tracked query = null; @tracked status = null; + @tracked customer_uuid = null; @tracked table = null; - - columns = [ - { - label: 'Invoice #', - valuePath: 'number', - width: '140px', - sortable: true, - }, - { - label: 'Customer', - valuePath: 'customer_name', - width: '180px', - }, - { - label: 'Due Date', - valuePath: 'due_at', - width: '120px', - sortable: true, - component: 'table/cell/date', - }, - { - label: 'Total', - valuePath: 'formatted_total', - width: '120px', - sortable: true, - }, - { - label: 'Balance', - valuePath: 'formatted_balance', - width: '120px', - }, - { - label: 'Status', - valuePath: 'status', - width: '100px', - component: 'table/cell/status', - }, - ]; - - get actionButtons() { +get columns() { return [ { - label: 'New Invoice', - icon: 'plus', - type: 'primary', - onClick: this.createInvoice, + sticky: true, + label: this.intl.t('column.id'), + valuePath: 'public_id', + cellComponent: 'table/cell/anchor', + action: this.invoiceActions.transition.view, + resizable: true, + sortable: true, + filterable: true, + filterParam: 'public_id', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.status'), + valuePath: 'status', + cellComponent: 'table/cell/status', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'status', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.amount'), + valuePath: 'amount', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.due-date'), + valuePath: 'due_date', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.created-at'), + valuePath: 'createdAt', + resizable: true, + sortable: true, }, ]; } - get bulkActions() { +get actionButtons() { return [ { - label: 'Delete Selected', - icon: 'trash', - fn: this.bulkDeleteInvoices, + icon: 'refresh', + onClick: this.invoiceActions.refresh, + helpText: this.intl.t('common.refresh'), }, - ]; - } - - @task({ restartable: true }) *search(query) { - this.query = query; - } - - @action createInvoice() { - this.hostRouter.transitionTo('console.ledger.billing.invoices.index.new'); - } - - @action viewInvoice(invoice) { - this.hostRouter.transitionTo('console.ledger.billing.invoices.index.details', invoice.id); - } - - @action async deleteInvoice(invoice) { - this.modalsManager.confirm({ - title: `Delete Invoice ${invoice.number}?`, - body: 'This action cannot be undone.', - confirm: async (modal) => { - modal.startLoading(); - try { - await invoice.destroyRecord(); - this.notifications.success('Invoice deleted.'); - this.hostRouter.refresh(); - } catch (error) { - this.notifications.serverError(error); - modal.stopLoading(); - } + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.invoiceActions.transition.create, }, - }); + ]; } - @action async bulkDeleteInvoices(selected) { - this.modalsManager.confirm({ - title: `Delete ${selected.length} invoice(s)?`, - body: 'This action cannot be undone.', - confirm: async (modal) => { - modal.startLoading(); - try { - await Promise.all(selected.map((i) => i.destroyRecord())); - this.notifications.success(`${selected.length} invoice(s) deleted.`); - this.hostRouter.refresh(); - } catch (error) { - this.notifications.serverError(error); - modal.stopLoading(); - } +get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.invoiceActions.bulkDelete, }, - }); - } - - @action reload() { - return this.hostRouter.refresh(); + ]; } } diff --git a/addon/controllers/payments/gateways/index.js b/addon/controllers/payments/gateways/index.js new file mode 100644 index 0000000..76e2223 --- /dev/null +++ b/addon/controllers/payments/gateways/index.js @@ -0,0 +1,78 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; + +export default class PaymentsGatewaysIndexController extends Controller { + @service gatewayActions; + @service tableContext; + @service intl; + + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type']; + @tracked page = 1; + @tracked limit = null; + @tracked sort = '-created_at'; + @tracked query = null; + @tracked type = null; + @tracked table = null; +get columns() { + return [ + { + sticky: true, + label: this.intl.t('column.name'), + valuePath: 'name', + cellComponent: 'table/cell/anchor', + action: this.gatewayActions.transition.view, + resizable: true, + sortable: true, + filterable: true, + filterParam: 'name', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.type'), + valuePath: 'type', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.sandbox'), + valuePath: 'sandbox', + cellComponent: 'table/cell/boolean', + resizable: true, + }, + { + label: this.intl.t('column.created-at'), + valuePath: 'createdAt', + resizable: true, + sortable: true, + }, + ]; + } + +get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.gatewayActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.gatewayActions.transition.create, + }, + ]; + } + +get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.gatewayActions.bulkDelete, + }, + ]; + } +} diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js new file mode 100644 index 0000000..c957ed3 --- /dev/null +++ b/addon/controllers/payments/transactions/index.js @@ -0,0 +1,73 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; + +export default class PaymentsTransactionsIndexController extends Controller { + @service transactionActions; + @service tableContext; + @service intl; + + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; + @tracked page = 1; + @tracked limit = null; + @tracked sort = '-created_at'; + @tracked query = null; + @tracked type = null; + @tracked status = null; + @tracked table = null; +get columns() { + return [ + { + sticky: true, + label: this.intl.t('column.id'), + valuePath: 'public_id', + cellComponent: 'table/cell/anchor', + action: this.transactionActions.transition.view, + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.type'), + valuePath: 'type', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'type', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.amount'), + valuePath: 'amount', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.status'), + valuePath: 'status', + cellComponent: 'table/cell/status', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.created-at'), + valuePath: 'createdAt', + resizable: true, + sortable: true, + }, + ]; + } + +get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.transactionActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + ]; + } + +get bulkActions() { + return []; + } +} diff --git a/addon/controllers/payments/wallets/index.js b/addon/controllers/payments/wallets/index.js new file mode 100644 index 0000000..8288cc1 --- /dev/null +++ b/addon/controllers/payments/wallets/index.js @@ -0,0 +1,80 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; + +export default class PaymentsWalletsIndexController extends Controller { + @service walletActions; + @service tableContext; + @service intl; + + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; + @tracked page = 1; + @tracked limit = null; + @tracked sort = '-created_at'; + @tracked query = null; + @tracked type = null; + @tracked status = null; + @tracked table = null; +get columns() { + return [ + { + sticky: true, + label: this.intl.t('column.name'), + valuePath: 'name', + cellComponent: 'table/cell/anchor', + action: this.walletActions.transition.view, + resizable: true, + sortable: true, + filterable: true, + filterParam: 'name', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.type'), + valuePath: 'type', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.currency'), + valuePath: 'currency', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.balance'), + valuePath: 'balance', + resizable: true, + sortable: true, + }, + { + label: this.intl.t('column.status'), + valuePath: 'status', + cellComponent: 'table/cell/status', + resizable: true, + sortable: true, + }, + ]; + } + +get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.walletActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + ]; + } + +get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.walletActions.bulkDelete, + }, + ]; + } +} diff --git a/addon/services/account-actions.js b/addon/services/account-actions.js new file mode 100644 index 0000000..8d4feca --- /dev/null +++ b/addon/services/account-actions.js @@ -0,0 +1,47 @@ +import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; + +export default class AccountActionsService extends ResourceActionService { + constructor() { + super(...arguments); + this.initialize('ledger-account', { + permissionPrefix: 'ledger', + mountPrefix: 'console.ledger', + }); + } + transition = { + view: (account) => this.transitionTo('console.ledger.accounting.accounts.index.details', account), + create: () => this.transitionTo('console.ledger.accounting.accounts.index.new'), + }; + panel = { + create: (attributes = {}, options = {}) => { + const account = this.createNewInstance(attributes); + return this.resourceContextPanel.open({ + content: 'account/form', + title: this.intl.t('common.create-a-new-resource', { resource: this.intl.t('resource.account')?.toLowerCase() }), + saveOptions: { callback: this.refresh }, + useDefaultSaveTask: true, + account, + ...options, + }); + }, + edit: (account, options = {}) => { + return this.resourceContextPanel.open({ + content: 'account/form', + title: this.intl.t('common.edit-resource-name', { resourceName: account.name }), + useDefaultSaveTask: true, + account, + ...options, + }); + }, + view: (account, options = {}) => { + return this.resourceContextPanel.open({ + account, + tabs: [ + { label: this.intl.t('common.overview'), component: 'account/details' }, + { label: this.intl.t('common.ledger'), component: 'account/ledger' }, + ], + ...options, + }); + }, + }; +} diff --git a/addon/services/gateway-actions.js b/addon/services/gateway-actions.js new file mode 100644 index 0000000..257a430 --- /dev/null +++ b/addon/services/gateway-actions.js @@ -0,0 +1,47 @@ +import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; + +export default class GatewayActionsService extends ResourceActionService { + constructor() { + super(...arguments); + this.initialize('ledger-gateway', { + permissionPrefix: 'ledger', + mountPrefix: 'console.ledger', + }); + } + transition = { + view: (gateway) => this.transitionTo('console.ledger.payments.gateways.index.details', gateway), + create: () => this.transitionTo('console.ledger.payments.gateways.index.new'), + }; + panel = { + create: (attributes = {}, options = {}) => { + const gateway = this.createNewInstance(attributes); + return this.resourceContextPanel.open({ + content: 'gateway/form', + title: this.intl.t('common.create-a-new-resource', { resource: this.intl.t('resource.gateway')?.toLowerCase() }), + saveOptions: { callback: this.refresh }, + useDefaultSaveTask: true, + gateway, + ...options, + }); + }, + edit: (gateway, options = {}) => { + return this.resourceContextPanel.open({ + content: 'gateway/form', + title: this.intl.t('common.edit-resource-name', { resourceName: gateway.name }), + useDefaultSaveTask: true, + gateway, + ...options, + }); + }, + view: (gateway, options = {}) => { + return this.resourceContextPanel.open({ + gateway, + tabs: [ + { label: this.intl.t('common.overview'), component: 'gateway/details' }, + { label: this.intl.t('common.transactions'), component: 'gateway/transactions' }, + ], + ...options, + }); + }, + }; +} diff --git a/addon/services/invoice-actions.js b/addon/services/invoice-actions.js new file mode 100644 index 0000000..dd67711 --- /dev/null +++ b/addon/services/invoice-actions.js @@ -0,0 +1,44 @@ +import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; + +export default class InvoiceActionsService extends ResourceActionService { + constructor() { + super(...arguments); + this.initialize('ledger-invoice', { + permissionPrefix: 'ledger', + mountPrefix: 'console.ledger', + }); + } + transition = { + view: (invoice) => this.transitionTo('console.ledger.billing.invoices.index.details', invoice), + create: () => this.transitionTo('console.ledger.billing.invoices.index.new'), + }; + panel = { + create: (attributes = {}, options = {}) => { + const invoice = this.createNewInstance(attributes); + return this.resourceContextPanel.open({ + content: 'invoice/form', + title: this.intl.t('common.create-a-new-resource', { resource: this.intl.t('resource.invoice')?.toLowerCase() }), + saveOptions: { callback: this.refresh }, + useDefaultSaveTask: true, + invoice, + ...options, + }); + }, + edit: (invoice, options = {}) => { + return this.resourceContextPanel.open({ + content: 'invoice/form', + title: this.intl.t('common.edit-resource-name', { resourceName: invoice.public_id }), + useDefaultSaveTask: true, + invoice, + ...options, + }); + }, + view: (invoice, options = {}) => { + return this.resourceContextPanel.open({ + invoice, + tabs: [{ label: this.intl.t('common.overview'), component: 'invoice/details' }], + ...options, + }); + }, + }; +} diff --git a/addon/services/journal-actions.js b/addon/services/journal-actions.js new file mode 100644 index 0000000..70200e3 --- /dev/null +++ b/addon/services/journal-actions.js @@ -0,0 +1,35 @@ +import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; + +export default class JournalActionsService extends ResourceActionService { + constructor() { + super(...arguments); + this.initialize('ledger-journal', { + permissionPrefix: 'ledger', + mountPrefix: 'console.ledger', + }); + } + transition = { + view: (journal) => this.transitionTo('console.ledger.accounting.journal.index.details', journal), + create: () => this.transitionTo('console.ledger.accounting.journal.index.new'), + }; + panel = { + create: (attributes = {}, options = {}) => { + const journal = this.createNewInstance(attributes); + return this.resourceContextPanel.open({ + content: 'journal/form', + title: this.intl.t('common.create-a-new-resource', { resource: this.intl.t('resource.journal')?.toLowerCase() }), + saveOptions: { callback: this.refresh }, + useDefaultSaveTask: true, + journal, + ...options, + }); + }, + view: (journal, options = {}) => { + return this.resourceContextPanel.open({ + journal, + tabs: [{ label: this.intl.t('common.overview'), component: 'journal/details' }], + ...options, + }); + }, + }; +} diff --git a/addon/services/transaction-actions.js b/addon/services/transaction-actions.js new file mode 100644 index 0000000..a07923f --- /dev/null +++ b/addon/services/transaction-actions.js @@ -0,0 +1,23 @@ +import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; + +export default class TransactionActionsService extends ResourceActionService { + constructor() { + super(...arguments); + this.initialize('ledger-transaction', { + permissionPrefix: 'ledger', + mountPrefix: 'console.ledger', + }); + } + transition = { + view: (transaction) => this.transitionTo('console.ledger.payments.transactions.index.details', transaction), + }; + panel = { + view: (transaction, options = {}) => { + return this.resourceContextPanel.open({ + transaction, + tabs: [{ label: this.intl.t('common.overview'), component: 'transaction/details' }], + ...options, + }); + }, + }; +} diff --git a/addon/services/wallet-actions.js b/addon/services/wallet-actions.js new file mode 100644 index 0000000..d6c1bb7 --- /dev/null +++ b/addon/services/wallet-actions.js @@ -0,0 +1,26 @@ +import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; + +export default class WalletActionsService extends ResourceActionService { + constructor() { + super(...arguments); + this.initialize('ledger-wallet', { + permissionPrefix: 'ledger', + mountPrefix: 'console.ledger', + }); + } + transition = { + view: (wallet) => this.transitionTo('console.ledger.payments.wallets.index.details', wallet), + }; + panel = { + view: (wallet, options = {}) => { + return this.resourceContextPanel.open({ + wallet, + tabs: [ + { label: this.intl.t('common.overview'), component: 'wallet/details' }, + { label: this.intl.t('common.transactions'), component: 'wallet/transactions' }, + ], + ...options, + }); + }, + }; +} diff --git a/addon/services/wallet-transaction-actions.js b/addon/services/wallet-transaction-actions.js new file mode 100644 index 0000000..b123bbf --- /dev/null +++ b/addon/services/wallet-transaction-actions.js @@ -0,0 +1,23 @@ +import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; + +export default class WalletTransactionActionsService extends ResourceActionService { + constructor() { + super(...arguments); + this.initialize('ledger-wallet-transaction', { + permissionPrefix: 'ledger', + mountPrefix: 'console.ledger', + }); + } + transition = { + view: (wallet-transaction) => this.transitionTo('console.ledger.payments.wallets.index.details.transactions', wallet-transaction), + }; + panel = { + view: (walletTransaction, options = {}) => { + return this.resourceContextPanel.open({ + walletTransaction, + tabs: [{ label: this.intl.t('common.overview'), component: 'wallet-transaction/details' }], + ...options, + }); + }, + }; +} diff --git a/addon/templates/accounting/accounts.hbs b/addon/templates/accounting/accounts.hbs index 688ec8d..c24cd68 100644 --- a/addon/templates/accounting/accounts.hbs +++ b/addon/templates/accounting/accounts.hbs @@ -1,15 +1 @@ - - <:actions> -
- -
- -
{{outlet}} diff --git a/addon/templates/accounting/accounts/index.hbs b/addon/templates/accounting/accounts/index.hbs index 0a17908..2e57737 100644 --- a/addon/templates/accounting/accounts/index.hbs +++ b/addon/templates/accounting/accounts/index.hbs @@ -1,15 +1,15 @@ - -
- + {{outlet}} diff --git a/addon/templates/accounting/journal.hbs b/addon/templates/accounting/journal.hbs index 7b20191..c24cd68 100644 --- a/addon/templates/accounting/journal.hbs +++ b/addon/templates/accounting/journal.hbs @@ -1,16 +1 @@ - - <:actions> -
- -
- -
{{outlet}} diff --git a/addon/templates/accounting/journal/index.hbs b/addon/templates/accounting/journal/index.hbs index a701cd3..65a56a5 100644 --- a/addon/templates/accounting/journal/index.hbs +++ b/addon/templates/accounting/journal/index.hbs @@ -1,15 +1,15 @@ - -
- + {{outlet}} diff --git a/addon/templates/billing/invoices.hbs b/addon/templates/billing/invoices.hbs index 51c59dd..c24cd68 100644 --- a/addon/templates/billing/invoices.hbs +++ b/addon/templates/billing/invoices.hbs @@ -1,16 +1 @@ - - <:actions> -
- -
- -
{{outlet}} diff --git a/addon/templates/billing/invoices/index.hbs b/addon/templates/billing/invoices/index.hbs index 64ce498..c76986d 100644 --- a/addon/templates/billing/invoices/index.hbs +++ b/addon/templates/billing/invoices/index.hbs @@ -1,15 +1,15 @@ - -
- + {{outlet}} diff --git a/addon/templates/payments/gateways.hbs b/addon/templates/payments/gateways.hbs index 1e87295..c24cd68 100644 --- a/addon/templates/payments/gateways.hbs +++ b/addon/templates/payments/gateways.hbs @@ -1,15 +1 @@ - - <:actions> -
- -
- -
{{outlet}} diff --git a/addon/templates/payments/gateways/index.hbs b/addon/templates/payments/gateways/index.hbs index 271a689..ce737a5 100644 --- a/addon/templates/payments/gateways/index.hbs +++ b/addon/templates/payments/gateways/index.hbs @@ -1,11 +1,15 @@ - -
- + {{outlet}} diff --git a/addon/templates/payments/transactions.hbs b/addon/templates/payments/transactions.hbs index 5122f48..c24cd68 100644 --- a/addon/templates/payments/transactions.hbs +++ b/addon/templates/payments/transactions.hbs @@ -1,15 +1 @@ - - <:actions> -
- -
- -
{{outlet}} diff --git a/addon/templates/payments/transactions/index.hbs b/addon/templates/payments/transactions/index.hbs index e97af01..13ad561 100644 --- a/addon/templates/payments/transactions/index.hbs +++ b/addon/templates/payments/transactions/index.hbs @@ -1,15 +1,15 @@ - -
- + {{outlet}} diff --git a/addon/templates/payments/wallets.hbs b/addon/templates/payments/wallets.hbs index 9622eea..c24cd68 100644 --- a/addon/templates/payments/wallets.hbs +++ b/addon/templates/payments/wallets.hbs @@ -1,15 +1 @@ - - <:actions> -
- -
- -
{{outlet}} diff --git a/addon/templates/payments/wallets/index.hbs b/addon/templates/payments/wallets/index.hbs index 5367695..944b1fc 100644 --- a/addon/templates/payments/wallets/index.hbs +++ b/addon/templates/payments/wallets/index.hbs @@ -1,15 +1,15 @@ - -
- + {{outlet}} diff --git a/app/services/account-actions.js b/app/services/account-actions.js new file mode 100644 index 0000000..1e7adc5 --- /dev/null +++ b/app/services/account-actions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/services/account-actions'; diff --git a/app/services/gateway-actions.js b/app/services/gateway-actions.js new file mode 100644 index 0000000..710d45e --- /dev/null +++ b/app/services/gateway-actions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/services/gateway-actions'; diff --git a/app/services/invoice-actions.js b/app/services/invoice-actions.js new file mode 100644 index 0000000..c5c12ee --- /dev/null +++ b/app/services/invoice-actions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/services/invoice-actions'; diff --git a/app/services/journal-actions.js b/app/services/journal-actions.js new file mode 100644 index 0000000..0236a5d --- /dev/null +++ b/app/services/journal-actions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/services/journal-actions'; diff --git a/app/services/transaction-actions.js b/app/services/transaction-actions.js new file mode 100644 index 0000000..be4d6db --- /dev/null +++ b/app/services/transaction-actions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/services/transaction-actions'; diff --git a/app/services/wallet-actions.js b/app/services/wallet-actions.js new file mode 100644 index 0000000..674820a --- /dev/null +++ b/app/services/wallet-actions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/services/wallet-actions'; diff --git a/app/services/wallet-transaction-actions.js b/app/services/wallet-transaction-actions.js new file mode 100644 index 0000000..9f9b742 --- /dev/null +++ b/app/services/wallet-transaction-actions.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/services/wallet-transaction-actions'; From c66f06ec851e823de84bf2cae38fee5301ea8240 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 20:38:05 -0500 Subject: [PATCH 026/209] fix: use valid camelCase param name in wallet-transaction-actions transition.view --- addon/services/wallet-transaction-actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/services/wallet-transaction-actions.js b/addon/services/wallet-transaction-actions.js index b123bbf..1cb74dd 100644 --- a/addon/services/wallet-transaction-actions.js +++ b/addon/services/wallet-transaction-actions.js @@ -9,7 +9,7 @@ export default class WalletTransactionActionsService extends ResourceActionServi }); } transition = { - view: (wallet-transaction) => this.transitionTo('console.ledger.payments.wallets.index.details.transactions', wallet-transaction), + view: (walletTransaction) => this.transitionTo('console.ledger.payments.wallets.index.details.transactions', walletTransaction), }; panel = { view: (walletTransaction, options = {}) => { From 7efb91e3de9f9c45307e65824a1e727a0fb6cf46 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 20:41:42 -0500 Subject: [PATCH 027/209] fix: reorganise all route files and app re-exports to match new navigation structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Moved billing/transactions → payments/transactions - Moved wallets → payments/wallets - Moved settings/gateways → payments/gateways - Removed stale billing/transactions, wallets, settings/gateways dirs - Created missing stub routes: accounting/general-ledger, accounting/accounts/index/new, accounting/accounts/index/details/index+ledger, accounting/journal/index/new, accounting/journal/index/details/index, billing/invoices/index/new, billing/invoices/index/details/index+line-items+transactions, reports/income-statement+balance-sheet+trial-balance+cash-flow+ar-aging+wallet-summary, settings/invoice+payment+accounting - Rebuilt app/routes/ledger/ re-exports (43 files) to match all addon/routes --- addon/routes/accounting/accounts/index/details/index.js | 2 ++ addon/routes/accounting/accounts/index/details/ledger.js | 2 ++ addon/routes/accounting/accounts/index/new.js | 2 ++ addon/routes/accounting/general-ledger.js | 2 ++ addon/routes/accounting/journal/index/details/index.js | 2 ++ addon/routes/accounting/journal/index/new.js | 2 ++ addon/routes/billing/invoices/index/details/index.js | 2 ++ addon/routes/billing/invoices/index/details/line-items.js | 2 ++ addon/routes/billing/invoices/index/details/transactions.js | 2 ++ addon/routes/billing/invoices/index/new.js | 2 ++ addon/routes/{settings => payments}/gateways.js | 0 addon/routes/{settings => payments}/gateways/index.js | 0 addon/routes/{settings => payments}/gateways/index/details.js | 0 .../{settings => payments}/gateways/index/details/index.js | 0 .../{settings => payments}/gateways/index/details/webhooks.js | 0 addon/routes/{billing => payments}/transactions.js | 0 addon/routes/{billing => payments}/transactions/index.js | 0 .../routes/{billing => payments}/transactions/index/details.js | 0 addon/routes/{ => payments}/wallets.js | 0 addon/routes/{ => payments}/wallets/index.js | 0 addon/routes/{ => payments}/wallets/index/details.js | 0 addon/routes/{ => payments}/wallets/index/details/index.js | 0 .../routes/{ => payments}/wallets/index/details/transactions.js | 0 addon/routes/reports/ar-aging.js | 2 ++ addon/routes/reports/balance-sheet.js | 2 ++ addon/routes/reports/cash-flow.js | 2 ++ addon/routes/reports/income-statement.js | 2 ++ addon/routes/reports/trial-balance.js | 2 ++ addon/routes/reports/wallet-summary.js | 2 ++ addon/routes/settings/accounting.js | 2 ++ addon/routes/settings/invoice.js | 2 ++ addon/routes/settings/payment.js | 2 ++ app/routes/ledger/accounting/accounts/index/new.js | 1 + app/routes/ledger/accounting/journal/index/new.js | 1 + .../index/details/index.js => billing/invoices/index/new.js} | 2 +- app/routes/ledger/payments/gateways.js | 2 +- app/routes/ledger/payments/gateways/index.js | 2 +- app/routes/ledger/payments/gateways/index/details.js | 2 +- app/routes/ledger/payments/gateways/index/details/index.js | 2 +- app/routes/ledger/payments/gateways/index/details/webhooks.js | 2 +- app/routes/ledger/payments/transactions.js | 2 +- app/routes/ledger/payments/transactions/index.js | 2 +- app/routes/ledger/payments/transactions/index/details.js | 2 +- app/routes/ledger/payments/wallets.js | 2 +- app/routes/ledger/payments/wallets/index.js | 2 +- app/routes/ledger/payments/wallets/index/details.js | 2 +- app/routes/ledger/payments/wallets/index/details/index.js | 2 +- .../ledger/payments/wallets/index/details/transactions.js | 2 +- 48 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 addon/routes/accounting/accounts/index/details/index.js create mode 100644 addon/routes/accounting/accounts/index/details/ledger.js create mode 100644 addon/routes/accounting/accounts/index/new.js create mode 100644 addon/routes/accounting/general-ledger.js create mode 100644 addon/routes/accounting/journal/index/details/index.js create mode 100644 addon/routes/accounting/journal/index/new.js create mode 100644 addon/routes/billing/invoices/index/details/index.js create mode 100644 addon/routes/billing/invoices/index/details/line-items.js create mode 100644 addon/routes/billing/invoices/index/details/transactions.js create mode 100644 addon/routes/billing/invoices/index/new.js rename addon/routes/{settings => payments}/gateways.js (100%) rename addon/routes/{settings => payments}/gateways/index.js (100%) rename addon/routes/{settings => payments}/gateways/index/details.js (100%) rename addon/routes/{settings => payments}/gateways/index/details/index.js (100%) rename addon/routes/{settings => payments}/gateways/index/details/webhooks.js (100%) rename addon/routes/{billing => payments}/transactions.js (100%) rename addon/routes/{billing => payments}/transactions/index.js (100%) rename addon/routes/{billing => payments}/transactions/index/details.js (100%) rename addon/routes/{ => payments}/wallets.js (100%) rename addon/routes/{ => payments}/wallets/index.js (100%) rename addon/routes/{ => payments}/wallets/index/details.js (100%) rename addon/routes/{ => payments}/wallets/index/details/index.js (100%) rename addon/routes/{ => payments}/wallets/index/details/transactions.js (100%) create mode 100644 addon/routes/reports/ar-aging.js create mode 100644 addon/routes/reports/balance-sheet.js create mode 100644 addon/routes/reports/cash-flow.js create mode 100644 addon/routes/reports/income-statement.js create mode 100644 addon/routes/reports/trial-balance.js create mode 100644 addon/routes/reports/wallet-summary.js create mode 100644 addon/routes/settings/accounting.js create mode 100644 addon/routes/settings/invoice.js create mode 100644 addon/routes/settings/payment.js create mode 100644 app/routes/ledger/accounting/accounts/index/new.js create mode 100644 app/routes/ledger/accounting/journal/index/new.js rename app/routes/ledger/{payments/transactions/index/details/index.js => billing/invoices/index/new.js} (64%) diff --git a/addon/routes/accounting/accounts/index/details/index.js b/addon/routes/accounting/accounts/index/details/index.js new file mode 100644 index 0000000..61aba60 --- /dev/null +++ b/addon/routes/accounting/accounts/index/details/index.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class AccountingAccountsIndexDetailsIndexRoute extends Route {} diff --git a/addon/routes/accounting/accounts/index/details/ledger.js b/addon/routes/accounting/accounts/index/details/ledger.js new file mode 100644 index 0000000..b2d138f --- /dev/null +++ b/addon/routes/accounting/accounts/index/details/ledger.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class AccountingAccountsIndexDetailsLedgerRoute extends Route {} diff --git a/addon/routes/accounting/accounts/index/new.js b/addon/routes/accounting/accounts/index/new.js new file mode 100644 index 0000000..0ddd8be --- /dev/null +++ b/addon/routes/accounting/accounts/index/new.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class AccountingAccountsIndexNewRoute extends Route {} diff --git a/addon/routes/accounting/general-ledger.js b/addon/routes/accounting/general-ledger.js new file mode 100644 index 0000000..109e34a --- /dev/null +++ b/addon/routes/accounting/general-ledger.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class AccountingGeneralLedgerRoute extends Route {} diff --git a/addon/routes/accounting/journal/index/details/index.js b/addon/routes/accounting/journal/index/details/index.js new file mode 100644 index 0000000..d97bf7e --- /dev/null +++ b/addon/routes/accounting/journal/index/details/index.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class AccountingJournalIndexDetailsIndexRoute extends Route {} diff --git a/addon/routes/accounting/journal/index/new.js b/addon/routes/accounting/journal/index/new.js new file mode 100644 index 0000000..dab3f96 --- /dev/null +++ b/addon/routes/accounting/journal/index/new.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class AccountingJournalIndexNewRoute extends Route {} diff --git a/addon/routes/billing/invoices/index/details/index.js b/addon/routes/billing/invoices/index/details/index.js new file mode 100644 index 0000000..74e7c7c --- /dev/null +++ b/addon/routes/billing/invoices/index/details/index.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class BillingInvoicesIndexDetailsIndexRoute extends Route {} diff --git a/addon/routes/billing/invoices/index/details/line-items.js b/addon/routes/billing/invoices/index/details/line-items.js new file mode 100644 index 0000000..ee02a84 --- /dev/null +++ b/addon/routes/billing/invoices/index/details/line-items.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class BillingInvoicesIndexDetailsLineItemsRoute extends Route {} diff --git a/addon/routes/billing/invoices/index/details/transactions.js b/addon/routes/billing/invoices/index/details/transactions.js new file mode 100644 index 0000000..f63e6e6 --- /dev/null +++ b/addon/routes/billing/invoices/index/details/transactions.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class BillingInvoicesIndexDetailsTransactionsRoute extends Route {} diff --git a/addon/routes/billing/invoices/index/new.js b/addon/routes/billing/invoices/index/new.js new file mode 100644 index 0000000..6ead49c --- /dev/null +++ b/addon/routes/billing/invoices/index/new.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class BillingInvoicesIndexNewRoute extends Route {} diff --git a/addon/routes/settings/gateways.js b/addon/routes/payments/gateways.js similarity index 100% rename from addon/routes/settings/gateways.js rename to addon/routes/payments/gateways.js diff --git a/addon/routes/settings/gateways/index.js b/addon/routes/payments/gateways/index.js similarity index 100% rename from addon/routes/settings/gateways/index.js rename to addon/routes/payments/gateways/index.js diff --git a/addon/routes/settings/gateways/index/details.js b/addon/routes/payments/gateways/index/details.js similarity index 100% rename from addon/routes/settings/gateways/index/details.js rename to addon/routes/payments/gateways/index/details.js diff --git a/addon/routes/settings/gateways/index/details/index.js b/addon/routes/payments/gateways/index/details/index.js similarity index 100% rename from addon/routes/settings/gateways/index/details/index.js rename to addon/routes/payments/gateways/index/details/index.js diff --git a/addon/routes/settings/gateways/index/details/webhooks.js b/addon/routes/payments/gateways/index/details/webhooks.js similarity index 100% rename from addon/routes/settings/gateways/index/details/webhooks.js rename to addon/routes/payments/gateways/index/details/webhooks.js diff --git a/addon/routes/billing/transactions.js b/addon/routes/payments/transactions.js similarity index 100% rename from addon/routes/billing/transactions.js rename to addon/routes/payments/transactions.js diff --git a/addon/routes/billing/transactions/index.js b/addon/routes/payments/transactions/index.js similarity index 100% rename from addon/routes/billing/transactions/index.js rename to addon/routes/payments/transactions/index.js diff --git a/addon/routes/billing/transactions/index/details.js b/addon/routes/payments/transactions/index/details.js similarity index 100% rename from addon/routes/billing/transactions/index/details.js rename to addon/routes/payments/transactions/index/details.js diff --git a/addon/routes/wallets.js b/addon/routes/payments/wallets.js similarity index 100% rename from addon/routes/wallets.js rename to addon/routes/payments/wallets.js diff --git a/addon/routes/wallets/index.js b/addon/routes/payments/wallets/index.js similarity index 100% rename from addon/routes/wallets/index.js rename to addon/routes/payments/wallets/index.js diff --git a/addon/routes/wallets/index/details.js b/addon/routes/payments/wallets/index/details.js similarity index 100% rename from addon/routes/wallets/index/details.js rename to addon/routes/payments/wallets/index/details.js diff --git a/addon/routes/wallets/index/details/index.js b/addon/routes/payments/wallets/index/details/index.js similarity index 100% rename from addon/routes/wallets/index/details/index.js rename to addon/routes/payments/wallets/index/details/index.js diff --git a/addon/routes/wallets/index/details/transactions.js b/addon/routes/payments/wallets/index/details/transactions.js similarity index 100% rename from addon/routes/wallets/index/details/transactions.js rename to addon/routes/payments/wallets/index/details/transactions.js diff --git a/addon/routes/reports/ar-aging.js b/addon/routes/reports/ar-aging.js new file mode 100644 index 0000000..b9e50cc --- /dev/null +++ b/addon/routes/reports/ar-aging.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class ReportsArAgingRoute extends Route {} diff --git a/addon/routes/reports/balance-sheet.js b/addon/routes/reports/balance-sheet.js new file mode 100644 index 0000000..b449bbc --- /dev/null +++ b/addon/routes/reports/balance-sheet.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class ReportsBalanceSheetRoute extends Route {} diff --git a/addon/routes/reports/cash-flow.js b/addon/routes/reports/cash-flow.js new file mode 100644 index 0000000..5422c80 --- /dev/null +++ b/addon/routes/reports/cash-flow.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class ReportsCashFlowRoute extends Route {} diff --git a/addon/routes/reports/income-statement.js b/addon/routes/reports/income-statement.js new file mode 100644 index 0000000..17ca07e --- /dev/null +++ b/addon/routes/reports/income-statement.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class ReportsIncomeStatementRoute extends Route {} diff --git a/addon/routes/reports/trial-balance.js b/addon/routes/reports/trial-balance.js new file mode 100644 index 0000000..f846b11 --- /dev/null +++ b/addon/routes/reports/trial-balance.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class ReportsTrialBalanceRoute extends Route {} diff --git a/addon/routes/reports/wallet-summary.js b/addon/routes/reports/wallet-summary.js new file mode 100644 index 0000000..54efcaf --- /dev/null +++ b/addon/routes/reports/wallet-summary.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class ReportsWalletSummaryRoute extends Route {} diff --git a/addon/routes/settings/accounting.js b/addon/routes/settings/accounting.js new file mode 100644 index 0000000..5140d20 --- /dev/null +++ b/addon/routes/settings/accounting.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class SettingsAccountingRoute extends Route {} diff --git a/addon/routes/settings/invoice.js b/addon/routes/settings/invoice.js new file mode 100644 index 0000000..7bece02 --- /dev/null +++ b/addon/routes/settings/invoice.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class SettingsInvoiceRoute extends Route {} diff --git a/addon/routes/settings/payment.js b/addon/routes/settings/payment.js new file mode 100644 index 0000000..d8cb6b7 --- /dev/null +++ b/addon/routes/settings/payment.js @@ -0,0 +1,2 @@ +import Route from '@ember/routing/route'; +export default class SettingsPaymentRoute extends Route {} diff --git a/app/routes/ledger/accounting/accounts/index/new.js b/app/routes/ledger/accounting/accounts/index/new.js new file mode 100644 index 0000000..2180fe7 --- /dev/null +++ b/app/routes/ledger/accounting/accounts/index/new.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/accounts/index/new'; diff --git a/app/routes/ledger/accounting/journal/index/new.js b/app/routes/ledger/accounting/journal/index/new.js new file mode 100644 index 0000000..be603d6 --- /dev/null +++ b/app/routes/ledger/accounting/journal/index/new.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/ledger-engine/routes/accounting/journal/index/new'; diff --git a/app/routes/ledger/payments/transactions/index/details/index.js b/app/routes/ledger/billing/invoices/index/new.js similarity index 64% rename from app/routes/ledger/payments/transactions/index/details/index.js rename to app/routes/ledger/billing/invoices/index/new.js index 05f1116..c7923da 100644 --- a/app/routes/ledger/payments/transactions/index/details/index.js +++ b/app/routes/ledger/billing/invoices/index/new.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/billing/transactions/index/details/index'; +export { default } from '@fleetbase/ledger-engine/routes/billing/invoices/index/new'; diff --git a/app/routes/ledger/payments/gateways.js b/app/routes/ledger/payments/gateways.js index d9533b0..6381d3f 100644 --- a/app/routes/ledger/payments/gateways.js +++ b/app/routes/ledger/payments/gateways.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/settings/gateways'; +export { default } from '@fleetbase/ledger-engine/routes/payments/gateways'; diff --git a/app/routes/ledger/payments/gateways/index.js b/app/routes/ledger/payments/gateways/index.js index 342a46a..7d48ed5 100644 --- a/app/routes/ledger/payments/gateways/index.js +++ b/app/routes/ledger/payments/gateways/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index'; +export { default } from '@fleetbase/ledger-engine/routes/payments/gateways/index'; diff --git a/app/routes/ledger/payments/gateways/index/details.js b/app/routes/ledger/payments/gateways/index/details.js index de1d4e8..a6d1773 100644 --- a/app/routes/ledger/payments/gateways/index/details.js +++ b/app/routes/ledger/payments/gateways/index/details.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index/details'; +export { default } from '@fleetbase/ledger-engine/routes/payments/gateways/index/details'; diff --git a/app/routes/ledger/payments/gateways/index/details/index.js b/app/routes/ledger/payments/gateways/index/details/index.js index 9b82de0..2cc1f62 100644 --- a/app/routes/ledger/payments/gateways/index/details/index.js +++ b/app/routes/ledger/payments/gateways/index/details/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index/details/index'; +export { default } from '@fleetbase/ledger-engine/routes/payments/gateways/index/details/index'; diff --git a/app/routes/ledger/payments/gateways/index/details/webhooks.js b/app/routes/ledger/payments/gateways/index/details/webhooks.js index 46d5de4..d961979 100644 --- a/app/routes/ledger/payments/gateways/index/details/webhooks.js +++ b/app/routes/ledger/payments/gateways/index/details/webhooks.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/settings/gateways/index/details/webhooks'; +export { default } from '@fleetbase/ledger-engine/routes/payments/gateways/index/details/webhooks'; diff --git a/app/routes/ledger/payments/transactions.js b/app/routes/ledger/payments/transactions.js index 49f8d9f..ad6e494 100644 --- a/app/routes/ledger/payments/transactions.js +++ b/app/routes/ledger/payments/transactions.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/billing/transactions'; +export { default } from '@fleetbase/ledger-engine/routes/payments/transactions'; diff --git a/app/routes/ledger/payments/transactions/index.js b/app/routes/ledger/payments/transactions/index.js index 93bc2d6..f34ce01 100644 --- a/app/routes/ledger/payments/transactions/index.js +++ b/app/routes/ledger/payments/transactions/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/billing/transactions/index'; +export { default } from '@fleetbase/ledger-engine/routes/payments/transactions/index'; diff --git a/app/routes/ledger/payments/transactions/index/details.js b/app/routes/ledger/payments/transactions/index/details.js index a9f7ca2..df08878 100644 --- a/app/routes/ledger/payments/transactions/index/details.js +++ b/app/routes/ledger/payments/transactions/index/details.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/billing/transactions/index/details'; +export { default } from '@fleetbase/ledger-engine/routes/payments/transactions/index/details'; diff --git a/app/routes/ledger/payments/wallets.js b/app/routes/ledger/payments/wallets.js index f7ab727..d4d1094 100644 --- a/app/routes/ledger/payments/wallets.js +++ b/app/routes/ledger/payments/wallets.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/wallets'; +export { default } from '@fleetbase/ledger-engine/routes/payments/wallets'; diff --git a/app/routes/ledger/payments/wallets/index.js b/app/routes/ledger/payments/wallets/index.js index 43f2118..b08e40e 100644 --- a/app/routes/ledger/payments/wallets/index.js +++ b/app/routes/ledger/payments/wallets/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/wallets/index'; +export { default } from '@fleetbase/ledger-engine/routes/payments/wallets/index'; diff --git a/app/routes/ledger/payments/wallets/index/details.js b/app/routes/ledger/payments/wallets/index/details.js index 71dee86..65d3d95 100644 --- a/app/routes/ledger/payments/wallets/index/details.js +++ b/app/routes/ledger/payments/wallets/index/details.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/wallets/index/details'; +export { default } from '@fleetbase/ledger-engine/routes/payments/wallets/index/details'; diff --git a/app/routes/ledger/payments/wallets/index/details/index.js b/app/routes/ledger/payments/wallets/index/details/index.js index fb2a5ea..2349af6 100644 --- a/app/routes/ledger/payments/wallets/index/details/index.js +++ b/app/routes/ledger/payments/wallets/index/details/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/wallets/index/details/index'; +export { default } from '@fleetbase/ledger-engine/routes/payments/wallets/index/details/index'; diff --git a/app/routes/ledger/payments/wallets/index/details/transactions.js b/app/routes/ledger/payments/wallets/index/details/transactions.js index d12a1f3..e0d8917 100644 --- a/app/routes/ledger/payments/wallets/index/details/transactions.js +++ b/app/routes/ledger/payments/wallets/index/details/transactions.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/routes/wallets/index/details/transactions'; +export { default } from '@fleetbase/ledger-engine/routes/payments/wallets/index/details/transactions'; From 294bae47402f3339385b833200a7a777d3d63c63 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Mon, 2 Mar 2026 09:43:22 +0800 Subject: [PATCH 028/209] ran ptettier --- addon/controllers/accounting/accounts/index.js | 6 +++--- addon/controllers/accounting/journal/index.js | 6 +++--- addon/controllers/billing/invoices/index.js | 6 +++--- addon/controllers/payments/gateways/index.js | 6 +++--- addon/controllers/payments/transactions/index.js | 6 +++--- addon/controllers/payments/wallets/index.js | 6 +++--- addon/controllers/settings/gateways/index.js | 4 +--- addon/serializers/ledger.js | 4 +++- addon/services/transaction-actions.js | 2 ++ 9 files changed, 24 insertions(+), 22 deletions(-) diff --git a/addon/controllers/accounting/accounts/index.js b/addon/controllers/accounting/accounts/index.js index 338dd28..d707e88 100644 --- a/addon/controllers/accounting/accounts/index.js +++ b/addon/controllers/accounting/accounts/index.js @@ -15,7 +15,7 @@ export default class AccountingAccountsIndexController extends Controller { @tracked type = null; @tracked status = null; @tracked table = null; -get columns() { + get columns() { return [ { sticky: true, @@ -60,7 +60,7 @@ get columns() { ]; } -get actionButtons() { + get actionButtons() { return [ { icon: 'refresh', @@ -76,7 +76,7 @@ get actionButtons() { ]; } -get bulkActions() { + get bulkActions() { const selected = this.tableContext.getSelectedRows(); return [ { diff --git a/addon/controllers/accounting/journal/index.js b/addon/controllers/accounting/journal/index.js index a12af51..542d1d4 100644 --- a/addon/controllers/accounting/journal/index.js +++ b/addon/controllers/accounting/journal/index.js @@ -14,7 +14,7 @@ export default class AccountingJournalIndexController extends Controller { @tracked query = null; @tracked entry_source = null; @tracked table = null; -get columns() { + get columns() { return [ { sticky: true, @@ -59,7 +59,7 @@ get columns() { ]; } -get actionButtons() { + get actionButtons() { return [ { icon: 'refresh', @@ -75,7 +75,7 @@ get actionButtons() { ]; } -get bulkActions() { + get bulkActions() { const selected = this.tableContext.getSelectedRows(); return [ { diff --git a/addon/controllers/billing/invoices/index.js b/addon/controllers/billing/invoices/index.js index cf1642c..660eb7a 100644 --- a/addon/controllers/billing/invoices/index.js +++ b/addon/controllers/billing/invoices/index.js @@ -15,7 +15,7 @@ export default class BillingInvoicesIndexController extends Controller { @tracked status = null; @tracked customer_uuid = null; @tracked table = null; -get columns() { + get columns() { return [ { sticky: true, @@ -60,7 +60,7 @@ get columns() { ]; } -get actionButtons() { + get actionButtons() { return [ { icon: 'refresh', @@ -76,7 +76,7 @@ get actionButtons() { ]; } -get bulkActions() { + get bulkActions() { const selected = this.tableContext.getSelectedRows(); return [ { diff --git a/addon/controllers/payments/gateways/index.js b/addon/controllers/payments/gateways/index.js index 76e2223..7dfdf98 100644 --- a/addon/controllers/payments/gateways/index.js +++ b/addon/controllers/payments/gateways/index.js @@ -14,7 +14,7 @@ export default class PaymentsGatewaysIndexController extends Controller { @tracked query = null; @tracked type = null; @tracked table = null; -get columns() { + get columns() { return [ { sticky: true, @@ -49,7 +49,7 @@ get columns() { ]; } -get actionButtons() { + get actionButtons() { return [ { icon: 'refresh', @@ -65,7 +65,7 @@ get actionButtons() { ]; } -get bulkActions() { + get bulkActions() { const selected = this.tableContext.getSelectedRows(); return [ { diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js index c957ed3..a57046d 100644 --- a/addon/controllers/payments/transactions/index.js +++ b/addon/controllers/payments/transactions/index.js @@ -15,7 +15,7 @@ export default class PaymentsTransactionsIndexController extends Controller { @tracked type = null; @tracked status = null; @tracked table = null; -get columns() { + get columns() { return [ { sticky: true, @@ -57,7 +57,7 @@ get columns() { ]; } -get actionButtons() { + get actionButtons() { return [ { icon: 'refresh', @@ -67,7 +67,7 @@ get actionButtons() { ]; } -get bulkActions() { + get bulkActions() { return []; } } diff --git a/addon/controllers/payments/wallets/index.js b/addon/controllers/payments/wallets/index.js index 8288cc1..e7f54e3 100644 --- a/addon/controllers/payments/wallets/index.js +++ b/addon/controllers/payments/wallets/index.js @@ -15,7 +15,7 @@ export default class PaymentsWalletsIndexController extends Controller { @tracked type = null; @tracked status = null; @tracked table = null; -get columns() { + get columns() { return [ { sticky: true, @@ -57,7 +57,7 @@ get columns() { ]; } -get actionButtons() { + get actionButtons() { return [ { icon: 'refresh', @@ -67,7 +67,7 @@ get actionButtons() { ]; } -get bulkActions() { + get bulkActions() { const selected = this.tableContext.getSelectedRows(); return [ { diff --git a/addon/controllers/settings/gateways/index.js b/addon/controllers/settings/gateways/index.js index 039db5d..16e02f2 100644 --- a/addon/controllers/settings/gateways/index.js +++ b/addon/controllers/settings/gateways/index.js @@ -23,9 +23,7 @@ export default class SettingsGatewaysIndexController extends Controller { ]; get actionButtons() { - return [ - { label: 'Add Gateway', icon: 'plus', type: 'primary', onClick: this.addGateway }, - ]; + return [{ label: 'Add Gateway', icon: 'plus', type: 'primary', onClick: this.addGateway }]; } @task({ restartable: true }) *search(query) { diff --git a/addon/serializers/ledger.js b/addon/serializers/ledger.js index a9bbb3d..0eb5db1 100644 --- a/addon/serializers/ledger.js +++ b/addon/serializers/ledger.js @@ -31,6 +31,8 @@ export default class LedgerSerializer extends LedgerSerializerBase { * snake_case to match what the backend expects. */ payloadKeyFromModelName(modelName) { - return underscore(modelName).replace(/^ledger_/, '').toLowerCase(); + return underscore(modelName) + .replace(/^ledger_/, '') + .toLowerCase(); } } diff --git a/addon/services/transaction-actions.js b/addon/services/transaction-actions.js index a07923f..30541e4 100644 --- a/addon/services/transaction-actions.js +++ b/addon/services/transaction-actions.js @@ -8,9 +8,11 @@ export default class TransactionActionsService extends ResourceActionService { mountPrefix: 'console.ledger', }); } + transition = { view: (transaction) => this.transitionTo('console.ledger.payments.transactions.index.details', transaction), }; + panel = { view: (transaction, options = {}) => { return this.resourceContextPanel.open({ From f65e767614d7bdd9e32b8decb416b983018c4d48 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 20:46:46 -0500 Subject: [PATCH 029/209] fix: correct stale route class names to match new file paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 13 route files had class names from their old locations: - BillingTransactions* → PaymentsTransactions* - Wallets* → PaymentsWallets* - SettingsGateways* → PaymentsGateways* --- addon/routes/payments/gateways.js | 2 +- addon/routes/payments/gateways/index.js | 2 +- addon/routes/payments/gateways/index/details.js | 2 +- addon/routes/payments/gateways/index/details/index.js | 2 +- addon/routes/payments/gateways/index/details/webhooks.js | 2 +- addon/routes/payments/transactions.js | 2 +- addon/routes/payments/transactions/index.js | 2 +- addon/routes/payments/transactions/index/details.js | 2 +- addon/routes/payments/wallets.js | 2 +- addon/routes/payments/wallets/index.js | 2 +- addon/routes/payments/wallets/index/details.js | 2 +- addon/routes/payments/wallets/index/details/index.js | 2 +- addon/routes/payments/wallets/index/details/transactions.js | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/addon/routes/payments/gateways.js b/addon/routes/payments/gateways.js index 193dcef..c945c2a 100644 --- a/addon/routes/payments/gateways.js +++ b/addon/routes/payments/gateways.js @@ -1,3 +1,3 @@ import Route from '@ember/routing/route'; -export default class SettingsGatewaysRoute extends Route {} +export default class PaymentsGatewaysRoute extends Route {} diff --git a/addon/routes/payments/gateways/index.js b/addon/routes/payments/gateways/index.js index b41ccc0..685a0bb 100644 --- a/addon/routes/payments/gateways/index.js +++ b/addon/routes/payments/gateways/index.js @@ -1,7 +1,7 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -export default class SettingsGatewaysIndexRoute extends Route { +export default class PaymentsGatewaysIndexRoute extends Route { @service store; model() { diff --git a/addon/routes/payments/gateways/index/details.js b/addon/routes/payments/gateways/index/details.js index d723e63..97d2763 100644 --- a/addon/routes/payments/gateways/index/details.js +++ b/addon/routes/payments/gateways/index/details.js @@ -1,7 +1,7 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -export default class SettingsGatewaysIndexDetailsRoute extends Route { +export default class PaymentsGatewaysIndexDetailsRoute extends Route { @service store; model({ id }) { diff --git a/addon/routes/payments/gateways/index/details/index.js b/addon/routes/payments/gateways/index/details/index.js index a7c4713..6e4e7c5 100644 --- a/addon/routes/payments/gateways/index/details/index.js +++ b/addon/routes/payments/gateways/index/details/index.js @@ -1,2 +1,2 @@ import Route from '@ember/routing/route'; -export default class SettingsGatewaysIndexDetailsIndexRoute extends Route {} +export default class PaymentsGatewaysIndexDetailsIndexRoute extends Route {} diff --git a/addon/routes/payments/gateways/index/details/webhooks.js b/addon/routes/payments/gateways/index/details/webhooks.js index 5f240fa..368a36c 100644 --- a/addon/routes/payments/gateways/index/details/webhooks.js +++ b/addon/routes/payments/gateways/index/details/webhooks.js @@ -1,2 +1,2 @@ import Route from '@ember/routing/route'; -export default class SettingsGatewaysIndexDetailsWebhooksRoute extends Route {} +export default class PaymentsGatewaysIndexDetailsWebhooksRoute extends Route {} diff --git a/addon/routes/payments/transactions.js b/addon/routes/payments/transactions.js index f9ba322..3ccf50b 100644 --- a/addon/routes/payments/transactions.js +++ b/addon/routes/payments/transactions.js @@ -1,3 +1,3 @@ import Route from '@ember/routing/route'; -export default class BillingTransactionsRoute extends Route {} +export default class PaymentsTransactionsRoute extends Route {} diff --git a/addon/routes/payments/transactions/index.js b/addon/routes/payments/transactions/index.js index 50781e9..62e08a9 100644 --- a/addon/routes/payments/transactions/index.js +++ b/addon/routes/payments/transactions/index.js @@ -1,7 +1,7 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -export default class BillingTransactionsIndexRoute extends Route { +export default class PaymentsTransactionsIndexRoute extends Route { @service store; queryParams = { diff --git a/addon/routes/payments/transactions/index/details.js b/addon/routes/payments/transactions/index/details.js index 03321df..50b8c17 100644 --- a/addon/routes/payments/transactions/index/details.js +++ b/addon/routes/payments/transactions/index/details.js @@ -1,7 +1,7 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -export default class BillingTransactionsIndexDetailsRoute extends Route { +export default class PaymentsTransactionsIndexDetailsRoute extends Route { @service store; model({ id }) { diff --git a/addon/routes/payments/wallets.js b/addon/routes/payments/wallets.js index a772400..28123d4 100644 --- a/addon/routes/payments/wallets.js +++ b/addon/routes/payments/wallets.js @@ -1,2 +1,2 @@ import Route from '@ember/routing/route'; -export default class WalletsRoute extends Route {} +export default class PaymentsWalletsRoute extends Route {} diff --git a/addon/routes/payments/wallets/index.js b/addon/routes/payments/wallets/index.js index be121a5..7521b7d 100644 --- a/addon/routes/payments/wallets/index.js +++ b/addon/routes/payments/wallets/index.js @@ -1,7 +1,7 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -export default class WalletsIndexRoute extends Route { +export default class PaymentsWalletsIndexRoute extends Route { @service store; queryParams = { diff --git a/addon/routes/payments/wallets/index/details.js b/addon/routes/payments/wallets/index/details.js index 62b4e96..fb78f33 100644 --- a/addon/routes/payments/wallets/index/details.js +++ b/addon/routes/payments/wallets/index/details.js @@ -1,7 +1,7 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -export default class WalletsIndexDetailsRoute extends Route { +export default class PaymentsWalletsIndexDetailsRoute extends Route { @service store; model({ id }) { diff --git a/addon/routes/payments/wallets/index/details/index.js b/addon/routes/payments/wallets/index/details/index.js index 12db618..cce1e42 100644 --- a/addon/routes/payments/wallets/index/details/index.js +++ b/addon/routes/payments/wallets/index/details/index.js @@ -1,2 +1,2 @@ import Route from '@ember/routing/route'; -export default class WalletsIndexDetailsIndexRoute extends Route {} +export default class PaymentsWalletsIndexDetailsIndexRoute extends Route {} diff --git a/addon/routes/payments/wallets/index/details/transactions.js b/addon/routes/payments/wallets/index/details/transactions.js index f051e40..8162dd7 100644 --- a/addon/routes/payments/wallets/index/details/transactions.js +++ b/addon/routes/payments/wallets/index/details/transactions.js @@ -1,2 +1,2 @@ import Route from '@ember/routing/route'; -export default class WalletsIndexDetailsTransactionsRoute extends Route {} +export default class PaymentsWalletsIndexDetailsTransactionsRoute extends Route {} From 59e8bb1fa3a3b98b3acf7a52009531c0486132e8 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 21:10:13 -0500 Subject: [PATCH 030/209] fix: correct all index controllers - limit=30, getter order, whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - @tracked limit = null → @tracked limit = 30 on all 6 index controllers - Removed blank lines between consecutive @service and @tracked declarations - Added blank line between last @tracked and first getter - Reordered getters: actionButtons → bulkActions → columns (with blank lines between) - Affected: billing/invoices, payments/transactions, payments/wallets, payments/gateways, accounting/accounts, accounting/journal --- .../controllers/accounting/accounts/index.js | 57 ++++++------- addon/controllers/accounting/journal/index.js | 57 ++++++------- addon/controllers/billing/invoices/index.js | 57 ++++++------- addon/controllers/payments/gateways/index.js | 79 +++++++++++-------- .../payments/transactions/index.js | 49 +++++++----- addon/controllers/payments/wallets/index.js | 54 +++++++------ 6 files changed, 195 insertions(+), 158 deletions(-) diff --git a/addon/controllers/accounting/accounts/index.js b/addon/controllers/accounting/accounts/index.js index d707e88..7c50013 100644 --- a/addon/controllers/accounting/accounts/index.js +++ b/addon/controllers/accounting/accounts/index.js @@ -9,12 +9,40 @@ export default class AccountingAccountsIndexController extends Controller { @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; @tracked page = 1; - @tracked limit = null; + @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked type = null; @tracked status = null; @tracked table = null; + + get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.accountActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.accountActions.transition.create, + }, + ]; + } + + get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.accountActions.bulkDelete, + }, + ]; + } + get columns() { return [ { @@ -59,31 +87,4 @@ export default class AccountingAccountsIndexController extends Controller { }, ]; } - - get actionButtons() { - return [ - { - icon: 'refresh', - onClick: this.accountActions.refresh, - helpText: this.intl.t('common.refresh'), - }, - { - text: this.intl.t('common.new'), - type: 'primary', - icon: 'plus', - onClick: this.accountActions.transition.create, - }, - ]; - } - - get bulkActions() { - const selected = this.tableContext.getSelectedRows(); - return [ - { - label: this.intl.t('common.delete-selected-count', { count: selected.length }), - class: 'text-red-500', - fn: this.accountActions.bulkDelete, - }, - ]; - } } diff --git a/addon/controllers/accounting/journal/index.js b/addon/controllers/accounting/journal/index.js index 542d1d4..498df9a 100644 --- a/addon/controllers/accounting/journal/index.js +++ b/addon/controllers/accounting/journal/index.js @@ -9,11 +9,39 @@ export default class AccountingJournalIndexController extends Controller { @tracked queryParams = ['page', 'limit', 'sort', 'query', 'entry_source']; @tracked page = 1; - @tracked limit = null; + @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked entry_source = null; @tracked table = null; + + get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.journalActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.journalActions.transition.create, + }, + ]; + } + + get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.journalActions.bulkDelete, + }, + ]; + } + get columns() { return [ { @@ -58,31 +86,4 @@ export default class AccountingJournalIndexController extends Controller { }, ]; } - - get actionButtons() { - return [ - { - icon: 'refresh', - onClick: this.journalActions.refresh, - helpText: this.intl.t('common.refresh'), - }, - { - text: this.intl.t('common.new'), - type: 'primary', - icon: 'plus', - onClick: this.journalActions.transition.create, - }, - ]; - } - - get bulkActions() { - const selected = this.tableContext.getSelectedRows(); - return [ - { - label: this.intl.t('common.delete-selected-count', { count: selected.length }), - class: 'text-red-500', - fn: this.journalActions.bulkDelete, - }, - ]; - } } diff --git a/addon/controllers/billing/invoices/index.js b/addon/controllers/billing/invoices/index.js index 660eb7a..88ad238 100644 --- a/addon/controllers/billing/invoices/index.js +++ b/addon/controllers/billing/invoices/index.js @@ -9,12 +9,40 @@ export default class BillingInvoicesIndexController extends Controller { @tracked queryParams = ['page', 'limit', 'sort', 'query', 'status', 'customer_uuid']; @tracked page = 1; - @tracked limit = null; + @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked status = null; @tracked customer_uuid = null; @tracked table = null; + + get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.invoiceActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.invoiceActions.transition.create, + }, + ]; + } + + get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.invoiceActions.bulkDelete, + }, + ]; + } + get columns() { return [ { @@ -59,31 +87,4 @@ export default class BillingInvoicesIndexController extends Controller { }, ]; } - - get actionButtons() { - return [ - { - icon: 'refresh', - onClick: this.invoiceActions.refresh, - helpText: this.intl.t('common.refresh'), - }, - { - text: this.intl.t('common.new'), - type: 'primary', - icon: 'plus', - onClick: this.invoiceActions.transition.create, - }, - ]; - } - - get bulkActions() { - const selected = this.tableContext.getSelectedRows(); - return [ - { - label: this.intl.t('common.delete-selected-count', { count: selected.length }), - class: 'text-red-500', - fn: this.invoiceActions.bulkDelete, - }, - ]; - } } diff --git a/addon/controllers/payments/gateways/index.js b/addon/controllers/payments/gateways/index.js index 7dfdf98..df55633 100644 --- a/addon/controllers/payments/gateways/index.js +++ b/addon/controllers/payments/gateways/index.js @@ -9,11 +9,39 @@ export default class PaymentsGatewaysIndexController extends Controller { @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type']; @tracked page = 1; - @tracked limit = null; + @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked type = null; @tracked table = null; + + get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.gatewayActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.gatewayActions.transition.create, + }, + ]; + } + + get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.gatewayActions.bulkDelete, + }, + ]; + } + get columns() { return [ { @@ -29,49 +57,32 @@ export default class PaymentsGatewaysIndexController extends Controller { filterComponent: 'filter/string', }, { - label: this.intl.t('column.type'), - valuePath: 'type', + label: this.intl.t('column.driver'), + valuePath: 'driver', resizable: true, sortable: true, + filterable: true, + filterParam: 'type', + filterComponent: 'filter/string', }, { - label: this.intl.t('column.sandbox'), - valuePath: 'sandbox', - cellComponent: 'table/cell/boolean', - resizable: true, - }, - { - label: this.intl.t('column.created-at'), - valuePath: 'createdAt', + label: this.intl.t('column.environment'), + valuePath: 'environment', resizable: true, sortable: true, }, - ]; - } - - get actionButtons() { - return [ { - icon: 'refresh', - onClick: this.gatewayActions.refresh, - helpText: this.intl.t('common.refresh'), - }, - { - text: this.intl.t('common.new'), - type: 'primary', - icon: 'plus', - onClick: this.gatewayActions.transition.create, + label: this.intl.t('column.default'), + valuePath: 'is_default', + cellComponent: 'table/cell/boolean', + resizable: true, }, - ]; - } - - get bulkActions() { - const selected = this.tableContext.getSelectedRows(); - return [ { - label: this.intl.t('common.delete-selected-count', { count: selected.length }), - class: 'text-red-500', - fn: this.gatewayActions.bulkDelete, + label: this.intl.t('column.status'), + valuePath: 'status', + cellComponent: 'table/cell/status', + resizable: true, + sortable: true, }, ]; } diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js index a57046d..3ad5a7e 100644 --- a/addon/controllers/payments/transactions/index.js +++ b/addon/controllers/payments/transactions/index.js @@ -9,12 +9,27 @@ export default class PaymentsTransactionsIndexController extends Controller { @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; @tracked page = 1; - @tracked limit = null; + @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked type = null; @tracked status = null; @tracked table = null; + + get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.transactionActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + ]; + } + + get bulkActions() { + return []; + } + get columns() { return [ { @@ -25,6 +40,9 @@ export default class PaymentsTransactionsIndexController extends Controller { action: this.transactionActions.transition.view, resizable: true, sortable: true, + filterable: true, + filterParam: 'public_id', + filterComponent: 'filter/string', }, { label: this.intl.t('column.type'), @@ -35,6 +53,16 @@ export default class PaymentsTransactionsIndexController extends Controller { filterParam: 'type', filterComponent: 'filter/string', }, + { + label: this.intl.t('column.status'), + valuePath: 'status', + cellComponent: 'table/cell/status', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'status', + filterComponent: 'filter/string', + }, { label: this.intl.t('column.amount'), valuePath: 'amount', @@ -42,9 +70,8 @@ export default class PaymentsTransactionsIndexController extends Controller { sortable: true, }, { - label: this.intl.t('column.status'), - valuePath: 'status', - cellComponent: 'table/cell/status', + label: this.intl.t('column.currency'), + valuePath: 'currency', resizable: true, sortable: true, }, @@ -56,18 +83,4 @@ export default class PaymentsTransactionsIndexController extends Controller { }, ]; } - - get actionButtons() { - return [ - { - icon: 'refresh', - onClick: this.transactionActions.refresh, - helpText: this.intl.t('common.refresh'), - }, - ]; - } - - get bulkActions() { - return []; - } } diff --git a/addon/controllers/payments/wallets/index.js b/addon/controllers/payments/wallets/index.js index e7f54e3..f9a0d84 100644 --- a/addon/controllers/payments/wallets/index.js +++ b/addon/controllers/payments/wallets/index.js @@ -9,12 +9,40 @@ export default class PaymentsWalletsIndexController extends Controller { @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; @tracked page = 1; - @tracked limit = null; + @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked type = null; @tracked status = null; @tracked table = null; + + get actionButtons() { + return [ + { + icon: 'refresh', + onClick: this.walletActions.refresh, + helpText: this.intl.t('common.refresh'), + }, + { + text: this.intl.t('common.new'), + type: 'primary', + icon: 'plus', + onClick: this.walletActions.transition.create, + }, + ]; + } + + get bulkActions() { + const selected = this.tableContext.getSelectedRows(); + return [ + { + label: this.intl.t('common.delete-selected-count', { count: selected.length }), + class: 'text-red-500', + fn: this.walletActions.bulkDelete, + }, + ]; + } + get columns() { return [ { @@ -34,6 +62,9 @@ export default class PaymentsWalletsIndexController extends Controller { valuePath: 'type', resizable: true, sortable: true, + filterable: true, + filterParam: 'type', + filterComponent: 'filter/string', }, { label: this.intl.t('column.currency'), @@ -56,25 +87,4 @@ export default class PaymentsWalletsIndexController extends Controller { }, ]; } - - get actionButtons() { - return [ - { - icon: 'refresh', - onClick: this.walletActions.refresh, - helpText: this.intl.t('common.refresh'), - }, - ]; - } - - get bulkActions() { - const selected = this.tableContext.getSelectedRows(); - return [ - { - label: this.intl.t('common.delete-selected-count', { count: selected.length }), - class: 'text-red-500', - fn: this.walletActions.bulkDelete, - }, - ]; - } } From 2780d1b077a171bcc6480560a2ca7469c7a84b60 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 21:17:28 -0500 Subject: [PATCH 031/209] feat: update models to new Transaction schema, improve columns and filters Models: - ledger-transaction: full rewrite with all 40+ new attributes from robust Transaction schema (5 polymorphic role pairs, direction, fee/tax/net amounts, exchange rate, settled currency/amount, gateway fields, reference, failure info, period, tags, timestamps) - ledger-account: remove formatted_balance computed getter (Money cast handles it) - ledger-invoice: remove formatted_* computed getters, add issued_at/paid_at - ledger-journal: remove formatted_amount getter, add entry_date/transaction_uuid - ledger-wallet: remove formatted_balance/status computed getters - ledger-gateway: add driver, environment, is_default fields - ledger-wallet-transaction: add direction, balance_after, reference, notes Controllers - improved columns and filters: - billing/invoices: number/status/total/balance/due_date/issued_at columns; status filter uses select with enum options - payments/transactions: add direction, currency, gateway, reference columns; direction/status filters use select; add direction/currency/gateway/period query params - payments/wallets: type filter uses select with enum; add currency filter param - payments/gateways: driver/environment/is_default/status columns; environment and status filters use select; add driver/environment/status query params - accounting/accounts: code as sticky anchor column; type filter uses select with asset/liability/equity/revenue/expense options; default sort by code - accounting/journal: number as sticky anchor; type and entry_source filters use select with enum options; add currency query param; sort by -entry_date --- .../controllers/accounting/accounts/index.js | 41 +++++++-- addon/controllers/accounting/journal/index.js | 44 ++++++++-- addon/controllers/billing/invoices/index.js | 33 +++++-- addon/controllers/payments/gateways/index.js | 22 ++++- .../payments/transactions/index.js | 47 +++++++++- addon/controllers/payments/wallets/index.js | 22 ++++- addon/models/ledger-account.js | 30 +------ addon/models/ledger-gateway.js | 33 ++----- addon/models/ledger-invoice.js | 62 ++----------- addon/models/ledger-journal.js | 27 +----- addon/models/ledger-transaction.js | 87 +++++++++++++------ addon/models/ledger-wallet-transaction.js | 39 +-------- addon/models/ledger-wallet.js | 33 +------ 13 files changed, 266 insertions(+), 254 deletions(-) diff --git a/addon/controllers/accounting/accounts/index.js b/addon/controllers/accounting/accounts/index.js index 7c50013..9eca07c 100644 --- a/addon/controllers/accounting/accounts/index.js +++ b/addon/controllers/accounting/accounts/index.js @@ -7,13 +7,14 @@ export default class AccountingAccountsIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status', 'currency']; @tracked page = 1; @tracked limit = 30; - @tracked sort = '-created_at'; + @tracked sort = 'code'; @tracked query = null; @tracked type = null; @tracked status = null; + @tracked currency = null; @tracked table = null; get actionButtons() { @@ -47,21 +48,24 @@ export default class AccountingAccountsIndexController extends Controller { return [ { sticky: true, - label: this.intl.t('column.name'), - valuePath: 'name', + label: this.intl.t('column.code'), + valuePath: 'code', cellComponent: 'table/cell/anchor', action: this.accountActions.transition.view, resizable: true, sortable: true, filterable: true, - filterParam: 'name', + filterParam: 'code', filterComponent: 'filter/string', }, { - label: this.intl.t('column.code'), - valuePath: 'code', + label: this.intl.t('column.name'), + valuePath: 'name', resizable: true, sortable: true, + filterable: true, + filterParam: 'name', + filterComponent: 'filter/string', }, { label: this.intl.t('column.type'), @@ -70,6 +74,22 @@ export default class AccountingAccountsIndexController extends Controller { sortable: true, filterable: true, filterParam: 'type', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Asset', value: 'asset' }, + { label: 'Liability', value: 'liability' }, + { label: 'Equity', value: 'equity' }, + { label: 'Revenue', value: 'revenue' }, + { label: 'Expense', value: 'expense' }, + ], + }, + { + label: this.intl.t('column.currency'), + valuePath: 'currency', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'currency', filterComponent: 'filter/string', }, { @@ -84,6 +104,13 @@ export default class AccountingAccountsIndexController extends Controller { cellComponent: 'table/cell/status', resizable: true, sortable: true, + filterable: true, + filterParam: 'status', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Active', value: 'active' }, + { label: 'Inactive', value: 'inactive' }, + ], }, ]; } diff --git a/addon/controllers/accounting/journal/index.js b/addon/controllers/accounting/journal/index.js index 498df9a..5a0cb39 100644 --- a/addon/controllers/accounting/journal/index.js +++ b/addon/controllers/accounting/journal/index.js @@ -7,12 +7,14 @@ export default class AccountingJournalIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'entry_source']; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'entry_source', 'currency']; @tracked page = 1; @tracked limit = 30; - @tracked sort = '-created_at'; + @tracked sort = '-entry_date'; @tracked query = null; + @tracked type = null; @tracked entry_source = null; + @tracked currency = null; @tracked table = null; get actionButtons() { @@ -46,8 +48,8 @@ export default class AccountingJournalIndexController extends Controller { return [ { sticky: true, - label: this.intl.t('column.id'), - valuePath: 'public_id', + label: this.intl.t('column.number'), + valuePath: 'number', cellComponent: 'table/cell/anchor', action: this.journalActions.transition.view, resizable: true, @@ -59,15 +61,39 @@ export default class AccountingJournalIndexController extends Controller { resizable: true, sortable: true, }, + { + label: this.intl.t('column.type'), + valuePath: 'type', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'type', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'General', value: 'general' }, + { label: 'Payment', value: 'payment' }, + { label: 'Refund', value: 'refund' }, + { label: 'Adjustment', value: 'adjustment' }, + { label: 'Deposit', value: 'deposit' }, + { label: 'Withdrawal', value: 'withdrawal' }, + { label: 'Transfer', value: 'transfer' }, + ], + }, { label: this.intl.t('column.debit-account'), - valuePath: 'debit_account.name', + valuePath: 'debit_account_name', resizable: true, + filterable: true, + filterParam: 'debit_account', + filterComponent: 'filter/string', }, { label: this.intl.t('column.credit-account'), - valuePath: 'credit_account.name', + valuePath: 'credit_account_name', resizable: true, + filterable: true, + filterParam: 'credit_account', + filterComponent: 'filter/string', }, { label: this.intl.t('column.amount'), @@ -82,7 +108,11 @@ export default class AccountingJournalIndexController extends Controller { sortable: true, filterable: true, filterParam: 'entry_source', - filterComponent: 'filter/string', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'System', value: 'system' }, + { label: 'Manual', value: 'manual' }, + ], }, ]; } diff --git a/addon/controllers/billing/invoices/index.js b/addon/controllers/billing/invoices/index.js index 88ad238..2783454 100644 --- a/addon/controllers/billing/invoices/index.js +++ b/addon/controllers/billing/invoices/index.js @@ -47,14 +47,14 @@ export default class BillingInvoicesIndexController extends Controller { return [ { sticky: true, - label: this.intl.t('column.id'), - valuePath: 'public_id', + label: this.intl.t('column.number'), + valuePath: 'number', cellComponent: 'table/cell/anchor', action: this.invoiceActions.transition.view, resizable: true, sortable: true, filterable: true, - filterParam: 'public_id', + filterParam: 'number', filterComponent: 'filter/string', }, { @@ -65,11 +65,26 @@ export default class BillingInvoicesIndexController extends Controller { sortable: true, filterable: true, filterParam: 'status', - filterComponent: 'filter/string', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Draft', value: 'draft' }, + { label: 'Sent', value: 'sent' }, + { label: 'Paid', value: 'paid' }, + { label: 'Partial', value: 'partial' }, + { label: 'Overdue', value: 'overdue' }, + { label: 'Void', value: 'void' }, + { label: 'Cancelled', value: 'cancelled' }, + ], + }, + { + label: this.intl.t('column.total'), + valuePath: 'total', + resizable: true, + sortable: true, }, { - label: this.intl.t('column.amount'), - valuePath: 'amount', + label: this.intl.t('column.balance'), + valuePath: 'balance', resizable: true, sortable: true, }, @@ -79,6 +94,12 @@ export default class BillingInvoicesIndexController extends Controller { resizable: true, sortable: true, }, + { + label: this.intl.t('column.issued-at'), + valuePath: 'issued_at', + resizable: true, + sortable: true, + }, { label: this.intl.t('column.created-at'), valuePath: 'createdAt', diff --git a/addon/controllers/payments/gateways/index.js b/addon/controllers/payments/gateways/index.js index df55633..6b3ed85 100644 --- a/addon/controllers/payments/gateways/index.js +++ b/addon/controllers/payments/gateways/index.js @@ -7,12 +7,14 @@ export default class PaymentsGatewaysIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type']; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'driver', 'environment', 'status']; @tracked page = 1; @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; - @tracked type = null; + @tracked driver = null; + @tracked environment = null; + @tracked status = null; @tracked table = null; get actionButtons() { @@ -62,7 +64,7 @@ export default class PaymentsGatewaysIndexController extends Controller { resizable: true, sortable: true, filterable: true, - filterParam: 'type', + filterParam: 'driver', filterComponent: 'filter/string', }, { @@ -70,6 +72,13 @@ export default class PaymentsGatewaysIndexController extends Controller { valuePath: 'environment', resizable: true, sortable: true, + filterable: true, + filterParam: 'environment', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Live', value: 'live' }, + { label: 'Sandbox', value: 'sandbox' }, + ], }, { label: this.intl.t('column.default'), @@ -83,6 +92,13 @@ export default class PaymentsGatewaysIndexController extends Controller { cellComponent: 'table/cell/status', resizable: true, sortable: true, + filterable: true, + filterParam: 'status', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Active', value: 'active' }, + { label: 'Inactive', value: 'inactive' }, + ], }, ]; } diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js index 3ad5a7e..bbb57dd 100644 --- a/addon/controllers/payments/transactions/index.js +++ b/addon/controllers/payments/transactions/index.js @@ -7,13 +7,17 @@ export default class PaymentsTransactionsIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status', 'direction', 'currency', 'gateway', 'period']; @tracked page = 1; @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked type = null; @tracked status = null; + @tracked direction = null; + @tracked currency = null; + @tracked gateway = null; + @tracked period = null; @tracked table = null; get actionButtons() { @@ -53,6 +57,19 @@ export default class PaymentsTransactionsIndexController extends Controller { filterParam: 'type', filterComponent: 'filter/string', }, + { + label: this.intl.t('column.direction'), + valuePath: 'direction', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'direction', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Credit', value: 'credit' }, + { label: 'Debit', value: 'debit' }, + ], + }, { label: this.intl.t('column.status'), valuePath: 'status', @@ -61,7 +78,15 @@ export default class PaymentsTransactionsIndexController extends Controller { sortable: true, filterable: true, filterParam: 'status', - filterComponent: 'filter/string', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Pending', value: 'pending' }, + { label: 'Succeeded', value: 'succeeded' }, + { label: 'Failed', value: 'failed' }, + { label: 'Refunded', value: 'refunded' }, + { label: 'Voided', value: 'voided' }, + { label: 'Reversed', value: 'reversed' }, + ], }, { label: this.intl.t('column.amount'), @@ -74,6 +99,24 @@ export default class PaymentsTransactionsIndexController extends Controller { valuePath: 'currency', resizable: true, sortable: true, + filterable: true, + filterParam: 'currency', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.gateway'), + valuePath: 'gateway', + resizable: true, + sortable: true, + filterable: true, + filterParam: 'gateway', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.reference'), + valuePath: 'reference', + resizable: true, + sortable: true, }, { label: this.intl.t('column.created-at'), diff --git a/addon/controllers/payments/wallets/index.js b/addon/controllers/payments/wallets/index.js index f9a0d84..2a5ebe3 100644 --- a/addon/controllers/payments/wallets/index.js +++ b/addon/controllers/payments/wallets/index.js @@ -7,13 +7,14 @@ export default class PaymentsWalletsIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status']; + @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status', 'currency']; @tracked page = 1; @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; @tracked type = null; @tracked status = null; + @tracked currency = null; @tracked table = null; get actionButtons() { @@ -64,13 +65,22 @@ export default class PaymentsWalletsIndexController extends Controller { sortable: true, filterable: true, filterParam: 'type', - filterComponent: 'filter/string', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Driver', value: 'driver' }, + { label: 'Customer', value: 'customer' }, + { label: 'Company', value: 'company' }, + { label: 'System', value: 'system' }, + ], }, { label: this.intl.t('column.currency'), valuePath: 'currency', resizable: true, sortable: true, + filterable: true, + filterParam: 'currency', + filterComponent: 'filter/string', }, { label: this.intl.t('column.balance'), @@ -84,6 +94,14 @@ export default class PaymentsWalletsIndexController extends Controller { cellComponent: 'table/cell/status', resizable: true, sortable: true, + filterable: true, + filterParam: 'status', + filterComponent: 'filter/select', + filterOptions: [ + { label: 'Active', value: 'active' }, + { label: 'Inactive', value: 'inactive' }, + { label: 'Frozen', value: 'frozen' }, + ], }, ]; } diff --git a/addon/models/ledger-account.js b/addon/models/ledger-account.js index f406ffe..69ae8da 100644 --- a/addon/models/ledger-account.js +++ b/addon/models/ledger-account.js @@ -1,37 +1,15 @@ import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; -export default class AccountModel extends Model { +export default class LedgerAccountModel extends Model { @attr('string') name; @attr('string') code; @attr('string') type; - @attr('string') description; + @attr('string') status; @attr('string') currency; @attr('number') balance; + @attr('string') description; @attr('boolean') is_active; + @attr('raw') meta; @attr('date') created_at; @attr('date') updated_at; - - @computed('balance', 'currency') - get formatted_balance() { - const amount = (this.balance || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); - } - - @computed('type') - get type_label() { - const labels = { - asset: 'Asset', - liability: 'Liability', - equity: 'Equity', - revenue: 'Revenue', - expense: 'Expense', - }; - return labels[this.type] || this.type; - } - - @computed('is_active') - get status_label() { - return this.is_active ? 'Active' : 'Inactive'; - } } diff --git a/addon/models/ledger-gateway.js b/addon/models/ledger-gateway.js index 80fe71c..af1cc80 100644 --- a/addon/models/ledger-gateway.js +++ b/addon/models/ledger-gateway.js @@ -1,39 +1,16 @@ import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; -export default class GatewayModel extends Model { +export default class LedgerGatewayModel extends Model { @attr('string') name; @attr('string') code; @attr('string') type; + @attr('string') driver; @attr('string') description; @attr('string') status; - @attr('boolean') sandbox; + @attr('string') environment; + @attr('boolean') is_default; + @attr('raw') config; @attr('raw') config_schema; @attr('date') created_at; @attr('date') updated_at; - - @computed('status') - get status_badge_color() { - return this.status === 'active' ? 'green' : 'gray'; - } - - @computed('sandbox') - get mode_label() { - return this.sandbox ? 'Sandbox' : 'Live'; - } - - @computed('sandbox') - get mode_badge_color() { - return this.sandbox ? 'yellow' : 'green'; - } - - @computed('code') - get icon_name() { - const icons = { - stripe: 'credit-card', - qpay: 'money-bill', - cash: 'money-bill-wave', - }; - return icons[this.code] || 'credit-card'; - } } diff --git a/addon/models/ledger-invoice.js b/addon/models/ledger-invoice.js index b9e927f..523677a 100644 --- a/addon/models/ledger-invoice.js +++ b/addon/models/ledger-invoice.js @@ -1,70 +1,22 @@ import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; -export default class InvoiceModel extends Model { +export default class LedgerInvoiceModel extends Model { @attr('string') number; @attr('string') status; @attr('string') currency; @attr('number') subtotal; - @attr('number') tax; + @attr('number') tax_amount; + @attr('number') discount_amount; @attr('number') total; @attr('number') amount_paid; @attr('number') balance; + @attr('string') customer_uuid; + @attr('string') customer_type; @attr('string') notes; - @attr('string') customer_name; - @attr('string') customer_email; - @attr('string') customer_phone; - @attr('raw') line_items; @attr('raw') meta; - @attr('date') due_at; + @attr('date') due_date; + @attr('date') issued_at; @attr('date') paid_at; - @attr('date') voided_at; @attr('date') created_at; @attr('date') updated_at; - - @computed('total', 'currency') - get formatted_total() { - const amount = (this.total || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); - } - - @computed('balance', 'currency') - get formatted_balance() { - const amount = (this.balance || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); - } - - @computed('amount_paid', 'currency') - get formatted_amount_paid() { - const amount = (this.amount_paid || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); - } - - @computed('status') - get status_badge_color() { - const colors = { - draft: 'gray', - sent: 'blue', - paid: 'green', - partial: 'yellow', - overdue: 'red', - void: 'gray', - }; - return colors[this.status] || 'gray'; - } - - @computed('status') - get is_paid() { - return this.status === 'paid'; - } - - @computed('status') - get is_overdue() { - return this.status === 'overdue'; - } - - @computed('status') - get is_draft() { - return this.status === 'draft'; - } } diff --git a/addon/models/ledger-journal.js b/addon/models/ledger-journal.js index 079879a..41356a5 100644 --- a/addon/models/ledger-journal.js +++ b/addon/models/ledger-journal.js @@ -1,7 +1,6 @@ import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; -export default class JournalModel extends Model { +export default class LedgerJournalModel extends Model { @attr('string') number; @attr('string') type; @attr('string') currency; @@ -13,34 +12,14 @@ export default class JournalModel extends Model { @attr('string') credit_account_uuid; @attr('string') credit_account_name; @attr('string') credit_account_code; + @attr('string') transaction_uuid; @attr('boolean') is_system_entry; @attr('raw') meta; - @attr('date') date; + @attr('date') entry_date; @attr('date') created_at; @attr('date') updated_at; - @computed('amount', 'currency') - get formatted_amount() { - const value = (this.amount || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); - } - - @computed('is_system_entry') get entry_source() { return this.is_system_entry ? 'System' : 'Manual'; } - - @computed('type') - get type_label() { - const labels = { - general: 'General', - payment: 'Payment', - refund: 'Refund', - adjustment: 'Adjustment', - deposit: 'Deposit', - withdrawal: 'Withdrawal', - transfer: 'Transfer', - }; - return labels[this.type] || this.type; - } } diff --git a/addon/models/ledger-transaction.js b/addon/models/ledger-transaction.js index 1715bb1..558ab23 100644 --- a/addon/models/ledger-transaction.js +++ b/addon/models/ledger-transaction.js @@ -1,36 +1,69 @@ -import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; +import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; -export default class TransactionModel extends Model { - @attr('string') gateway_transaction_id; - @attr('string') gateway_code; +export default class LedgerTransactionModel extends Model { + // Classification @attr('string') type; + @attr('string') direction; @attr('string') status; - @attr('string') currency; + + // Monetary @attr('number') amount; + @attr('number') fee_amount; + @attr('number') tax_amount; + @attr('number') net_amount; + @attr('number') balance_after; + @attr('string') currency; + @attr('number') exchange_rate; + @attr('string') settled_currency; + @attr('number') settled_amount; + + // Polymorphic roles + @attr('string') subject_uuid; + @attr('string') subject_type; + @attr('string') payer_uuid; + @attr('string') payer_type; + @attr('string') payee_uuid; + @attr('string') payee_type; + @attr('string') initiator_uuid; + @attr('string') initiator_type; + @attr('string') context_uuid; + @attr('string') context_type; + + // Gateway + @attr('string') gateway; + @attr('string') gateway_uuid; + @attr('string') gateway_transaction_id; + @attr('string') payment_method; + @attr('string') payment_method_last4; + @attr('string') payment_method_brand; + + // Idempotency and linkage + @attr('string') reference; + @attr('string') parent_transaction_uuid; + + // Descriptive @attr('string') description; - @attr('string') customer_name; - @attr('string') customer_email; + @attr('string') notes; + + // Failure info + @attr('string') failure_reason; + @attr('string') failure_code; + + // Reporting + @attr('string') period; + @attr('raw') tags; + + // Traceability + @attr('string') ip_address; + + // Misc @attr('raw') meta; + + // Timestamps + @attr('date') settled_at; + @attr('date') voided_at; + @attr('date') reversed_at; + @attr('date') expires_at; @attr('date') created_at; @attr('date') updated_at; - - @computed('amount', 'currency') - get formatted_amount() { - const value = (this.amount || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); - } - - @computed('status') - get status_badge_color() { - const colors = { - pending: 'yellow', - succeeded: 'green', - failed: 'red', - refunded: 'blue', - partially_refunded: 'blue', - cancelled: 'gray', - }; - return colors[this.status] || 'gray'; - } } diff --git a/addon/models/ledger-wallet-transaction.js b/addon/models/ledger-wallet-transaction.js index 86729f9..5329cfd 100644 --- a/addon/models/ledger-wallet-transaction.js +++ b/addon/models/ledger-wallet-transaction.js @@ -1,7 +1,6 @@ import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; -export default class WalletTransactionModel extends Model { +export default class LedgerWalletTransactionModel extends Model { @attr('string') wallet_uuid; @attr('string') type; @attr('string') direction; @@ -9,42 +8,10 @@ export default class WalletTransactionModel extends Model { @attr('string') currency; @attr('number') amount; @attr('number') balance_after; - @attr('string') description; @attr('string') reference; + @attr('string') description; + @attr('string') notes; @attr('raw') meta; @attr('date') created_at; @attr('date') updated_at; - - @computed('amount', 'currency') - get formatted_amount() { - const value = (this.amount || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); - } - - @computed('balance_after', 'currency') - get formatted_balance_after() { - const value = (this.balance_after || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(value); - } - - @computed('direction') - get direction_sign() { - return this.direction === 'credit' ? '+' : '-'; - } - - @computed('direction') - get direction_color() { - return this.direction === 'credit' ? 'green' : 'red'; - } - - @computed('status') - get status_badge_color() { - const colors = { - pending: 'yellow', - completed: 'green', - failed: 'red', - reversed: 'blue', - }; - return colors[this.status] || 'gray'; - } } diff --git a/addon/models/ledger-wallet.js b/addon/models/ledger-wallet.js index f195e13..4f003e4 100644 --- a/addon/models/ledger-wallet.js +++ b/addon/models/ledger-wallet.js @@ -1,7 +1,6 @@ import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; -export default class WalletModel extends Model { +export default class LedgerWalletModel extends Model { @attr('string') name; @attr('string') owner_uuid; @attr('string') owner_type; @@ -10,35 +9,7 @@ export default class WalletModel extends Model { @attr('string') currency; @attr('number') balance; @attr('boolean') is_frozen; + @attr('raw') meta; @attr('date') created_at; @attr('date') updated_at; - - @computed('balance', 'currency') - get formatted_balance() { - const amount = (this.balance || 0) / 100; - return new Intl.NumberFormat('en-US', { style: 'currency', currency: this.currency || 'USD' }).format(amount); - } - - @computed('type') - get type_label() { - const labels = { - driver: 'Driver', - customer: 'Customer', - company: 'Company', - system: 'System', - }; - return labels[this.type] || this.type; - } - - @computed('is_frozen', 'status') - get status_label() { - if (this.is_frozen) return 'Frozen'; - return this.status === 'active' ? 'Active' : 'Inactive'; - } - - @computed('is_frozen', 'status') - get status_badge_color() { - if (this.is_frozen) return 'blue'; - return this.status === 'active' ? 'green' : 'gray'; - } } From 965a0f8a7d839b6f5ec8f24bc52d4f7e123d0d96 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 21:35:06 -0500 Subject: [PATCH 032/209] feat: implement full transactions table columns getter with filters and queryParams - 7 default visible columns: id (sticky anchor), date, description, type, direction, amount, status - 11 hidden/toggleable columns: net_amount, fee_amount, tax_amount, currency, gateway, payment_method, reference, period, settled_at, failure_reason, updated_at - Sticky right dropdown with view/delete row actions and permission guards - type uses filter/multi-option with all 9 transaction type values - direction uses filter/select (credit/debit) - status uses filter/multi-option with all 7 status values (including expired) - payment_method uses filter/select (card/bank_transfer/wallet/cash) - amount/net_amount/fee_amount/tax_amount use table/cell/currency (ember-ui built-in) - Added 9 new queryParams: public_id, description, payment_method, reference, failure_reason, created_at, updated_at, settled_at (+ existing ones) - bulkActions now includes bulk delete --- .../payments/transactions/index.js | 218 ++++++++++++++++-- 1 file changed, 202 insertions(+), 16 deletions(-) diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js index bbb57dd..87b4463 100644 --- a/addon/controllers/payments/transactions/index.js +++ b/addon/controllers/payments/transactions/index.js @@ -7,17 +7,44 @@ export default class PaymentsTransactionsIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status', 'direction', 'currency', 'gateway', 'period']; + @tracked queryParams = [ + 'page', + 'limit', + 'sort', + 'query', + 'public_id', + 'description', + 'type', + 'status', + 'direction', + 'currency', + 'gateway', + 'payment_method', + 'reference', + 'period', + 'failure_reason', + 'created_at', + 'updated_at', + 'settled_at', + ]; @tracked page = 1; @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; + @tracked public_id = null; + @tracked description = null; @tracked type = null; @tracked status = null; @tracked direction = null; @tracked currency = null; @tracked gateway = null; + @tracked payment_method = null; + @tracked reference = null; @tracked period = null; + @tracked failure_reason = null; + @tracked created_at = null; + @tracked updated_at = null; + @tracked settled_at = null; @tracked table = null; get actionButtons() { @@ -31,23 +58,51 @@ export default class PaymentsTransactionsIndexController extends Controller { } get bulkActions() { - return []; + return [ + { + label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.transactions') }), + icon: 'trash', + class: 'text-red-500', + fn: this.transactionActions.bulkDelete, + }, + ]; } get columns() { return [ + // ── Default visible columns ────────────────────────────────────── { sticky: true, label: this.intl.t('column.id'), valuePath: 'public_id', cellComponent: 'table/cell/anchor', action: this.transactionActions.transition.view, + width: 120, resizable: true, sortable: true, filterable: true, filterParam: 'public_id', filterComponent: 'filter/string', }, + { + label: this.intl.t('column.date'), + valuePath: 'createdAt', + sortParam: 'created_at', + filterParam: 'created_at', + resizable: true, + sortable: true, + filterable: true, + filterComponent: 'filter/date', + }, + { + label: this.intl.t('column.description'), + valuePath: 'description', + resizable: true, + sortable: false, + filterable: true, + filterParam: 'description', + filterComponent: 'filter/string', + }, { label: this.intl.t('column.type'), valuePath: 'type', @@ -55,21 +110,44 @@ export default class PaymentsTransactionsIndexController extends Controller { sortable: true, filterable: true, filterParam: 'type', - filterComponent: 'filter/string', + filterComponent: 'filter/multi-option', + filterOptions: [ + 'wallet_deposit', + 'wallet_withdrawal', + 'wallet_transfer', + 'gateway_charge', + 'gateway_refund', + 'gateway_payout', + 'adjustment', + 'earning', + 'fee', + ], }, { label: this.intl.t('column.direction'), valuePath: 'direction', + cellComponent: 'table/cell/status', resizable: true, sortable: true, filterable: true, filterParam: 'direction', filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', filterOptions: [ { label: 'Credit', value: 'credit' }, { label: 'Debit', value: 'debit' }, ], }, + { + label: this.intl.t('column.amount'), + valuePath: 'amount', + cellComponent: 'table/cell/currency', + resizable: true, + sortable: true, + sortParam: 'amount', + filterable: false, + }, { label: this.intl.t('column.status'), valuePath: 'status', @@ -78,25 +156,42 @@ export default class PaymentsTransactionsIndexController extends Controller { sortable: true, filterable: true, filterParam: 'status', - filterComponent: 'filter/select', - filterOptions: [ - { label: 'Pending', value: 'pending' }, - { label: 'Succeeded', value: 'succeeded' }, - { label: 'Failed', value: 'failed' }, - { label: 'Refunded', value: 'refunded' }, - { label: 'Voided', value: 'voided' }, - { label: 'Reversed', value: 'reversed' }, - ], + filterComponent: 'filter/multi-option', + filterOptions: ['pending', 'succeeded', 'failed', 'refunded', 'voided', 'reversed', 'expired'], }, + // ── Hidden / toggleable columns ────────────────────────────────── { - label: this.intl.t('column.amount'), - valuePath: 'amount', + label: this.intl.t('column.net-amount'), + valuePath: 'net_amount', + cellComponent: 'table/cell/currency', + hidden: true, resizable: true, sortable: true, + sortParam: 'net_amount', + filterable: false, + }, + { + label: this.intl.t('column.fee'), + valuePath: 'fee_amount', + cellComponent: 'table/cell/currency', + hidden: true, + resizable: true, + sortable: false, + filterable: false, + }, + { + label: this.intl.t('column.tax'), + valuePath: 'tax_amount', + cellComponent: 'table/cell/currency', + hidden: true, + resizable: true, + sortable: false, + filterable: false, }, { label: this.intl.t('column.currency'), valuePath: 'currency', + hidden: true, resizable: true, sortable: true, filterable: true, @@ -106,23 +201,114 @@ export default class PaymentsTransactionsIndexController extends Controller { { label: this.intl.t('column.gateway'), valuePath: 'gateway', + hidden: true, resizable: true, sortable: true, filterable: true, filterParam: 'gateway', filterComponent: 'filter/string', }, + { + label: this.intl.t('column.payment-method'), + valuePath: 'payment_method', + hidden: true, + resizable: true, + sortable: false, + filterable: true, + filterParam: 'payment_method', + filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', + filterOptions: [ + { label: 'Card', value: 'card' }, + { label: 'Bank Transfer', value: 'bank_transfer' }, + { label: 'Wallet', value: 'wallet' }, + { label: 'Cash', value: 'cash' }, + ], + }, { label: this.intl.t('column.reference'), valuePath: 'reference', + hidden: true, + resizable: true, + sortable: false, + filterable: true, + filterParam: 'reference', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.period'), + valuePath: 'period', + hidden: true, + resizable: true, + sortable: true, + filterable: true, + filterParam: 'period', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.settled-at'), + valuePath: 'settled_at', + sortParam: 'settled_at', + filterParam: 'settled_at', + hidden: true, resizable: true, sortable: true, + filterable: true, + filterComponent: 'filter/date', }, { - label: this.intl.t('column.created-at'), - valuePath: 'createdAt', + label: this.intl.t('column.failure-reason'), + valuePath: 'failure_reason', + hidden: true, + resizable: true, + sortable: false, + filterable: true, + filterParam: 'failure_reason', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.updated-at'), + valuePath: 'updatedAt', + sortParam: 'updated_at', + filterParam: 'updated_at', + hidden: true, resizable: true, sortable: true, + filterable: true, + filterComponent: 'filter/date', + }, + // ── Row actions dropdown ───────────────────────────────────────── + { + label: '', + cellComponent: 'table/cell/dropdown', + ddButtonText: false, + ddButtonIcon: 'ellipsis-h', + ddButtonIconPrefix: 'fas', + ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.transaction') }), + cellClassNames: 'overflow-visible', + wrapperClass: 'flex items-center justify-end mx-2', + sticky: 'right', + width: 60, + actions: [ + { + label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.transaction') }), + icon: 'eye', + fn: this.transactionActions.transition.view, + permission: 'ledger view transaction', + }, + { separator: true }, + { + label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.transaction') }), + icon: 'trash', + fn: this.transactionActions.delete, + permission: 'ledger delete transaction', + }, + ], + sortable: false, + filterable: false, + resizable: false, + searchable: false, }, ]; } From 56cad0e4d3286781fee1bdc320f46ada45b564b0 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 21:39:04 -0500 Subject: [PATCH 033/209] feat: add computed date properties to all models; fix transactions controller Models: - Add @computed createdAt/createdAtAgo/createdAtShort, updatedAt/updatedAtAgo/updatedAtShort to all 7 Ledger Ember models following the fleetops-data date-fns pattern - ledger-invoice: also adds dueDate/issuedAt/paidAt computed variants - ledger-journal: also adds entryDate computed variants - ledger-transaction: also adds settledAt/voidedAt/reversedAt/expiresAt computed variants - All models confirmed to have public_id attribute - All models import { computed } from '@ember/object' and date-fns helpers Transactions controller: - Remove bulk delete from bulkActions (transactions are immutable records) - Remove delete action from row dropdown for same reason - bulkActions now returns empty array --- .../payments/transactions/index.js | 17 +-- addon/models/ledger-account.js | 45 ++++++ addon/models/ledger-gateway.js | 44 ++++++ addon/models/ledger-invoice.js | 104 +++++++++++++ addon/models/ledger-journal.js | 64 ++++++++ addon/models/ledger-transaction.js | 137 ++++++++++++++++-- addon/models/ledger-wallet-transaction.js | 44 ++++++ addon/models/ledger-wallet.js | 44 ++++++ 8 files changed, 473 insertions(+), 26 deletions(-) diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js index 87b4463..821f62a 100644 --- a/addon/controllers/payments/transactions/index.js +++ b/addon/controllers/payments/transactions/index.js @@ -58,14 +58,7 @@ export default class PaymentsTransactionsIndexController extends Controller { } get bulkActions() { - return [ - { - label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.transactions') }), - icon: 'trash', - class: 'text-red-500', - fn: this.transactionActions.bulkDelete, - }, - ]; + return []; } get columns() { @@ -297,13 +290,7 @@ export default class PaymentsTransactionsIndexController extends Controller { fn: this.transactionActions.transition.view, permission: 'ledger view transaction', }, - { separator: true }, - { - label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.transaction') }), - icon: 'trash', - fn: this.transactionActions.delete, - permission: 'ledger delete transaction', - }, + ], sortable: false, filterable: false, diff --git a/addon/models/ledger-account.js b/addon/models/ledger-account.js index 69ae8da..9061e2b 100644 --- a/addon/models/ledger-account.js +++ b/addon/models/ledger-account.js @@ -1,6 +1,10 @@ import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; export default class LedgerAccountModel extends Model { + @attr('string') public_id; + @attr('string') company_uuid; @attr('string') name; @attr('string') code; @attr('string') type; @@ -12,4 +16,45 @@ export default class LedgerAccountModel extends Model { @attr('raw') meta; @attr('date') created_at; @attr('date') updated_at; + + @computed('created_at') get createdAtAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'PP HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + @computed('updated_at') get updatedAtAgo() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDistanceToNow(this.updated_at); + } + + @computed('updated_at') get updatedAt() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'PP HH:mm'); + } + + @computed('updated_at') get updatedAtShort() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'dd, MMM'); + } } diff --git a/addon/models/ledger-gateway.js b/addon/models/ledger-gateway.js index af1cc80..f6de402 100644 --- a/addon/models/ledger-gateway.js +++ b/addon/models/ledger-gateway.js @@ -1,6 +1,9 @@ import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; export default class LedgerGatewayModel extends Model { + @attr('string') public_id; @attr('string') name; @attr('string') code; @attr('string') type; @@ -13,4 +16,45 @@ export default class LedgerGatewayModel extends Model { @attr('raw') config_schema; @attr('date') created_at; @attr('date') updated_at; + + @computed('created_at') get createdAtAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'PP HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + @computed('updated_at') get updatedAtAgo() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDistanceToNow(this.updated_at); + } + + @computed('updated_at') get updatedAt() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'PP HH:mm'); + } + + @computed('updated_at') get updatedAtShort() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'dd, MMM'); + } } diff --git a/addon/models/ledger-invoice.js b/addon/models/ledger-invoice.js index 523677a..62448f8 100644 --- a/addon/models/ledger-invoice.js +++ b/addon/models/ledger-invoice.js @@ -1,6 +1,9 @@ import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; export default class LedgerInvoiceModel extends Model { + @attr('string') public_id; @attr('string') number; @attr('string') status; @attr('string') currency; @@ -19,4 +22,105 @@ export default class LedgerInvoiceModel extends Model { @attr('date') paid_at; @attr('date') created_at; @attr('date') updated_at; + + @computed('created_at') get createdAtAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'PP HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + @computed('updated_at') get updatedAtAgo() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDistanceToNow(this.updated_at); + } + + @computed('updated_at') get updatedAt() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'PP HH:mm'); + } + + @computed('updated_at') get updatedAtShort() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'dd, MMM'); + } + @computed('due_date') get dueDateAgo() { + if (!isValidDate(this.due_date)) { + return null; + } + return formatDistanceToNow(this.due_date); + } + + @computed('due_date') get dueDate() { + if (!isValidDate(this.due_date)) { + return null; + } + return formatDate(this.due_date, 'PP HH:mm'); + } + + @computed('due_date') get dueDateShort() { + if (!isValidDate(this.due_date)) { + return null; + } + return formatDate(this.due_date, 'dd, MMM'); + } + @computed('issued_at') get issuedAtAgo() { + if (!isValidDate(this.issued_at)) { + return null; + } + return formatDistanceToNow(this.issued_at); + } + + @computed('issued_at') get issuedAt() { + if (!isValidDate(this.issued_at)) { + return null; + } + return formatDate(this.issued_at, 'PP HH:mm'); + } + + @computed('issued_at') get issuedAtShort() { + if (!isValidDate(this.issued_at)) { + return null; + } + return formatDate(this.issued_at, 'dd, MMM'); + } + @computed('paid_at') get paidAtAgo() { + if (!isValidDate(this.paid_at)) { + return null; + } + return formatDistanceToNow(this.paid_at); + } + + @computed('paid_at') get paidAt() { + if (!isValidDate(this.paid_at)) { + return null; + } + return formatDate(this.paid_at, 'PP HH:mm'); + } + + @computed('paid_at') get paidAtShort() { + if (!isValidDate(this.paid_at)) { + return null; + } + return formatDate(this.paid_at, 'dd, MMM'); + } } diff --git a/addon/models/ledger-journal.js b/addon/models/ledger-journal.js index 41356a5..fd7ebe1 100644 --- a/addon/models/ledger-journal.js +++ b/addon/models/ledger-journal.js @@ -1,6 +1,9 @@ import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; export default class LedgerJournalModel extends Model { + @attr('string') public_id; @attr('string') number; @attr('string') type; @attr('string') currency; @@ -22,4 +25,65 @@ export default class LedgerJournalModel extends Model { get entry_source() { return this.is_system_entry ? 'System' : 'Manual'; } + + @computed('created_at') get createdAtAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'PP HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + @computed('updated_at') get updatedAtAgo() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDistanceToNow(this.updated_at); + } + + @computed('updated_at') get updatedAt() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'PP HH:mm'); + } + + @computed('updated_at') get updatedAtShort() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'dd, MMM'); + } + @computed('entry_date') get entryDateAgo() { + if (!isValidDate(this.entry_date)) { + return null; + } + return formatDistanceToNow(this.entry_date); + } + + @computed('entry_date') get entryDate() { + if (!isValidDate(this.entry_date)) { + return null; + } + return formatDate(this.entry_date, 'PP HH:mm'); + } + + @computed('entry_date') get entryDateShort() { + if (!isValidDate(this.entry_date)) { + return null; + } + return formatDate(this.entry_date, 'dd, MMM'); + } } diff --git a/addon/models/ledger-transaction.js b/addon/models/ledger-transaction.js index 558ab23..0f37f2d 100644 --- a/addon/models/ledger-transaction.js +++ b/addon/models/ledger-transaction.js @@ -1,11 +1,14 @@ -import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; +import Model, { attr, belongsTo } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; export default class LedgerTransactionModel extends Model { + // Identity + @attr('string') public_id; // Classification @attr('string') type; @attr('string') direction; @attr('string') status; - // Monetary @attr('number') amount; @attr('number') fee_amount; @@ -16,7 +19,6 @@ export default class LedgerTransactionModel extends Model { @attr('number') exchange_rate; @attr('string') settled_currency; @attr('number') settled_amount; - // Polymorphic roles @attr('string') subject_uuid; @attr('string') subject_type; @@ -28,7 +30,6 @@ export default class LedgerTransactionModel extends Model { @attr('string') initiator_type; @attr('string') context_uuid; @attr('string') context_type; - // Gateway @attr('string') gateway; @attr('string') gateway_uuid; @@ -36,29 +37,22 @@ export default class LedgerTransactionModel extends Model { @attr('string') payment_method; @attr('string') payment_method_last4; @attr('string') payment_method_brand; - // Idempotency and linkage @attr('string') reference; @attr('string') parent_transaction_uuid; - // Descriptive @attr('string') description; @attr('string') notes; - // Failure info @attr('string') failure_reason; @attr('string') failure_code; - // Reporting @attr('string') period; @attr('raw') tags; - // Traceability @attr('string') ip_address; - // Misc @attr('raw') meta; - // Timestamps @attr('date') settled_at; @attr('date') voided_at; @@ -66,4 +60,125 @@ export default class LedgerTransactionModel extends Model { @attr('date') expires_at; @attr('date') created_at; @attr('date') updated_at; + + @computed('created_at') get createdAtAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'PP HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + @computed('updated_at') get updatedAtAgo() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDistanceToNow(this.updated_at); + } + + @computed('updated_at') get updatedAt() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'PP HH:mm'); + } + + @computed('updated_at') get updatedAtShort() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'dd, MMM'); + } + @computed('settled_at') get settledAtAgo() { + if (!isValidDate(this.settled_at)) { + return null; + } + return formatDistanceToNow(this.settled_at); + } + + @computed('settled_at') get settledAt() { + if (!isValidDate(this.settled_at)) { + return null; + } + return formatDate(this.settled_at, 'PP HH:mm'); + } + + @computed('settled_at') get settledAtShort() { + if (!isValidDate(this.settled_at)) { + return null; + } + return formatDate(this.settled_at, 'dd, MMM'); + } + @computed('voided_at') get voidedAtAgo() { + if (!isValidDate(this.voided_at)) { + return null; + } + return formatDistanceToNow(this.voided_at); + } + + @computed('voided_at') get voidedAt() { + if (!isValidDate(this.voided_at)) { + return null; + } + return formatDate(this.voided_at, 'PP HH:mm'); + } + + @computed('voided_at') get voidedAtShort() { + if (!isValidDate(this.voided_at)) { + return null; + } + return formatDate(this.voided_at, 'dd, MMM'); + } + @computed('reversed_at') get reversedAtAgo() { + if (!isValidDate(this.reversed_at)) { + return null; + } + return formatDistanceToNow(this.reversed_at); + } + + @computed('reversed_at') get reversedAt() { + if (!isValidDate(this.reversed_at)) { + return null; + } + return formatDate(this.reversed_at, 'PP HH:mm'); + } + + @computed('reversed_at') get reversedAtShort() { + if (!isValidDate(this.reversed_at)) { + return null; + } + return formatDate(this.reversed_at, 'dd, MMM'); + } + @computed('expires_at') get expiresAtAgo() { + if (!isValidDate(this.expires_at)) { + return null; + } + return formatDistanceToNow(this.expires_at); + } + + @computed('expires_at') get expiresAt() { + if (!isValidDate(this.expires_at)) { + return null; + } + return formatDate(this.expires_at, 'PP HH:mm'); + } + + @computed('expires_at') get expiresAtShort() { + if (!isValidDate(this.expires_at)) { + return null; + } + return formatDate(this.expires_at, 'dd, MMM'); + } } diff --git a/addon/models/ledger-wallet-transaction.js b/addon/models/ledger-wallet-transaction.js index 5329cfd..85fd76f 100644 --- a/addon/models/ledger-wallet-transaction.js +++ b/addon/models/ledger-wallet-transaction.js @@ -1,6 +1,9 @@ import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; export default class LedgerWalletTransactionModel extends Model { + @attr('string') public_id; @attr('string') wallet_uuid; @attr('string') type; @attr('string') direction; @@ -14,4 +17,45 @@ export default class LedgerWalletTransactionModel extends Model { @attr('raw') meta; @attr('date') created_at; @attr('date') updated_at; + + @computed('created_at') get createdAtAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'PP HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + @computed('updated_at') get updatedAtAgo() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDistanceToNow(this.updated_at); + } + + @computed('updated_at') get updatedAt() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'PP HH:mm'); + } + + @computed('updated_at') get updatedAtShort() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'dd, MMM'); + } } diff --git a/addon/models/ledger-wallet.js b/addon/models/ledger-wallet.js index 4f003e4..a5d60d9 100644 --- a/addon/models/ledger-wallet.js +++ b/addon/models/ledger-wallet.js @@ -1,6 +1,9 @@ import Model, { attr } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; export default class LedgerWalletModel extends Model { + @attr('string') public_id; @attr('string') name; @attr('string') owner_uuid; @attr('string') owner_type; @@ -12,4 +15,45 @@ export default class LedgerWalletModel extends Model { @attr('raw') meta; @attr('date') created_at; @attr('date') updated_at; + + @computed('created_at') get createdAtAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'PP HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + @computed('updated_at') get updatedAtAgo() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDistanceToNow(this.updated_at); + } + + @computed('updated_at') get updatedAt() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'PP HH:mm'); + } + + @computed('updated_at') get updatedAtShort() { + if (!isValidDate(this.updated_at)) { + return null; + } + return formatDate(this.updated_at, 'dd, MMM'); + } } From d560825772df44c10f43730f3b070c05eaafec56 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 21:47:00 -0500 Subject: [PATCH 034/209] feat: add complete translations for all resource, common, column, and menu keys - Add all resource.* keys: account, accounts, invoice, invoices, journal, journal-entries, transaction, transactions, wallet, wallets, gateway, gateways, wallet-transaction, wallet-transactions - Add all common.* keys: ledger, new, refresh, overview, transactions, resource-actions, view-resource, edit-resource-name, create-a-new-resource, delete-resource, delete-selected-count (with interpolation params) - Add all column.* keys: id, number, name, code, type, status, direction, description, date, created-at, updated-at, amount, balance, total, net-amount, fee, tax, currency, gateway, payment-method, reference, period, settled-at, failure-reason, due-date, issued-at, debit-account, credit-account, source, driver, environment, default - Add all menu.* keys for the full navigation structure --- translations/en-us.yaml | 94 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/translations/en-us.yaml b/translations/en-us.yaml index 967563c..4fc2c9b 100644 --- a/translations/en-us.yaml +++ b/translations/en-us.yaml @@ -1,2 +1,94 @@ ledger: - extension-name: Ledger \ No newline at end of file + extension-name: Ledger + +common: + ledger: Ledger + new: New + refresh: Refresh + overview: Overview + transactions: Transactions + resource-actions: >- + {resource} Actions + view-resource: >- + View {resource} + edit-resource-name: >- + Edit {resource} + create-a-new-resource: >- + Create a new {resource} + delete-resource: >- + Delete {resource} + delete-selected-count: >- + Delete {count} selected + +resource: + account: Account + accounts: Accounts + invoice: Invoice + invoices: Invoices + journal: Journal Entry + journal-entries: Journal Entries + transaction: Transaction + transactions: Transactions + wallet: Wallet + wallets: Wallets + gateway: Gateway + gateways: Gateways + wallet-transaction: Wallet Transaction + wallet-transactions: Wallet Transactions + +column: + id: ID + number: Number + name: Name + code: Code + type: Type + status: Status + direction: Direction + description: Description + date: Date + created-at: Created + updated-at: Updated + amount: Amount + balance: Balance + total: Total + net-amount: Net Amount + fee: Fee + tax: Tax + currency: Currency + gateway: Gateway + payment-method: Payment Method + reference: Reference + period: Period + settled-at: Settled At + failure-reason: Failure Reason + due-date: Due Date + issued-at: Issued At + debit-account: Debit Account + credit-account: Credit Account + source: Source + driver: Driver + environment: Environment + default: Default + +menu: + dashboard: Dashboard + billing: Billing + invoices: Invoices + payments: Payments + wallets: Wallets + gateways: Gateways + accounting: Accounting + chart-of-accounts: Chart of Accounts + journal-entries: Journal Entries + general-ledger: General Ledger + reports: Reports + income-statement: Income Statement + balance-sheet: Balance Sheet + trial-balance: Trial Balance + cash-flow: Cash Flow + ar-aging: AR Aging + wallet-summary: Wallet Summary + settings: Settings + invoice-settings: Invoice Settings + payment-settings: Payment Settings + accounting-settings: Accounting Settings From 4df65c189d5a3b618f86b944b78f02f9776f9c98 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 21:52:31 -0500 Subject: [PATCH 035/209] fix: action services - correct panel method indentation, blank lines between properties, strip console.ledger prefix from transitionTo routes - Remove 'console.ledger.' prefix from all transitionTo() route strings (mountPrefix in initialize() already handles this) - Fix panel method indentation (8 spaces, not 4) - Ensure blank lines between constructor, transition, and panel properties in all 7 action services --- addon/services/account-actions.js | 15 ++++++++------- addon/services/gateway-actions.js | 15 ++++++++------- addon/services/invoice-actions.js | 8 ++++++-- addon/services/journal-actions.js | 7 +++++-- addon/services/transaction-actions.js | 2 +- addon/services/wallet-actions.js | 9 ++++----- addon/services/wallet-transaction-actions.js | 4 +++- 7 files changed, 35 insertions(+), 25 deletions(-) diff --git a/addon/services/account-actions.js b/addon/services/account-actions.js index 8d4feca..a4376b2 100644 --- a/addon/services/account-actions.js +++ b/addon/services/account-actions.js @@ -8,10 +8,12 @@ export default class AccountActionsService extends ResourceActionService { mountPrefix: 'console.ledger', }); } + transition = { - view: (account) => this.transitionTo('console.ledger.accounting.accounts.index.details', account), - create: () => this.transitionTo('console.ledger.accounting.accounts.index.new'), + view: (account) => this.transitionTo('accounting.accounts.index.details', account), + create: () => this.transitionTo('accounting.accounts.index.new'), }; + panel = { create: (attributes = {}, options = {}) => { const account = this.createNewInstance(attributes); @@ -24,22 +26,21 @@ export default class AccountActionsService extends ResourceActionService { ...options, }); }, + edit: (account, options = {}) => { return this.resourceContextPanel.open({ content: 'account/form', - title: this.intl.t('common.edit-resource-name', { resourceName: account.name }), + title: this.intl.t('common.edit-resource-name', { resourceName: account.public_id }), useDefaultSaveTask: true, account, ...options, }); }, + view: (account, options = {}) => { return this.resourceContextPanel.open({ account, - tabs: [ - { label: this.intl.t('common.overview'), component: 'account/details' }, - { label: this.intl.t('common.ledger'), component: 'account/ledger' }, - ], + tabs: [{ label: this.intl.t('common.overview'), component: 'account/details' }], ...options, }); }, diff --git a/addon/services/gateway-actions.js b/addon/services/gateway-actions.js index 257a430..ea70ca3 100644 --- a/addon/services/gateway-actions.js +++ b/addon/services/gateway-actions.js @@ -8,10 +8,12 @@ export default class GatewayActionsService extends ResourceActionService { mountPrefix: 'console.ledger', }); } + transition = { - view: (gateway) => this.transitionTo('console.ledger.payments.gateways.index.details', gateway), - create: () => this.transitionTo('console.ledger.payments.gateways.index.new'), + view: (gateway) => this.transitionTo('payments.gateways.index.details', gateway), + create: () => this.transitionTo('payments.gateways.index.new'), }; + panel = { create: (attributes = {}, options = {}) => { const gateway = this.createNewInstance(attributes); @@ -24,22 +26,21 @@ export default class GatewayActionsService extends ResourceActionService { ...options, }); }, + edit: (gateway, options = {}) => { return this.resourceContextPanel.open({ content: 'gateway/form', - title: this.intl.t('common.edit-resource-name', { resourceName: gateway.name }), + title: this.intl.t('common.edit-resource-name', { resourceName: gateway.public_id }), useDefaultSaveTask: true, gateway, ...options, }); }, + view: (gateway, options = {}) => { return this.resourceContextPanel.open({ gateway, - tabs: [ - { label: this.intl.t('common.overview'), component: 'gateway/details' }, - { label: this.intl.t('common.transactions'), component: 'gateway/transactions' }, - ], + tabs: [{ label: this.intl.t('common.overview'), component: 'gateway/details' }], ...options, }); }, diff --git a/addon/services/invoice-actions.js b/addon/services/invoice-actions.js index dd67711..c798d16 100644 --- a/addon/services/invoice-actions.js +++ b/addon/services/invoice-actions.js @@ -8,10 +8,12 @@ export default class InvoiceActionsService extends ResourceActionService { mountPrefix: 'console.ledger', }); } + transition = { - view: (invoice) => this.transitionTo('console.ledger.billing.invoices.index.details', invoice), - create: () => this.transitionTo('console.ledger.billing.invoices.index.new'), + view: (invoice) => this.transitionTo('billing.invoices.index.details', invoice), + create: () => this.transitionTo('billing.invoices.index.new'), }; + panel = { create: (attributes = {}, options = {}) => { const invoice = this.createNewInstance(attributes); @@ -24,6 +26,7 @@ export default class InvoiceActionsService extends ResourceActionService { ...options, }); }, + edit: (invoice, options = {}) => { return this.resourceContextPanel.open({ content: 'invoice/form', @@ -33,6 +36,7 @@ export default class InvoiceActionsService extends ResourceActionService { ...options, }); }, + view: (invoice, options = {}) => { return this.resourceContextPanel.open({ invoice, diff --git a/addon/services/journal-actions.js b/addon/services/journal-actions.js index 70200e3..5077de7 100644 --- a/addon/services/journal-actions.js +++ b/addon/services/journal-actions.js @@ -8,10 +8,12 @@ export default class JournalActionsService extends ResourceActionService { mountPrefix: 'console.ledger', }); } + transition = { - view: (journal) => this.transitionTo('console.ledger.accounting.journal.index.details', journal), - create: () => this.transitionTo('console.ledger.accounting.journal.index.new'), + view: (journal) => this.transitionTo('accounting.journal.index.details', journal), + create: () => this.transitionTo('accounting.journal.index.new'), }; + panel = { create: (attributes = {}, options = {}) => { const journal = this.createNewInstance(attributes); @@ -24,6 +26,7 @@ export default class JournalActionsService extends ResourceActionService { ...options, }); }, + view: (journal, options = {}) => { return this.resourceContextPanel.open({ journal, diff --git a/addon/services/transaction-actions.js b/addon/services/transaction-actions.js index 30541e4..42f2f6f 100644 --- a/addon/services/transaction-actions.js +++ b/addon/services/transaction-actions.js @@ -10,7 +10,7 @@ export default class TransactionActionsService extends ResourceActionService { } transition = { - view: (transaction) => this.transitionTo('console.ledger.payments.transactions.index.details', transaction), + view: (transaction) => this.transitionTo('payments.transactions.index.details', transaction), }; panel = { diff --git a/addon/services/wallet-actions.js b/addon/services/wallet-actions.js index d6c1bb7..b318efc 100644 --- a/addon/services/wallet-actions.js +++ b/addon/services/wallet-actions.js @@ -8,17 +8,16 @@ export default class WalletActionsService extends ResourceActionService { mountPrefix: 'console.ledger', }); } + transition = { - view: (wallet) => this.transitionTo('console.ledger.payments.wallets.index.details', wallet), + view: (wallet) => this.transitionTo('payments.wallets.index.details', wallet), }; + panel = { view: (wallet, options = {}) => { return this.resourceContextPanel.open({ wallet, - tabs: [ - { label: this.intl.t('common.overview'), component: 'wallet/details' }, - { label: this.intl.t('common.transactions'), component: 'wallet/transactions' }, - ], + tabs: [{ label: this.intl.t('common.overview'), component: 'wallet/details' }, { label: this.intl.t('common.transactions'), component: 'wallet/transactions' }], ...options, }); }, diff --git a/addon/services/wallet-transaction-actions.js b/addon/services/wallet-transaction-actions.js index 1cb74dd..5fd9fe5 100644 --- a/addon/services/wallet-transaction-actions.js +++ b/addon/services/wallet-transaction-actions.js @@ -8,9 +8,11 @@ export default class WalletTransactionActionsService extends ResourceActionServi mountPrefix: 'console.ledger', }); } + transition = { - view: (walletTransaction) => this.transitionTo('console.ledger.payments.wallets.index.details.transactions', walletTransaction), + view: (walletTransaction) => this.transitionTo('payments.wallets.index.details.transactions', walletTransaction), }; + panel = { view: (walletTransaction, options = {}) => { return this.resourceContextPanel.open({ From d189dbb2d649d6172274f2267df09dd21942f035 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 21:59:25 -0500 Subject: [PATCH 036/209] feat(frontend): update all detail panel templates and controllers to correct pattern - Update all 6 details.hbs templates to use full Layout::Resource::Panel pattern: - @resource=@model - @controller={{this}} - @headerComponent with per-resource panel-header component - @headerTitle with appropriate model property - @actionButtons={{this.actionButtons}} - @onPressCancel={{transition-to ''}} - @onOverlayReady={{fn (mut this.overlay)}} - @headerClass='no-bottom-border' - @bodyClass='no-scroll' - TabNavigation with @contentClass='scrollable' @tablistClass='pl-2' wrapping {{outlet}} - Update/create all 6 details controllers with: - @tracked overlay = null - tabs getter returning tab array with label/route pairs - actionButtons getter with resource-appropriate actions - @action methods for resource-specific operations Resources updated: - billing/invoices (send, record-payment, void actions) - payments/transactions (read-only, no actions) - payments/wallets (top-up, transfer actions) - payments/gateways (edit, delete actions) - accounting/accounts (read-only, no actions) - accounting/journal (delete entry action) --- .../accounting/accounts/index/details.js | 10 +++- .../accounting/journal/index/details.js | 14 ++++- .../billing/invoices/index/details.js | 22 +++++-- .../payments/gateways/index/details.js | 57 +++++++++++++++++++ .../payments/transactions/index/details.js | 19 +++++++ .../payments/wallets/index/details.js | 43 ++++++++++++++ .../accounting/accounts/index/details.hbs | 23 ++++---- .../accounting/journal/index/details.hbs | 23 ++++---- .../billing/invoices/index/details.hbs | 23 ++++---- .../payments/gateways/index/details.hbs | 23 ++++---- .../payments/transactions/index/details.hbs | 24 ++++---- .../payments/wallets/index/details.hbs | 23 ++++---- 12 files changed, 223 insertions(+), 81 deletions(-) create mode 100644 addon/controllers/payments/gateways/index/details.js create mode 100644 addon/controllers/payments/transactions/index/details.js create mode 100644 addon/controllers/payments/wallets/index/details.js diff --git a/addon/controllers/accounting/accounts/index/details.js b/addon/controllers/accounting/accounts/index/details.js index af61b0a..a68211c 100644 --- a/addon/controllers/accounting/accounts/index/details.js +++ b/addon/controllers/accounting/accounts/index/details.js @@ -1,14 +1,20 @@ import Controller from '@ember/controller'; +import { tracked } from '@glimmer/tracking'; export default class AccountingAccountsIndexDetailsController extends Controller { + @tracked overlay = null; + + get tabs() { return [ - { label: 'Details', route: 'console.ledger.accounting.accounts.index.details.index' }, - { label: 'General Ledger', route: 'console.ledger.accounting.accounts.index.details.ledger' }, + { label: 'Overview', route: 'accounting.accounts.index.details.index' }, + { label: 'General Ledger', route: 'accounting.accounts.index.details.ledger' }, ]; } + get actionButtons() { return []; } + } diff --git a/addon/controllers/accounting/journal/index/details.js b/addon/controllers/accounting/journal/index/details.js index b37c819..f79b6ce 100644 --- a/addon/controllers/accounting/journal/index/details.js +++ b/addon/controllers/accounting/journal/index/details.js @@ -1,22 +1,31 @@ import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; export default class AccountingJournalIndexDetailsController extends Controller { @service notifications; @service modalsManager; @service hostRouter; + + @tracked overlay = null; + + get tabs() { - return [{ label: 'Details', route: 'console.ledger.accounting.journal.index.details.index' }]; + return [ + { label: 'Overview', route: 'accounting.journal.index.details.index' }, + ]; } + get actionButtons() { const entry = this.model; if (entry?.is_system_entry) return []; return [{ label: 'Delete', icon: 'trash', type: 'danger', onClick: this.deleteEntry }]; } + @action async deleteEntry() { const entry = this.model; this.modalsManager.confirm({ @@ -27,7 +36,7 @@ export default class AccountingJournalIndexDetailsController extends Controller try { await entry.destroyRecord(); this.notifications.success('Journal entry deleted.'); - this.hostRouter.transitionTo('console.ledger.accounting.journal.index'); + this.hostRouter.transitionTo('accounting.journal.index'); modal.done(); } catch (error) { this.notifications.serverError(error); @@ -36,4 +45,5 @@ export default class AccountingJournalIndexDetailsController extends Controller }, }); } + } diff --git a/addon/controllers/billing/invoices/index/details.js b/addon/controllers/billing/invoices/index/details.js index efd8aba..a6e0d5f 100644 --- a/addon/controllers/billing/invoices/index/details.js +++ b/addon/controllers/billing/invoices/index/details.js @@ -1,6 +1,7 @@ import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; export default class BillingInvoicesIndexDetailsController extends Controller { @service notifications; @@ -8,31 +9,39 @@ export default class BillingInvoicesIndexDetailsController extends Controller { @service fetch; @service hostRouter; + + @tracked overlay = null; + + get tabs() { return [ - { label: 'Details', route: 'console.ledger.billing.invoices.index.details.index' }, - { label: 'Line Items', route: 'console.ledger.billing.invoices.index.details.line-items' }, - { label: 'Transactions', route: 'console.ledger.billing.invoices.index.details.transactions' }, + { label: 'Details', route: 'billing.invoices.index.details.index' }, + { label: 'Line Items', route: 'billing.invoices.index.details.line-items' }, + { label: 'Transactions', route: 'billing.invoices.index.details.transactions' }, ]; } + get actionButtons() { const invoice = this.model; const buttons = []; - + if (invoice?.status === 'draft') { buttons.push({ label: 'Send', icon: 'paper-plane', type: 'primary', onClick: this.sendInvoice }); } + if (['sent', 'overdue', 'partial'].includes(invoice?.status)) { buttons.push({ label: 'Record Payment', icon: 'check-circle', type: 'success', onClick: this.recordPayment }); } + if (!['paid', 'void'].includes(invoice?.status)) { buttons.push({ label: 'Void', icon: 'ban', type: 'danger', onClick: this.voidInvoice }); } - + return buttons; } + @action async sendInvoice() { const invoice = this.model; try { @@ -44,11 +53,13 @@ export default class BillingInvoicesIndexDetailsController extends Controller { } } + @action async recordPayment() { const invoice = this.model; this.modalsManager.show('modals/record-payment', { invoice }); } + @action async voidInvoice() { const invoice = this.model; this.modalsManager.confirm({ @@ -68,4 +79,5 @@ export default class BillingInvoicesIndexDetailsController extends Controller { }, }); } + } diff --git a/addon/controllers/payments/gateways/index/details.js b/addon/controllers/payments/gateways/index/details.js new file mode 100644 index 0000000..4197870 --- /dev/null +++ b/addon/controllers/payments/gateways/index/details.js @@ -0,0 +1,57 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; + +export default class PaymentsGatewaysIndexDetailsController extends Controller { + @service notifications; + @service modalsManager; + @service hostRouter; + + + @tracked overlay = null; + + + get tabs() { + return [ + { label: 'Overview', route: 'payments.gateways.index.details.index' }, + { label: 'Webhooks', route: 'payments.gateways.index.details.webhooks' }, + ]; + } + + + get actionButtons() { + return [ + { label: 'Edit', icon: 'pencil', onClick: this.editGateway }, + { label: 'Delete', icon: 'trash', type: 'danger', onClick: this.deleteGateway }, + ]; + } + + + @action editGateway() { + const gateway = this.model; + this.modalsManager.show('modals/gateway-form', { gateway }); + } + + + @action async deleteGateway() { + const gateway = this.model; + this.modalsManager.confirm({ + title: `Delete Gateway ${gateway.name}?`, + body: 'This action cannot be undone.', + confirm: async (modal) => { + modal.startLoading(); + try { + await gateway.destroyRecord(); + this.notifications.success('Gateway deleted.'); + this.hostRouter.transitionTo('payments.gateways.index'); + modal.done(); + } catch (error) { + this.notifications.serverError(error); + modal.stopLoading(); + } + }, + }); + } + +} diff --git a/addon/controllers/payments/transactions/index/details.js b/addon/controllers/payments/transactions/index/details.js new file mode 100644 index 0000000..f0bf35e --- /dev/null +++ b/addon/controllers/payments/transactions/index/details.js @@ -0,0 +1,19 @@ +import Controller from '@ember/controller'; +import { tracked } from '@glimmer/tracking'; + +export default class PaymentsTransactionsIndexDetailsController extends Controller { + @tracked overlay = null; + + + get tabs() { + return [ + { label: 'Overview', route: 'payments.transactions.index.details.index' }, + ]; + } + + + get actionButtons() { + return []; + } + +} diff --git a/addon/controllers/payments/wallets/index/details.js b/addon/controllers/payments/wallets/index/details.js new file mode 100644 index 0000000..f43bb2e --- /dev/null +++ b/addon/controllers/payments/wallets/index/details.js @@ -0,0 +1,43 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; + +export default class PaymentsWalletsIndexDetailsController extends Controller { + @service notifications; + @service modalsManager; + @service fetch; + @service hostRouter; + + + @tracked overlay = null; + + + get tabs() { + return [ + { label: 'Overview', route: 'payments.wallets.index.details.index' }, + { label: 'Transactions', route: 'payments.wallets.index.details.transactions' }, + ]; + } + + + get actionButtons() { + return [ + { label: 'Top Up', icon: 'plus-circle', type: 'primary', onClick: this.topUpWallet }, + { label: 'Transfer', icon: 'exchange-alt', onClick: this.transferFunds }, + ]; + } + + + @action async topUpWallet() { + const wallet = this.model; + this.modalsManager.show('modals/wallet-top-up', { wallet }); + } + + + @action async transferFunds() { + const wallet = this.model; + this.modalsManager.show('modals/wallet-transfer', { wallet }); + } + +} diff --git a/addon/templates/accounting/accounts/index/details.hbs b/addon/templates/accounting/accounts/index/details.hbs index 6641778..310f502 100644 --- a/addon/templates/accounting/accounts/index/details.hbs +++ b/addon/templates/accounting/accounts/index/details.hbs @@ -1,16 +1,15 @@ - <:header> - - - <:default> - - <:default> - {{outlet}} - - - + + {{outlet}} + diff --git a/addon/templates/accounting/journal/index/details.hbs b/addon/templates/accounting/journal/index/details.hbs index 29c74bd..3ab9139 100644 --- a/addon/templates/accounting/journal/index/details.hbs +++ b/addon/templates/accounting/journal/index/details.hbs @@ -1,16 +1,15 @@ - <:header> - - - <:default> - - <:default> - {{outlet}} - - - + + {{outlet}} + diff --git a/addon/templates/billing/invoices/index/details.hbs b/addon/templates/billing/invoices/index/details.hbs index eeb2e5b..feba53b 100644 --- a/addon/templates/billing/invoices/index/details.hbs +++ b/addon/templates/billing/invoices/index/details.hbs @@ -1,16 +1,15 @@ - <:header> - - - <:default> - - <:default> - {{outlet}} - - - + + {{outlet}} + diff --git a/addon/templates/payments/gateways/index/details.hbs b/addon/templates/payments/gateways/index/details.hbs index fcd5f6a..77507c6 100644 --- a/addon/templates/payments/gateways/index/details.hbs +++ b/addon/templates/payments/gateways/index/details.hbs @@ -1,16 +1,15 @@ - <:header> - - - <:default> - - <:default> - {{outlet}} - - - + + {{outlet}} + diff --git a/addon/templates/payments/transactions/index/details.hbs b/addon/templates/payments/transactions/index/details.hbs index 5a5d918..7c197ac 100644 --- a/addon/templates/payments/transactions/index/details.hbs +++ b/addon/templates/payments/transactions/index/details.hbs @@ -1,15 +1,15 @@ - <:header> - - - <:default> - - <:default> - {{outlet}} - - - + + {{outlet}} + diff --git a/addon/templates/payments/wallets/index/details.hbs b/addon/templates/payments/wallets/index/details.hbs index 386aab5..4bed47d 100644 --- a/addon/templates/payments/wallets/index/details.hbs +++ b/addon/templates/payments/wallets/index/details.hbs @@ -1,16 +1,15 @@ - <:header> - - - <:default> - - <:default> - {{outlet}} - - - + + {{outlet}} + From 4001522f2bdb72cc46f871b0861dd9a5c20b9a24 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 22:03:13 -0500 Subject: [PATCH 037/209] fix(frontend): correct Handlebars syntax in all detail panel templates - Change @resource=@model to @resource={{@model}} on all 6 details.hbs templates - Remove redundant @headerTitle arg (superseded by @headerComponent on all panels) Affected templates: - billing/invoices/index/details.hbs - payments/transactions/index/details.hbs - payments/wallets/index/details.hbs - payments/gateways/index/details.hbs - accounting/accounts/index/details.hbs - accounting/journal/index/details.hbs --- addon/templates/accounting/accounts/index/details.hbs | 3 +-- addon/templates/accounting/journal/index/details.hbs | 3 +-- addon/templates/billing/invoices/index/details.hbs | 3 +-- addon/templates/payments/gateways/index/details.hbs | 3 +-- addon/templates/payments/transactions/index/details.hbs | 3 +-- addon/templates/payments/wallets/index/details.hbs | 3 +-- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/addon/templates/accounting/accounts/index/details.hbs b/addon/templates/accounting/accounts/index/details.hbs index 310f502..ebc16e0 100644 --- a/addon/templates/accounting/accounts/index/details.hbs +++ b/addon/templates/accounting/accounts/index/details.hbs @@ -1,8 +1,7 @@ Date: Sun, 1 Mar 2026 22:11:18 -0500 Subject: [PATCH 038/209] fix(frontend): replace all format-date usages with correct helpers/computed properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace incorrect format-date helper throughout all component templates: Use model computed date properties (no template helper needed): - invoice/panel-header.hbs: @invoice.due_at → @invoice.dueDate - invoice/details.hbs: @invoice.due_at → @invoice.dueDate - invoice/transactions.hbs: txn.created_at → txn.createdAt - transaction/panel-header.hbs: @transaction.created_at → @transaction.createdAt - transaction/details.hbs: @transaction.created_at → @transaction.createdAt - wallet/details.hbs: @wallet.created_at → @wallet.createdAt - wallet/transaction-history.hbs: txn.created_at → txn.createdAtShort (compact) Use format-date-fns helper (raw API/non-model dates with no computed property): - journal/panel-header.hbs: @entry.date → format-date-fns @entry.date "MMM d, yyyy" - journal/details.hbs: @entry.date → format-date-fns @entry.date "MMM d, yyyy" - account/general-ledger.hbs: entry.date → format-date-fns entry.date "MMM d, yyyy" - report/balance-sheet.hbs: @data.as_of → format-date-fns @data.as_of "MMMM d, yyyy" - report/ar-aging.hbs: @data.as_of + row.due_date → format-date-fns with respective formats - gateway/webhook-events.hbs: event.created_at → format-date-fns event.created_at "MMM d, HH:mm" --- addon/components/account/general-ledger.hbs | 2 +- addon/components/gateway/webhook-events.hbs | 2 +- addon/components/invoice/details.hbs | 2 +- addon/components/invoice/panel-header.hbs | 2 +- addon/components/invoice/transactions.hbs | 2 +- addon/components/journal/details.hbs | 2 +- addon/components/journal/panel-header.hbs | 2 +- addon/components/report/ar-aging.hbs | 4 ++-- addon/components/report/balance-sheet.hbs | 2 +- addon/components/transaction/details.hbs | 2 +- addon/components/transaction/panel-header.hbs | 2 +- addon/components/wallet/details.hbs | 2 +- addon/components/wallet/transaction-history.hbs | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/addon/components/account/general-ledger.hbs b/addon/components/account/general-ledger.hbs index 8991029..9ac83e2 100644 --- a/addon/components/account/general-ledger.hbs +++ b/addon/components/account/general-ledger.hbs @@ -31,7 +31,7 @@ {{#each this.entries as |entry|}} - + {{#each this.events as |event|}} - + diff --git a/addon/components/invoice/details.hbs b/addon/components/invoice/details.hbs index 204cf34..b9ffe13 100644 --- a/addon/components/invoice/details.hbs +++ b/addon/components/invoice/details.hbs @@ -18,7 +18,7 @@
-

{{format-date @invoice.due_at format="MMM d, yyyy"}}

+

{{@invoice.dueDate}}

diff --git a/addon/components/invoice/panel-header.hbs b/addon/components/invoice/panel-header.hbs index 5ea0e99..e0e5285 100644 --- a/addon/components/invoice/panel-header.hbs +++ b/addon/components/invoice/panel-header.hbs @@ -1,7 +1,7 @@

{{@invoice.customer_name}}

-

Due {{format-date @invoice.due_at format="MMM d, yyyy"}}

+

Due {{@invoice.dueDate}}

{{@invoice.formatted_total}} diff --git a/addon/components/invoice/transactions.hbs b/addon/components/invoice/transactions.hbs index cd8a7be..e92c835 100644 --- a/addon/components/invoice/transactions.hbs +++ b/addon/components/invoice/transactions.hbs @@ -14,7 +14,7 @@
{{#each this.transactions as |txn|}} - + - + {{#each this.transactions as |txn|}} - +
{{format-date entry.date format="MMM d, yyyy"}}{{format-date-fns entry.date "MMM d, yyyy"}} {{entry.description}} {{or entry.formatted_debit "—"}} diff --git a/addon/components/gateway/webhook-events.hbs b/addon/components/gateway/webhook-events.hbs index f09bedd..89acf8e 100644 --- a/addon/components/gateway/webhook-events.hbs +++ b/addon/components/gateway/webhook-events.hbs @@ -15,7 +15,7 @@
{{format-date event.created_at format="MMM d, HH:mm"}}{{format-date-fns event.created_at "MMM d, HH:mm"}} {{event.event_type}} {{event.gateway_reference_id}} {{event.formatted_amount}}
{{format-date txn.created_at format="MMM d, yyyy"}}{{txn.createdAt}} {{txn.gateway_code}} {{txn.formatted_amount}} diff --git a/addon/components/journal/details.hbs b/addon/components/journal/details.hbs index ac369ba..e5c63a0 100644 --- a/addon/components/journal/details.hbs +++ b/addon/components/journal/details.hbs @@ -10,7 +10,7 @@
-

{{format-date @entry.date format="MMM d, yyyy"}}

+

{{format-date-fns @entry.date "MMM d, yyyy"}}

diff --git a/addon/components/journal/panel-header.hbs b/addon/components/journal/panel-header.hbs index c54373c..e136b21 100644 --- a/addon/components/journal/panel-header.hbs +++ b/addon/components/journal/panel-header.hbs @@ -1,7 +1,7 @@

{{@entry.type_label}}

-

{{format-date @entry.date format="MMM d, yyyy"}}

+

{{format-date-fns @entry.date "MMM d, yyyy"}}

{{@entry.formatted_amount}} diff --git a/addon/components/report/ar-aging.hbs b/addon/components/report/ar-aging.hbs index ed8b4d5..06c5406 100644 --- a/addon/components/report/ar-aging.hbs +++ b/addon/components/report/ar-aging.hbs @@ -2,7 +2,7 @@

Accounts Receivable Aging

{{#if @data.as_of}} - As of {{format-date @data.as_of format="MMMM d, yyyy"}} + As of {{format-date-fns @data.as_of "MMMM d, yyyy"}} {{/if}}
@@ -34,7 +34,7 @@
{{row.number}} {{row.customer_name}}{{format-date row.due_date format="MMM d, yyyy"}}{{format-date-fns row.due_date "MMM d, yyyy"}} {{row.formatted_balance}} {{row.days_overdue}} diff --git a/addon/components/report/balance-sheet.hbs b/addon/components/report/balance-sheet.hbs index 23731fb..8644fde 100644 --- a/addon/components/report/balance-sheet.hbs +++ b/addon/components/report/balance-sheet.hbs @@ -2,7 +2,7 @@

Balance Sheet

{{#if @data.as_of}} - As of {{format-date @data.as_of format="MMMM d, yyyy"}} + As of {{format-date-fns @data.as_of "MMMM d, yyyy"}} {{/if}} {{if @data.balanced "Balanced" "Unbalanced"}}
diff --git a/addon/components/transaction/details.hbs b/addon/components/transaction/details.hbs index 2d45088..e009d34 100644 --- a/addon/components/transaction/details.hbs +++ b/addon/components/transaction/details.hbs @@ -30,7 +30,7 @@
-

{{format-date @transaction.created_at format="MMM d, yyyy HH:mm"}}

+

{{@transaction.createdAt}}

{{#if @transaction.description}} diff --git a/addon/components/transaction/panel-header.hbs b/addon/components/transaction/panel-header.hbs index d7c7882..91a3501 100644 --- a/addon/components/transaction/panel-header.hbs +++ b/addon/components/transaction/panel-header.hbs @@ -1,7 +1,7 @@

{{@transaction.gateway_code}}

-

{{format-date @transaction.created_at format="MMM d, yyyy HH:mm"}}

+

{{@transaction.createdAt}}

{{@transaction.formatted_amount}} diff --git a/addon/components/wallet/details.hbs b/addon/components/wallet/details.hbs index afe036c..f8498c3 100644 --- a/addon/components/wallet/details.hbs +++ b/addon/components/wallet/details.hbs @@ -22,7 +22,7 @@
-

{{format-date @wallet.created_at format="MMM d, yyyy"}}

+

{{@wallet.createdAt}}

diff --git a/addon/components/wallet/transaction-history.hbs b/addon/components/wallet/transaction-history.hbs index cc30f40..c2b7f0a 100644 --- a/addon/components/wallet/transaction-history.hbs +++ b/addon/components/wallet/transaction-history.hbs @@ -16,7 +16,7 @@
{{format-date txn.created_at format="MMM d, HH:mm"}}{{txn.createdAtShort}} {{txn.type}} {{or txn.description "—"}} From 736e14bdcce346b426fc0bf9988c43c7a7e7633d Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 22:22:50 -0500 Subject: [PATCH 039/209] feat(frontend): rewrite all resource details and panel-header components to correct pattern Following the fleetops vehicle/details.hbs reference pattern: - Use ContentPanel sections with @open, @wrapperClass='bordered-top' - Use .details-wrapper root div with ...attributes spread - Use .field-info-container / .field-name / .field-value div structure - Use n-a helper for all field values to handle null/empty gracefully - Group fields into logical sections with uppercase section headers - Include Record Info ContentPanel (closed by default) on all resources Following the fleetops vehicle/panel-header.hbs reference pattern: - Use px-4 py-2 root div with ...attributes spread - Use @resource arg (not resource-specific named args like @invoice, @wallet etc) - Show resource title as h1 with font-semibold text-2xl - Show key metadata as subtitle row with Badge components - Show key metric (balance/amount/total) right-aligned Components rewritten: invoice/details.hbs: Invoice Info, Amounts, Notes, Record Info sections invoice/panel-header.hbs: number + customer/status + total/due date transaction/details.hbs: Transaction Info, Amounts, Settlement, Parties, Failure, Notes, Record Info transaction/panel-header.hbs: public_id + type/status + directional amount/currency wallet/details.hbs: Wallet Info, Balance, Owner, Record Info sections wallet/panel-header.hbs: name + type/currency/status/frozen + balance gateway/details.hbs: Gateway Info, Integration (webhook/capabilities), Record Info gateway/panel-header.hbs: name + driver/environment/default + status badge account/details.hbs: Account Info, Balance, Record Info sections account/panel-header.hbs: name + code/type/status + balance/currency journal/details.hbs: Entry Info, Double-Entry (debit/credit), Record Info journal/panel-header.hbs: number + type/source + amount/entry date Route templates updated: - All details.hbs: headerComponent now passes resource=@model - All details/index.hbs: component invocations now use @resource={{@model}} --- addon/components/account/details.hbs | 105 +++++--- addon/components/account/panel-header.hbs | 20 +- addon/components/gateway/details.hbs | 130 ++++++--- addon/components/gateway/panel-header.hbs | 25 +- addon/components/invoice/details.hbs | 154 ++++++++--- addon/components/invoice/panel-header.hbs | 21 +- addon/components/journal/details.hbs | 143 +++++++--- addon/components/journal/panel-header.hbs | 21 +- addon/components/transaction/details.hbs | 250 +++++++++++++++--- addon/components/transaction/panel-header.hbs | 23 +- addon/components/wallet/details.hbs | 106 ++++++-- addon/components/wallet/panel-header.hbs | 24 +- .../accounting/accounts/index/details.hbs | 2 +- .../accounts/index/details/index.hbs | 2 +- .../accounting/journal/index/details.hbs | 2 +- .../journal/index/details/index.hbs | 2 +- .../billing/invoices/index/details.hbs | 2 +- .../billing/invoices/index/details/index.hbs | 2 +- .../payments/gateways/index/details.hbs | 2 +- .../payments/gateways/index/details/index.hbs | 2 +- .../payments/transactions/index/details.hbs | 2 +- .../transactions/index/details/index.hbs | 2 +- .../payments/wallets/index/details.hbs | 2 +- .../payments/wallets/index/details/index.hbs | 2 +- 24 files changed, 771 insertions(+), 275 deletions(-) diff --git a/addon/components/account/details.hbs b/addon/components/account/details.hbs index 01ce9c8..df96f98 100644 --- a/addon/components/account/details.hbs +++ b/addon/components/account/details.hbs @@ -1,34 +1,77 @@ -
-
-
- -

{{@account.name}}

+
+ {{! ACCOUNT DETAILS }} + +
+ +
+ Account Information +
+ +
+
Account Name
+
{{n-a @resource.name}}
+
+ +
+
Account Code
+
{{n-a @resource.code}}
+
+ +
+
Type
+
{{n-a @resource.type_label}}
+
+ +
+
Status
+
+ {{@resource.status_label}} +
+
+ +
+
Currency
+
{{n-a @resource.currency}}
+
+ + {{#if @resource.description}} +
+
Description
+
{{@resource.description}}
+
+ {{/if}} + +
+ Balance +
+ +
+
Current Balance
+
{{n-a @resource.formatted_balance}}
+
+
-
- -

{{@account.code}}

+ + + {{! RECORD INFO }} + +
+ +
+
Internal ID
+
{{n-a @resource.public_id}}
+
+ +
+
Created
+
{{n-a @resource.createdAt}}
+
+ +
+
Last Updated
+
{{n-a @resource.updatedAt}}
+
+
-
- -

{{@account.type_label}}

-
-
- - {{@account.status_label}} -
-
- -

{{@account.formatted_balance}}

-
-
- -

{{@account.currency}}

-
-
- {{#if @account.description}} -
- -

{{@account.description}}

-
- {{/if}} +
diff --git a/addon/components/account/panel-header.hbs b/addon/components/account/panel-header.hbs index 65fdc06..71a838c 100644 --- a/addon/components/account/panel-header.hbs +++ b/addon/components/account/panel-header.hbs @@ -1,9 +1,15 @@ -
-
-

{{@account.code}} · {{@account.type_label}}

-
-
- {{@account.formatted_balance}} - {{@account.status_label}} +
+
+
+

{{n-a @resource.name}}

+
+ {{n-a @resource.code}} · {{n-a @resource.type_label}} + {{@resource.status_label}} +
+
+
+ {{n-a @resource.formatted_balance}} + {{n-a @resource.currency}} +
diff --git a/addon/components/gateway/details.hbs b/addon/components/gateway/details.hbs index 6abd782..75c7dfc 100644 --- a/addon/components/gateway/details.hbs +++ b/addon/components/gateway/details.hbs @@ -1,39 +1,103 @@ -
-
-
- -

{{@gateway.name}}

-
-
- -

{{@gateway.driver_label}}

-
-
- - {{@gateway.environment}} -
-
- - {{@gateway.status_label}} -
-
- -

{{if @gateway.is_default "Yes" "No"}}

+
+ {{! GATEWAY DETAILS }} + +
+ +
+ Gateway Information +
+ +
+
Name
+
{{n-a @resource.name}}
+
+ +
+
Code
+
{{n-a @resource.code}}
+
+ +
+
Driver
+
{{n-a @resource.driver_label}}
+
+ +
+
Type
+
{{n-a @resource.type}}
+
+ +
+
Environment
+
+ {{n-a @resource.environment}} +
+
+ +
+
Status
+
+ {{@resource.status_label}} +
+
+ +
+
Default Gateway
+
{{if @resource.is_default "Yes" "No"}}
+
+ + {{#if @resource.description}} +
+
Description
+
{{@resource.description}}
+
+ {{/if}} +
-
- -

{{@gateway.webhook_url}}

+ + + {{! INTEGRATION }} + +
+ +
+
Webhook URL
+
{{n-a @resource.webhook_url}}
+
+ + {{#if @resource.capabilities}} +
+
Capabilities
+
+ {{#each @resource.capabilities as |cap|}} + {{cap}} + {{/each}} +
+
+ {{/if}} +
-
+
+ + {{! RECORD INFO }} + +
+ +
+
Internal ID
+
{{n-a @resource.public_id}}
+
+ +
+
Created
+
{{n-a @resource.createdAt}}
+
- {{#if @gateway.capabilities}} -
-

Capabilities

-
- {{#each @gateway.capabilities as |cap|}} - {{cap}} - {{/each}} +
+
Last Updated
+
{{n-a @resource.updatedAt}}
+
- {{/if}} +
diff --git a/addon/components/gateway/panel-header.hbs b/addon/components/gateway/panel-header.hbs index f9aa089..82b2e9c 100644 --- a/addon/components/gateway/panel-header.hbs +++ b/addon/components/gateway/panel-header.hbs @@ -1,12 +1,17 @@ -
-
-

{{@gateway.driver_label}}

-

{{@gateway.environment}}

-
-
- {{#if @gateway.is_default}} - Default - {{/if}} - {{@gateway.status_label}} +
+
+
+

{{n-a @resource.name}}

+
+ {{n-a @resource.driver_label}} + {{n-a @resource.environment}} + {{#if @resource.is_default}} + Default + {{/if}} +
+
+
+ {{@resource.status_label}} +
diff --git a/addon/components/invoice/details.hbs b/addon/components/invoice/details.hbs index b9ffe13..a91fc55 100644 --- a/addon/components/invoice/details.hbs +++ b/addon/components/invoice/details.hbs @@ -1,60 +1,126 @@ -
-
-
- -

{{@invoice.number}}

-
-
- - {{@invoice.status}} -
-
- -

{{@invoice.customer_name}}

-
-
- -

{{or @invoice.customer_email "—"}}

-
-
- -

{{@invoice.dueDate}}

-
-
- -

{{@invoice.currency}}

-
-
+
+ {{! INVOICE DETAILS }} + +
+ +
+ Invoice Information +
-
-
- -

{{@invoice.formatted_subtotal}}

+
Invoice Number
+
{{n-a @resource.number}}
+
- -

{{@invoice.formatted_tax}}

+
Status
+
+ {{@resource.status}} +
+
- -

{{@invoice.formatted_total}}

+
Currency
+
{{n-a @resource.currency}}
+
- -

{{@invoice.formatted_amount_paid}}

+
Issued
+
{{n-a @resource.issuedAt}}
+ +
+
Due Date
+
{{n-a @resource.dueDate}}
+
+
- -

{{@invoice.formatted_balance}}

+
Paid At
+
{{n-a @resource.paidAt}}
+ +
+ Customer +
+ +
+
Customer Name
+
{{n-a @resource.customer_name}}
+
+ +
+
Customer Email
+
{{n-a @resource.customer_email}}
+
+
-
+ + + {{! AMOUNTS }} + +
+ +
+
Subtotal
+
{{n-a @resource.formatted_subtotal}}
+
+ +
+
Tax
+
{{n-a @resource.formatted_tax}}
+
+ +
+
Discount
+
{{n-a @resource.formatted_discount}}
+
+ +
+
Total
+
{{n-a @resource.formatted_total}}
+
+ +
+
Amount Paid
+
{{n-a @resource.formatted_amount_paid}}
+
+ +
+
Balance Due
+
{{n-a @resource.formatted_balance}}
+
- {{#if @invoice.notes}} -
- -

{{@invoice.notes}}

+ + + {{! NOTES }} + {{#if @resource.notes}} + +
+ {{@resource.notes}} +
+
{{/if}} + + {{! METADATA }} + +
+ +
+
Internal ID
+
{{n-a @resource.public_id}}
+
+ +
+
Created
+
{{n-a @resource.createdAt}}
+
+ +
+
Last Updated
+
{{n-a @resource.updatedAt}}
+
+ +
+
diff --git a/addon/components/invoice/panel-header.hbs b/addon/components/invoice/panel-header.hbs index e0e5285..a43ddf0 100644 --- a/addon/components/invoice/panel-header.hbs +++ b/addon/components/invoice/panel-header.hbs @@ -1,10 +1,15 @@ -
-
-

{{@invoice.customer_name}}

-

Due {{@invoice.dueDate}}

-
-
- {{@invoice.formatted_total}} - {{@invoice.status}} +
+
+
+

{{n-a @resource.number}}

+
+ {{n-a @resource.customer_name}} + {{@resource.status}} +
+
+
+ {{n-a @resource.formatted_total}} + Due {{n-a @resource.dueDate}} +
diff --git a/addon/components/journal/details.hbs b/addon/components/journal/details.hbs index e5c63a0..8a23421 100644 --- a/addon/components/journal/details.hbs +++ b/addon/components/journal/details.hbs @@ -1,51 +1,108 @@ -
-
-
- -

{{@entry.number}}

-
-
- -

{{@entry.type_label}}

-
-
- -

{{format-date-fns @entry.date "MMM d, yyyy"}}

-
-
- - {{@entry.entry_source}} -
-
- -

{{@entry.formatted_amount}}

-
-
- -

{{@entry.currency}}

+
+ {{! JOURNAL ENTRY DETAILS }} + +
+ +
+ Entry Information +
+ +
+
Entry Number
+
{{n-a @resource.number}}
+
+ +
+
Type
+
{{n-a @resource.type_label}}
+
+ +
+
Entry Date
+
{{n-a @resource.entryDate}}
+
+ +
+
Source
+
+ {{@resource.entry_source}} +
+
+ +
+
Amount
+
{{n-a @resource.formatted_amount}}
+
+ +
+
Currency
+
{{n-a @resource.currency}}
+
+ + {{#if @resource.description}} +
+
Description
+
{{@resource.description}}
+
+ {{/if}} +
-
+ + + {{! DOUBLE-ENTRY }} + +
+ +
+ Debit +
+ +
+
Debit Account
+
{{n-a @resource.debit_account_name}}
+
-
-

Double-Entry

-
-
-

Debit

-

{{@entry.debit_account_name}}

-

{{@entry.debit_account_code}}

+
+
Debit Account Code
+
{{n-a @resource.debit_account_code}}
-
-

Credit

-

{{@entry.credit_account_name}}

-

{{@entry.credit_account_code}}

+ +
+ Credit
+ +
+
Credit Account
+
{{n-a @resource.credit_account_name}}
+
+ +
+
Credit Account Code
+
{{n-a @resource.credit_account_code}}
+
+
-
+ + + {{! RECORD INFO }} + +
+ +
+
Internal ID
+
{{n-a @resource.public_id}}
+
+ +
+
Created
+
{{n-a @resource.createdAt}}
+
+ +
+
Last Updated
+
{{n-a @resource.updatedAt}}
+
- {{#if @entry.description}} -
- -

{{@entry.description}}

- {{/if}} +
diff --git a/addon/components/journal/panel-header.hbs b/addon/components/journal/panel-header.hbs index e136b21..39267c9 100644 --- a/addon/components/journal/panel-header.hbs +++ b/addon/components/journal/panel-header.hbs @@ -1,10 +1,15 @@ -
-
-

{{@entry.type_label}}

-

{{format-date-fns @entry.date "MMM d, yyyy"}}

-
-
- {{@entry.formatted_amount}} - {{@entry.entry_source}} +
+
+
+

{{n-a @resource.number}}

+
+ {{n-a @resource.type_label}} + {{@resource.entry_source}} +
+
+
+ {{n-a @resource.formatted_amount}} + {{n-a @resource.entryDate}} +
diff --git a/addon/components/transaction/details.hbs b/addon/components/transaction/details.hbs index e009d34..ee3beaa 100644 --- a/addon/components/transaction/details.hbs +++ b/addon/components/transaction/details.hbs @@ -1,42 +1,216 @@ -
-
-
- -

{{@transaction.gateway_transaction_id}}

+
+ {{! TRANSACTION DETAILS }} + +
+ +
+ Transaction Information +
+ +
+
Reference ID
+
{{n-a @resource.public_id}}
+
+ +
+
Status
+
+ {{@resource.status}} +
+
+ +
+
Type
+
{{n-a @resource.type}}
+
+ +
+
Direction
+
{{n-a @resource.direction}}
+
+ +
+
Gateway
+
{{n-a @resource.gateway}}
+
+ +
+
Gateway Transaction ID
+
{{n-a @resource.gateway_transaction_id}}
+
+ +
+
Payment Method
+
{{n-a @resource.payment_method}}
+
+ +
+
Card
+
+ {{#if @resource.payment_method_brand}} + {{@resource.payment_method_brand}} ···· {{@resource.payment_method_last4}} + {{else}} + {{n-a null}} + {{/if}} +
+
+ +
+
Reference
+
{{n-a @resource.reference}}
+
+ +
+
Date
+
{{n-a @resource.createdAt}}
+
+ +
+ Amounts +
+ +
+
Amount
+
{{n-a @resource.formatted_amount}}
+
+ +
+
Currency
+
{{n-a @resource.currency}}
+
+ +
+
Fee
+
{{n-a @resource.formatted_fee}}
+
+ +
+
Tax
+
{{n-a @resource.formatted_tax}}
+
+ +
+
Net Amount
+
{{n-a @resource.formatted_net}}
+
+ +
+
Balance After
+
{{n-a @resource.formatted_balance_after}}
+
+ + {{#if @resource.exchange_rate}} +
+ Settlement +
+ +
+
Exchange Rate
+
{{n-a @resource.exchange_rate}}
+
+ +
+
Settled Currency
+
{{n-a @resource.settled_currency}}
+
+ +
+
Settled Amount
+
{{n-a @resource.formatted_settled_amount}}
+
+ +
+
Settled At
+
{{n-a @resource.settledAt}}
+
+ {{/if}} +
-
- - {{@transaction.status}} -
-
- -

{{@transaction.gateway_code}}

-
-
- -

{{@transaction.type}}

-
-
- -

{{@transaction.formatted_amount}}

-
-
- -

{{@transaction.currency}}

-
-
- -

{{or @transaction.customer_name "—"}}

-
-
- -

{{@transaction.createdAt}}

-
-
- {{#if @transaction.description}} -
- -

{{@transaction.description}}

+ + + {{! PARTIES }} + +
+ +
+
Payer
+
{{n-a @resource.payer_name}}
+
+ +
+
Payee
+
{{n-a @resource.payee_name}}
+
+ +
+
Initiated By
+
{{n-a @resource.initiator_name}}
+
+ +
+
IP Address
+
{{n-a @resource.ip_address}}
+
+
+
+ + {{! FAILURE INFO }} + {{#if @resource.failure_reason}} + +
+ +
+
Failure Code
+
{{n-a @resource.failure_code}}
+
+ +
+
Failure Reason
+
{{n-a @resource.failure_reason}}
+
+ +
+
{{/if}} + + {{! DESCRIPTION & NOTES }} + {{#if (or @resource.description @resource.notes)}} + +
+ + {{#if @resource.description}} +
+
Description
+
{{@resource.description}}
+
+ {{/if}} + + {{#if @resource.notes}} +
+
Notes
+
{{@resource.notes}}
+
+ {{/if}} + +
+
+ {{/if}} + + {{! RECORD INFO }} + +
+ +
+
Created
+
{{n-a @resource.createdAt}}
+
+ +
+
Last Updated
+
{{n-a @resource.updatedAt}}
+
+ +
+
diff --git a/addon/components/transaction/panel-header.hbs b/addon/components/transaction/panel-header.hbs index 91a3501..1c8a735 100644 --- a/addon/components/transaction/panel-header.hbs +++ b/addon/components/transaction/panel-header.hbs @@ -1,10 +1,17 @@ -
-
-

{{@transaction.gateway_code}}

-

{{@transaction.createdAt}}

-
-
- {{@transaction.formatted_amount}} - {{@transaction.status}} +
+
+
+

{{n-a @resource.public_id}}

+
+ {{n-a @resource.type}} + {{@resource.status}} +
+
+
+ + {{@resource.direction_sign}}{{n-a @resource.formatted_amount}} + + {{n-a @resource.currency}} +
diff --git a/addon/components/wallet/details.hbs b/addon/components/wallet/details.hbs index f8498c3..c0933e7 100644 --- a/addon/components/wallet/details.hbs +++ b/addon/components/wallet/details.hbs @@ -1,28 +1,84 @@ -
-
-
- -

{{@wallet.name}}

+
+ {{! WALLET DETAILS }} + +
+ +
+ Wallet Information +
+ +
+
Wallet Name
+
{{n-a @resource.name}}
+
+ +
+
Type
+
{{n-a @resource.type_label}}
+
+ +
+
Currency
+
{{n-a @resource.currency}}
+
+ +
+
Status
+
+ {{@resource.status_label}} +
+
+ +
+
Frozen
+
{{if @resource.is_frozen "Yes" "No"}}
+
+ +
+ Balance +
+ +
+
Current Balance
+
{{n-a @resource.formatted_balance}}
+
+ +
+ Owner +
+ +
+
Owner
+
{{n-a @resource.owner_name}}
+
+ +
+
Owner Type
+
{{n-a @resource.owner_type}}
+
+
-
- -

{{@wallet.type_label}}

+ + + {{! RECORD INFO }} + +
+ +
+
Internal ID
+
{{n-a @resource.public_id}}
+
+ +
+
Created
+
{{n-a @resource.createdAt}}
+
+ +
+
Last Updated
+
{{n-a @resource.updatedAt}}
+
+
-
- -

{{@wallet.formatted_balance}}

-
-
- -

{{@wallet.currency}}

-
-
- - {{@wallet.status_label}} -
-
- -

{{@wallet.createdAt}}

-
-
+
diff --git a/addon/components/wallet/panel-header.hbs b/addon/components/wallet/panel-header.hbs index af2f4c1..71bf5d7 100644 --- a/addon/components/wallet/panel-header.hbs +++ b/addon/components/wallet/panel-header.hbs @@ -1,10 +1,18 @@ -
-
-

{{@wallet.type_label}} Wallet

-

{{@wallet.currency}}

-
-
- {{@wallet.formatted_balance}} - {{@wallet.status_label}} +
+
+
+

{{n-a @resource.name}}

+
+ {{n-a @resource.type_label}} · {{n-a @resource.currency}} + {{@resource.status_label}} + {{#if @resource.is_frozen}} + Frozen + {{/if}} +
+
+
+ {{n-a @resource.formatted_balance}} + Balance +
diff --git a/addon/templates/accounting/accounts/index/details.hbs b/addon/templates/accounting/accounts/index/details.hbs index ebc16e0..c4efb2b 100644 --- a/addon/templates/accounting/accounts/index/details.hbs +++ b/addon/templates/accounting/accounts/index/details.hbs @@ -1,7 +1,7 @@ + diff --git a/addon/templates/accounting/journal/index/details.hbs b/addon/templates/accounting/journal/index/details.hbs index a260ada..df775de 100644 --- a/addon/templates/accounting/journal/index/details.hbs +++ b/addon/templates/accounting/journal/index/details.hbs @@ -1,7 +1,7 @@ + diff --git a/addon/templates/billing/invoices/index/details.hbs b/addon/templates/billing/invoices/index/details.hbs index 6b5725e..4c1740f 100644 --- a/addon/templates/billing/invoices/index/details.hbs +++ b/addon/templates/billing/invoices/index/details.hbs @@ -1,7 +1,7 @@ + diff --git a/addon/templates/payments/gateways/index/details.hbs b/addon/templates/payments/gateways/index/details.hbs index 33ff173..1ecf9ac 100644 --- a/addon/templates/payments/gateways/index/details.hbs +++ b/addon/templates/payments/gateways/index/details.hbs @@ -1,7 +1,7 @@ + diff --git a/addon/templates/payments/transactions/index/details.hbs b/addon/templates/payments/transactions/index/details.hbs index 1cd5724..6f0d8b3 100644 --- a/addon/templates/payments/transactions/index/details.hbs +++ b/addon/templates/payments/transactions/index/details.hbs @@ -1,7 +1,7 @@ + diff --git a/addon/templates/payments/wallets/index/details.hbs b/addon/templates/payments/wallets/index/details.hbs index dfe11ac..0950457 100644 --- a/addon/templates/payments/wallets/index/details.hbs +++ b/addon/templates/payments/wallets/index/details.hbs @@ -1,7 +1,7 @@ + From a34e53fd6f734d49bc009bbb845820ff25d3ef62 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Mon, 2 Mar 2026 11:36:41 +0800 Subject: [PATCH 040/209] fixed controller app rexports and ran prettier --- .../accounting/accounts/index/details.js | 3 --- .../accounting/journal/index/details.js | 9 +-------- .../billing/invoices/index/details.js | 15 ++++----------- .../payments/gateways/index/details.js | 6 ------ addon/controllers/payments/transactions/index.js | 16 +++------------- .../payments/transactions/index/details.js | 7 +------ .../payments/wallets/index/details.js | 6 ------ addon/services/wallet-actions.js | 5 ++++- .../payments/transactions/index/details.hbs | 1 + .../{ledger => }/accounting/accounts/index.js | 0 .../accounting/accounts/index/details.js | 0 .../{ledger => }/accounting/journal/index.js | 0 .../accounting/journal/index/details.js | 0 .../{ledger => }/billing/invoices/index.js | 0 .../billing/invoices/index/details.js | 0 app/controllers/{ledger => }/home.js | 0 .../{ledger => }/payments/gateways/index.js | 0 .../payments/gateways/index/details.js | 0 .../{ledger => }/payments/transactions/index.js | 0 .../payments/transactions/index/details.js | 0 .../{ledger => }/payments/wallets/index.js | 0 .../payments/wallets/index/details.js | 0 app/controllers/{ledger => }/reports/index.js | 0 translations/en-us.yaml | 14 -------------- 24 files changed, 14 insertions(+), 68 deletions(-) rename app/controllers/{ledger => }/accounting/accounts/index.js (100%) rename app/controllers/{ledger => }/accounting/accounts/index/details.js (100%) rename app/controllers/{ledger => }/accounting/journal/index.js (100%) rename app/controllers/{ledger => }/accounting/journal/index/details.js (100%) rename app/controllers/{ledger => }/billing/invoices/index.js (100%) rename app/controllers/{ledger => }/billing/invoices/index/details.js (100%) rename app/controllers/{ledger => }/home.js (100%) rename app/controllers/{ledger => }/payments/gateways/index.js (100%) rename app/controllers/{ledger => }/payments/gateways/index/details.js (100%) rename app/controllers/{ledger => }/payments/transactions/index.js (100%) rename app/controllers/{ledger => }/payments/transactions/index/details.js (100%) rename app/controllers/{ledger => }/payments/wallets/index.js (100%) rename app/controllers/{ledger => }/payments/wallets/index/details.js (100%) rename app/controllers/{ledger => }/reports/index.js (100%) diff --git a/addon/controllers/accounting/accounts/index/details.js b/addon/controllers/accounting/accounts/index/details.js index a68211c..d53353f 100644 --- a/addon/controllers/accounting/accounts/index/details.js +++ b/addon/controllers/accounting/accounts/index/details.js @@ -4,7 +4,6 @@ import { tracked } from '@glimmer/tracking'; export default class AccountingAccountsIndexDetailsController extends Controller { @tracked overlay = null; - get tabs() { return [ { label: 'Overview', route: 'accounting.accounts.index.details.index' }, @@ -12,9 +11,7 @@ export default class AccountingAccountsIndexDetailsController extends Controller ]; } - get actionButtons() { return []; } - } diff --git a/addon/controllers/accounting/journal/index/details.js b/addon/controllers/accounting/journal/index/details.js index f79b6ce..fc7aa4d 100644 --- a/addon/controllers/accounting/journal/index/details.js +++ b/addon/controllers/accounting/journal/index/details.js @@ -8,24 +8,18 @@ export default class AccountingJournalIndexDetailsController extends Controller @service modalsManager; @service hostRouter; - @tracked overlay = null; - get tabs() { - return [ - { label: 'Overview', route: 'accounting.journal.index.details.index' }, - ]; + return [{ label: 'Overview', route: 'accounting.journal.index.details.index' }]; } - get actionButtons() { const entry = this.model; if (entry?.is_system_entry) return []; return [{ label: 'Delete', icon: 'trash', type: 'danger', onClick: this.deleteEntry }]; } - @action async deleteEntry() { const entry = this.model; this.modalsManager.confirm({ @@ -45,5 +39,4 @@ export default class AccountingJournalIndexDetailsController extends Controller }, }); } - } diff --git a/addon/controllers/billing/invoices/index/details.js b/addon/controllers/billing/invoices/index/details.js index a6e0d5f..a9b2124 100644 --- a/addon/controllers/billing/invoices/index/details.js +++ b/addon/controllers/billing/invoices/index/details.js @@ -9,10 +9,8 @@ export default class BillingInvoicesIndexDetailsController extends Controller { @service fetch; @service hostRouter; - @tracked overlay = null; - get tabs() { return [ { label: 'Details', route: 'billing.invoices.index.details.index' }, @@ -21,27 +19,25 @@ export default class BillingInvoicesIndexDetailsController extends Controller { ]; } - get actionButtons() { const invoice = this.model; const buttons = []; - + if (invoice?.status === 'draft') { buttons.push({ label: 'Send', icon: 'paper-plane', type: 'primary', onClick: this.sendInvoice }); } - + if (['sent', 'overdue', 'partial'].includes(invoice?.status)) { buttons.push({ label: 'Record Payment', icon: 'check-circle', type: 'success', onClick: this.recordPayment }); } - + if (!['paid', 'void'].includes(invoice?.status)) { buttons.push({ label: 'Void', icon: 'ban', type: 'danger', onClick: this.voidInvoice }); } - + return buttons; } - @action async sendInvoice() { const invoice = this.model; try { @@ -53,13 +49,11 @@ export default class BillingInvoicesIndexDetailsController extends Controller { } } - @action async recordPayment() { const invoice = this.model; this.modalsManager.show('modals/record-payment', { invoice }); } - @action async voidInvoice() { const invoice = this.model; this.modalsManager.confirm({ @@ -79,5 +73,4 @@ export default class BillingInvoicesIndexDetailsController extends Controller { }, }); } - } diff --git a/addon/controllers/payments/gateways/index/details.js b/addon/controllers/payments/gateways/index/details.js index 4197870..9c5783e 100644 --- a/addon/controllers/payments/gateways/index/details.js +++ b/addon/controllers/payments/gateways/index/details.js @@ -8,10 +8,8 @@ export default class PaymentsGatewaysIndexDetailsController extends Controller { @service modalsManager; @service hostRouter; - @tracked overlay = null; - get tabs() { return [ { label: 'Overview', route: 'payments.gateways.index.details.index' }, @@ -19,7 +17,6 @@ export default class PaymentsGatewaysIndexDetailsController extends Controller { ]; } - get actionButtons() { return [ { label: 'Edit', icon: 'pencil', onClick: this.editGateway }, @@ -27,13 +24,11 @@ export default class PaymentsGatewaysIndexDetailsController extends Controller { ]; } - @action editGateway() { const gateway = this.model; this.modalsManager.show('modals/gateway-form', { gateway }); } - @action async deleteGateway() { const gateway = this.model; this.modalsManager.confirm({ @@ -53,5 +48,4 @@ export default class PaymentsGatewaysIndexDetailsController extends Controller { }, }); } - } diff --git a/addon/controllers/payments/transactions/index.js b/addon/controllers/payments/transactions/index.js index 821f62a..13f937d 100644 --- a/addon/controllers/payments/transactions/index.js +++ b/addon/controllers/payments/transactions/index.js @@ -104,22 +104,13 @@ export default class PaymentsTransactionsIndexController extends Controller { filterable: true, filterParam: 'type', filterComponent: 'filter/multi-option', - filterOptions: [ - 'wallet_deposit', - 'wallet_withdrawal', - 'wallet_transfer', - 'gateway_charge', - 'gateway_refund', - 'gateway_payout', - 'adjustment', - 'earning', - 'fee', - ], + filterOptions: ['wallet_deposit', 'wallet_withdrawal', 'wallet_transfer', 'gateway_charge', 'gateway_refund', 'gateway_payout', 'adjustment', 'earning', 'fee'], }, { label: this.intl.t('column.direction'), valuePath: 'direction', - cellComponent: 'table/cell/status', + cellComponent: 'table/cell/base', + humanize: true, resizable: true, sortable: true, filterable: true, @@ -290,7 +281,6 @@ export default class PaymentsTransactionsIndexController extends Controller { fn: this.transactionActions.transition.view, permission: 'ledger view transaction', }, - ], sortable: false, filterable: false, diff --git a/addon/controllers/payments/transactions/index/details.js b/addon/controllers/payments/transactions/index/details.js index f0bf35e..fe9d054 100644 --- a/addon/controllers/payments/transactions/index/details.js +++ b/addon/controllers/payments/transactions/index/details.js @@ -4,16 +4,11 @@ import { tracked } from '@glimmer/tracking'; export default class PaymentsTransactionsIndexDetailsController extends Controller { @tracked overlay = null; - get tabs() { - return [ - { label: 'Overview', route: 'payments.transactions.index.details.index' }, - ]; + return [{ label: 'Overview', route: 'payments.transactions.index.details.index' }]; } - get actionButtons() { return []; } - } diff --git a/addon/controllers/payments/wallets/index/details.js b/addon/controllers/payments/wallets/index/details.js index f43bb2e..261860c 100644 --- a/addon/controllers/payments/wallets/index/details.js +++ b/addon/controllers/payments/wallets/index/details.js @@ -9,10 +9,8 @@ export default class PaymentsWalletsIndexDetailsController extends Controller { @service fetch; @service hostRouter; - @tracked overlay = null; - get tabs() { return [ { label: 'Overview', route: 'payments.wallets.index.details.index' }, @@ -20,7 +18,6 @@ export default class PaymentsWalletsIndexDetailsController extends Controller { ]; } - get actionButtons() { return [ { label: 'Top Up', icon: 'plus-circle', type: 'primary', onClick: this.topUpWallet }, @@ -28,16 +25,13 @@ export default class PaymentsWalletsIndexDetailsController extends Controller { ]; } - @action async topUpWallet() { const wallet = this.model; this.modalsManager.show('modals/wallet-top-up', { wallet }); } - @action async transferFunds() { const wallet = this.model; this.modalsManager.show('modals/wallet-transfer', { wallet }); } - } diff --git a/addon/services/wallet-actions.js b/addon/services/wallet-actions.js index b318efc..58ace3e 100644 --- a/addon/services/wallet-actions.js +++ b/addon/services/wallet-actions.js @@ -17,7 +17,10 @@ export default class WalletActionsService extends ResourceActionService { view: (wallet, options = {}) => { return this.resourceContextPanel.open({ wallet, - tabs: [{ label: this.intl.t('common.overview'), component: 'wallet/details' }, { label: this.intl.t('common.transactions'), component: 'wallet/transactions' }], + tabs: [ + { label: this.intl.t('common.overview'), component: 'wallet/details' }, + { label: this.intl.t('common.transactions'), component: 'wallet/transactions' }, + ], ...options, }); }, diff --git a/addon/templates/payments/transactions/index/details.hbs b/addon/templates/payments/transactions/index/details.hbs index 6f0d8b3..8d63888 100644 --- a/addon/templates/payments/transactions/index/details.hbs +++ b/addon/templates/payments/transactions/index/details.hbs @@ -9,6 +9,7 @@ @bodyClass="no-scroll" > + {{log this.tabs}} {{outlet}} diff --git a/app/controllers/ledger/accounting/accounts/index.js b/app/controllers/accounting/accounts/index.js similarity index 100% rename from app/controllers/ledger/accounting/accounts/index.js rename to app/controllers/accounting/accounts/index.js diff --git a/app/controllers/ledger/accounting/accounts/index/details.js b/app/controllers/accounting/accounts/index/details.js similarity index 100% rename from app/controllers/ledger/accounting/accounts/index/details.js rename to app/controllers/accounting/accounts/index/details.js diff --git a/app/controllers/ledger/accounting/journal/index.js b/app/controllers/accounting/journal/index.js similarity index 100% rename from app/controllers/ledger/accounting/journal/index.js rename to app/controllers/accounting/journal/index.js diff --git a/app/controllers/ledger/accounting/journal/index/details.js b/app/controllers/accounting/journal/index/details.js similarity index 100% rename from app/controllers/ledger/accounting/journal/index/details.js rename to app/controllers/accounting/journal/index/details.js diff --git a/app/controllers/ledger/billing/invoices/index.js b/app/controllers/billing/invoices/index.js similarity index 100% rename from app/controllers/ledger/billing/invoices/index.js rename to app/controllers/billing/invoices/index.js diff --git a/app/controllers/ledger/billing/invoices/index/details.js b/app/controllers/billing/invoices/index/details.js similarity index 100% rename from app/controllers/ledger/billing/invoices/index/details.js rename to app/controllers/billing/invoices/index/details.js diff --git a/app/controllers/ledger/home.js b/app/controllers/home.js similarity index 100% rename from app/controllers/ledger/home.js rename to app/controllers/home.js diff --git a/app/controllers/ledger/payments/gateways/index.js b/app/controllers/payments/gateways/index.js similarity index 100% rename from app/controllers/ledger/payments/gateways/index.js rename to app/controllers/payments/gateways/index.js diff --git a/app/controllers/ledger/payments/gateways/index/details.js b/app/controllers/payments/gateways/index/details.js similarity index 100% rename from app/controllers/ledger/payments/gateways/index/details.js rename to app/controllers/payments/gateways/index/details.js diff --git a/app/controllers/ledger/payments/transactions/index.js b/app/controllers/payments/transactions/index.js similarity index 100% rename from app/controllers/ledger/payments/transactions/index.js rename to app/controllers/payments/transactions/index.js diff --git a/app/controllers/ledger/payments/transactions/index/details.js b/app/controllers/payments/transactions/index/details.js similarity index 100% rename from app/controllers/ledger/payments/transactions/index/details.js rename to app/controllers/payments/transactions/index/details.js diff --git a/app/controllers/ledger/payments/wallets/index.js b/app/controllers/payments/wallets/index.js similarity index 100% rename from app/controllers/ledger/payments/wallets/index.js rename to app/controllers/payments/wallets/index.js diff --git a/app/controllers/ledger/payments/wallets/index/details.js b/app/controllers/payments/wallets/index/details.js similarity index 100% rename from app/controllers/ledger/payments/wallets/index/details.js rename to app/controllers/payments/wallets/index/details.js diff --git a/app/controllers/ledger/reports/index.js b/app/controllers/reports/index.js similarity index 100% rename from app/controllers/ledger/reports/index.js rename to app/controllers/reports/index.js diff --git a/translations/en-us.yaml b/translations/en-us.yaml index 4fc2c9b..5e06986 100644 --- a/translations/en-us.yaml +++ b/translations/en-us.yaml @@ -3,22 +3,8 @@ ledger: common: ledger: Ledger - new: New - refresh: Refresh overview: Overview transactions: Transactions - resource-actions: >- - {resource} Actions - view-resource: >- - View {resource} - edit-resource-name: >- - Edit {resource} - create-a-new-resource: >- - Create a new {resource} - delete-resource: >- - Delete {resource} - delete-selected-count: >- - Delete {count} selected resource: account: Account From 1cce964ec7d6dfb180e37286cb3226665f79a280 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 22:41:28 -0500 Subject: [PATCH 041/209] fix(app): correct re-export paths for payments controllers The following app/controllers re-exports were pointing at wrong addon paths: payments/gateways/index.js: settings/gateways/index -> payments/gateways/index payments/gateways/index/details.js: settings/gateways/index/details -> payments/gateways/index/details payments/transactions/index.js: billing/transactions/index -> payments/transactions/index payments/transactions/index/details.js: billing/transactions/index/details -> payments/transactions/index/details payments/wallets/index.js: wallets/index -> payments/wallets/index payments/wallets/index/details.js: wallets/index/details -> payments/wallets/index/details All re-export paths now verified against actual addon controller files. --- app/controllers/payments/gateways/index.js | 2 +- app/controllers/payments/gateways/index/details.js | 2 +- app/controllers/payments/transactions/index.js | 2 +- app/controllers/payments/transactions/index/details.js | 2 +- app/controllers/payments/wallets/index.js | 2 +- app/controllers/payments/wallets/index/details.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/payments/gateways/index.js b/app/controllers/payments/gateways/index.js index 680d3e8..df677a6 100644 --- a/app/controllers/payments/gateways/index.js +++ b/app/controllers/payments/gateways/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/controllers/settings/gateways/index'; +export { default } from '@fleetbase/ledger-engine/controllers/payments/gateways/index'; diff --git a/app/controllers/payments/gateways/index/details.js b/app/controllers/payments/gateways/index/details.js index cffca60..809e1b5 100644 --- a/app/controllers/payments/gateways/index/details.js +++ b/app/controllers/payments/gateways/index/details.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/controllers/settings/gateways/index/details'; +export { default } from '@fleetbase/ledger-engine/controllers/payments/gateways/index/details'; diff --git a/app/controllers/payments/transactions/index.js b/app/controllers/payments/transactions/index.js index df97650..8fe3f11 100644 --- a/app/controllers/payments/transactions/index.js +++ b/app/controllers/payments/transactions/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/controllers/billing/transactions/index'; +export { default } from '@fleetbase/ledger-engine/controllers/payments/transactions/index'; diff --git a/app/controllers/payments/transactions/index/details.js b/app/controllers/payments/transactions/index/details.js index ea27fff..bc6a57b 100644 --- a/app/controllers/payments/transactions/index/details.js +++ b/app/controllers/payments/transactions/index/details.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/controllers/billing/transactions/index/details'; +export { default } from '@fleetbase/ledger-engine/controllers/payments/transactions/index/details'; diff --git a/app/controllers/payments/wallets/index.js b/app/controllers/payments/wallets/index.js index ecf3eb4..964d882 100644 --- a/app/controllers/payments/wallets/index.js +++ b/app/controllers/payments/wallets/index.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/controllers/wallets/index'; +export { default } from '@fleetbase/ledger-engine/controllers/payments/wallets/index'; diff --git a/app/controllers/payments/wallets/index/details.js b/app/controllers/payments/wallets/index/details.js index a7b44f6..a2b4a27 100644 --- a/app/controllers/payments/wallets/index/details.js +++ b/app/controllers/payments/wallets/index/details.js @@ -1 +1 @@ -export { default } from '@fleetbase/ledger-engine/controllers/wallets/index/details'; +export { default } from '@fleetbase/ledger-engine/controllers/payments/wallets/index/details'; From 201a712239a0b28f49d11a7fcfd731b6c7e1c448 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 22:42:18 -0500 Subject: [PATCH 042/209] feat(frontend): add Layout::Resource::Panel::HeaderActions to all panel-header components All 6 resource panel-header components were missing the HeaderActions block which provides the close/exit button and action button rendering. Added to: - invoice/panel-header.hbs - transaction/panel-header.hbs - wallet/panel-header.hbs - gateway/panel-header.hbs - account/panel-header.hbs - journal/panel-header.hbs Each now includes:
--- addon/components/account/panel-header.hbs | 12 ++++++++++++ addon/components/gateway/panel-header.hbs | 12 ++++++++++++ addon/components/invoice/panel-header.hbs | 12 ++++++++++++ addon/components/journal/panel-header.hbs | 12 ++++++++++++ addon/components/transaction/panel-header.hbs | 12 ++++++++++++ addon/components/wallet/panel-header.hbs | 12 ++++++++++++ 6 files changed, 72 insertions(+) diff --git a/addon/components/account/panel-header.hbs b/addon/components/account/panel-header.hbs index 71a838c..2c2082d 100644 --- a/addon/components/account/panel-header.hbs +++ b/addon/components/account/panel-header.hbs @@ -12,4 +12,16 @@ {{n-a @resource.currency}}
+
+ +
diff --git a/addon/components/gateway/panel-header.hbs b/addon/components/gateway/panel-header.hbs index 82b2e9c..dbb7037 100644 --- a/addon/components/gateway/panel-header.hbs +++ b/addon/components/gateway/panel-header.hbs @@ -14,4 +14,16 @@ {{@resource.status_label}}
+
+ +
diff --git a/addon/components/invoice/panel-header.hbs b/addon/components/invoice/panel-header.hbs index a43ddf0..2656464 100644 --- a/addon/components/invoice/panel-header.hbs +++ b/addon/components/invoice/panel-header.hbs @@ -12,4 +12,16 @@ Due {{n-a @resource.dueDate}}
+
+ +
diff --git a/addon/components/journal/panel-header.hbs b/addon/components/journal/panel-header.hbs index 39267c9..581d4d0 100644 --- a/addon/components/journal/panel-header.hbs +++ b/addon/components/journal/panel-header.hbs @@ -12,4 +12,16 @@ {{n-a @resource.entryDate}}
+
+ +
diff --git a/addon/components/transaction/panel-header.hbs b/addon/components/transaction/panel-header.hbs index 1c8a735..114b92f 100644 --- a/addon/components/transaction/panel-header.hbs +++ b/addon/components/transaction/panel-header.hbs @@ -14,4 +14,16 @@ {{n-a @resource.currency}}
+
+ +
diff --git a/addon/components/wallet/panel-header.hbs b/addon/components/wallet/panel-header.hbs index 71bf5d7..4cfbefd 100644 --- a/addon/components/wallet/panel-header.hbs +++ b/addon/components/wallet/panel-header.hbs @@ -15,4 +15,16 @@ Balance
+
+ +
From da5d42d0e4e6ef6b93302a1073ad6fc024aa6ece Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Mon, 2 Mar 2026 12:01:49 +0800 Subject: [PATCH 043/209] fixed transaction panel-header --- addon/components/transaction/panel-header.hbs | 47 ++++++++++--------- addon/styles/ledger-engine.css | 3 ++ 2 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 addon/styles/ledger-engine.css diff --git a/addon/components/transaction/panel-header.hbs b/addon/components/transaction/panel-header.hbs index 114b92f..895ae67 100644 --- a/addon/components/transaction/panel-header.hbs +++ b/addon/components/transaction/panel-header.hbs @@ -1,29 +1,32 @@ -
+
-

{{n-a @resource.public_id}}

+

{{n-a @resource.public_id}}

- {{n-a @resource.type}} - {{@resource.status}} + {{titleize @resource.status}} + {{#if @resource.type}} + {{titleize @resource.type}} + {{/if}}
-
- - {{@resource.direction_sign}}{{n-a @resource.formatted_amount}} - - {{n-a @resource.currency}} +
+ +
+ + {{@resource.direction_sign}}{{format-currency @resource.amount @resource.currency}} + + {{n-a @resource.currency}} +
+
-
- -
-
+
\ No newline at end of file diff --git a/addon/styles/ledger-engine.css b/addon/styles/ledger-engine.css new file mode 100644 index 0000000..1799d04 --- /dev/null +++ b/addon/styles/ledger-engine.css @@ -0,0 +1,3 @@ +.f-child-items-start > * { + align-items: start !important; +} From 3c9b844b63ca5e6146dcd331b1d3234b3e5d77ec Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 23:05:22 -0500 Subject: [PATCH 044/209] feat(frontend): add Spacer @height=200px to bottom of all resource details components Provides scroll padding at the bottom of each details panel so content is not obscured by the panel footer when scrolled to the end. Applied to: invoice, transaction, wallet, gateway, account, journal details components. --- addon/components/account/details.hbs | 1 + addon/components/gateway/details.hbs | 1 + addon/components/invoice/details.hbs | 1 + addon/components/journal/details.hbs | 1 + addon/components/transaction/details.hbs | 1 + addon/components/wallet/details.hbs | 1 + 6 files changed, 6 insertions(+) diff --git a/addon/components/account/details.hbs b/addon/components/account/details.hbs index df96f98..4bb5ed5 100644 --- a/addon/components/account/details.hbs +++ b/addon/components/account/details.hbs @@ -74,4 +74,5 @@
+
diff --git a/addon/components/gateway/details.hbs b/addon/components/gateway/details.hbs index 75c7dfc..4041876 100644 --- a/addon/components/gateway/details.hbs +++ b/addon/components/gateway/details.hbs @@ -100,4 +100,5 @@
+
diff --git a/addon/components/invoice/details.hbs b/addon/components/invoice/details.hbs index a91fc55..8e86d2e 100644 --- a/addon/components/invoice/details.hbs +++ b/addon/components/invoice/details.hbs @@ -123,4 +123,5 @@
+
diff --git a/addon/components/journal/details.hbs b/addon/components/journal/details.hbs index 8a23421..d42b05c 100644 --- a/addon/components/journal/details.hbs +++ b/addon/components/journal/details.hbs @@ -105,4 +105,5 @@
+
diff --git a/addon/components/transaction/details.hbs b/addon/components/transaction/details.hbs index ee3beaa..b2bbac1 100644 --- a/addon/components/transaction/details.hbs +++ b/addon/components/transaction/details.hbs @@ -213,4 +213,5 @@
+
diff --git a/addon/components/wallet/details.hbs b/addon/components/wallet/details.hbs index c0933e7..327f454 100644 --- a/addon/components/wallet/details.hbs +++ b/addon/components/wallet/details.hbs @@ -81,4 +81,5 @@
+
From c425b1c1aa7b601b6395603f05df19bfb0dbba7a Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Mon, 2 Mar 2026 12:12:11 +0800 Subject: [PATCH 045/209] fix backend controller namings --- .../Controllers/Internal/v1/AccountController.php | 4 ++-- .../Controllers/Internal/v1/GatewayController.php | 4 ++-- .../Controllers/Internal/v1/InvoiceController.php | 4 ++-- .../Controllers/Internal/v1/JournalController.php | 4 ++-- .../Internal/v1/TransactionController.php | 6 +++--- .../Controllers/Internal/v1/WalletController.php | 4 ++-- .../Internal/v1/WalletTransactionController.php | 6 +++--- ...rController.php => LedgerResourceController.php} | 2 +- .../Http/Controllers/PalletResourceController.php | 13 ------------- server/src/Http/Resources/v1/GatewayTransaction.php | 2 -- server/src/Http/Resources/v1/Journal.php | 2 -- server/src/Http/Resources/v1/Transaction.php | 2 -- server/src/Models/Account.php | 10 +++++----- server/src/Models/InvoiceItem.php | 2 +- server/src/Models/Journal.php | 3 +-- 15 files changed, 24 insertions(+), 44 deletions(-) rename server/src/Http/Controllers/{LedgerController.php => LedgerResourceController.php} (81%) delete mode 100644 server/src/Http/Controllers/PalletResourceController.php diff --git a/server/src/Http/Controllers/Internal/v1/AccountController.php b/server/src/Http/Controllers/Internal/v1/AccountController.php index 1999b14..b597e30 100644 --- a/server/src/Http/Controllers/Internal/v1/AccountController.php +++ b/server/src/Http/Controllers/Internal/v1/AccountController.php @@ -2,14 +2,14 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; use Fleetbase\Ledger\Http\Resources\v1\Account as AccountResource; use Fleetbase\Ledger\Models\Account; use Fleetbase\Ledger\Services\LedgerService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -class AccountController extends LedgerController +class AccountController extends LedgerResourceController { /** * The resource to query. diff --git a/server/src/Http/Controllers/Internal/v1/GatewayController.php b/server/src/Http/Controllers/Internal/v1/GatewayController.php index 7beffcb..c77d9fe 100644 --- a/server/src/Http/Controllers/Internal/v1/GatewayController.php +++ b/server/src/Http/Controllers/Internal/v1/GatewayController.php @@ -4,7 +4,7 @@ use Fleetbase\Ledger\DTO\PurchaseRequest; use Fleetbase\Ledger\DTO\RefundRequest; -use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; use Fleetbase\Ledger\Http\Resources\v1\GatewayTransaction as GatewayTransactionResource; use Fleetbase\Ledger\Models\Gateway; use Fleetbase\Ledger\Models\GatewayTransaction; @@ -12,7 +12,7 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -class GatewayController extends LedgerController +class GatewayController extends LedgerResourceController { /** * The resource to query. diff --git a/server/src/Http/Controllers/Internal/v1/InvoiceController.php b/server/src/Http/Controllers/Internal/v1/InvoiceController.php index 2f3652e..ae890e6 100644 --- a/server/src/Http/Controllers/Internal/v1/InvoiceController.php +++ b/server/src/Http/Controllers/Internal/v1/InvoiceController.php @@ -2,13 +2,13 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; use Fleetbase\Ledger\Http\Resources\v1\Invoice as InvoiceResource; use Fleetbase\Ledger\Models\Invoice; use Fleetbase\Ledger\Services\InvoiceService; use Illuminate\Http\Request; -class InvoiceController extends LedgerController +class InvoiceController extends LedgerResourceController { /** * The resource to query. diff --git a/server/src/Http/Controllers/Internal/v1/JournalController.php b/server/src/Http/Controllers/Internal/v1/JournalController.php index 5c4287f..3b960b3 100644 --- a/server/src/Http/Controllers/Internal/v1/JournalController.php +++ b/server/src/Http/Controllers/Internal/v1/JournalController.php @@ -2,14 +2,14 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; use Fleetbase\Ledger\Http\Resources\v1\Journal as JournalResource; use Fleetbase\Ledger\Models\Journal; use Fleetbase\Ledger\Services\LedgerService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -class JournalController extends LedgerController +class JournalController extends LedgerResourceController { /** * The resource to query. diff --git a/server/src/Http/Controllers/Internal/v1/TransactionController.php b/server/src/Http/Controllers/Internal/v1/TransactionController.php index a6f9e8e..d355a28 100644 --- a/server/src/Http/Controllers/Internal/v1/TransactionController.php +++ b/server/src/Http/Controllers/Internal/v1/TransactionController.php @@ -2,18 +2,18 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; /** * TransactionController. * * Read-only view of Ledger Transaction records (which extend the core-api * Transaction model with a journal relationship). All CRUD and filtering is - * handled by HasApiControllerBehavior via LedgerController. The TransactionFilter + * handled by HasApiControllerBehavior via LedgerResourceController. The TransactionFilter * applies company scoping. The Transaction resource includes the journal * relationship via whenLoaded(). */ -class TransactionController extends LedgerController +class TransactionController extends LedgerResourceController { /** * The resource to query. diff --git a/server/src/Http/Controllers/Internal/v1/WalletController.php b/server/src/Http/Controllers/Internal/v1/WalletController.php index fb35e8a..c977595 100644 --- a/server/src/Http/Controllers/Internal/v1/WalletController.php +++ b/server/src/Http/Controllers/Internal/v1/WalletController.php @@ -2,7 +2,7 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; use Fleetbase\Ledger\Http\Resources\v1\Wallet as WalletResource; use Fleetbase\Ledger\Http\Resources\v1\WalletTransaction as WalletTransactionResource; use Fleetbase\Ledger\Models\Wallet; @@ -12,7 +12,7 @@ use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; -class WalletController extends LedgerController +class WalletController extends LedgerResourceController { /** * The resource to query. diff --git a/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php b/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php index 7a4fce5..5813392 100644 --- a/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php +++ b/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php @@ -2,17 +2,17 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; -use Fleetbase\Ledger\Http\Controllers\LedgerController; +use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; /** * WalletTransactionController. * * Provides a company-scoped query/find endpoint for wallet transactions * across all wallets. All CRUD is handled by HasApiControllerBehavior via - * LedgerController; the WalletTransactionFilter handles company scoping + * LedgerResourceController; the WalletTransactionFilter handles company scoping * and parameter filtering automatically. */ -class WalletTransactionController extends LedgerController +class WalletTransactionController extends LedgerResourceController { /** * The resource to query. diff --git a/server/src/Http/Controllers/LedgerController.php b/server/src/Http/Controllers/LedgerResourceController.php similarity index 81% rename from server/src/Http/Controllers/LedgerController.php rename to server/src/Http/Controllers/LedgerResourceController.php index 70fac7f..e7e0de7 100644 --- a/server/src/Http/Controllers/LedgerController.php +++ b/server/src/Http/Controllers/LedgerResourceController.php @@ -4,7 +4,7 @@ use Fleetbase\Http\Controllers\FleetbaseController; -class LedgerController extends FleetbaseController +class LedgerResourceController extends FleetbaseController { /** * The package namespace used to resolve models, resources, filters, and requests. diff --git a/server/src/Http/Controllers/PalletResourceController.php b/server/src/Http/Controllers/PalletResourceController.php deleted file mode 100644 index 71ff8fb..0000000 --- a/server/src/Http/Controllers/PalletResourceController.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Sun, 1 Mar 2026 23:15:04 -0500 Subject: [PATCH 046/209] fix(backend): call parent::__construct() in WalletController and GatewayController MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both controllers extend LedgerResourceController -> FleetbaseController, whose constructor calls setApiModel() and setApiResource() via HasApiControllerBehavior. These methods resolve and wire up $this->model, $this->resource, $this->request, $this->service, $this->resourcePluralName, and $this->resourceSingularlName — all required for the inherited CRUD actions (index, show, store, update, destroy) to function correctly. By overriding __construct() without calling parent::__construct(), the entire controller bootstrap was skipped, breaking all inherited API actions. Fix: remove promoted-property shorthand, store injected service explicitly, and call parent::__construct() first so the framework wiring runs before any service assignment. --- .../Http/Controllers/Internal/v1/GatewayController.php | 9 ++++++++- .../Http/Controllers/Internal/v1/WalletController.php | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/server/src/Http/Controllers/Internal/v1/GatewayController.php b/server/src/Http/Controllers/Internal/v1/GatewayController.php index c77d9fe..322cde1 100644 --- a/server/src/Http/Controllers/Internal/v1/GatewayController.php +++ b/server/src/Http/Controllers/Internal/v1/GatewayController.php @@ -21,8 +21,15 @@ class GatewayController extends LedgerResourceController */ public $resource = 'gateway'; - public function __construct(protected PaymentService $paymentService) + /** + * The PaymentService instance. + */ + protected PaymentService $paymentService; + + public function __construct(PaymentService $paymentService) { + parent::__construct(); + $this->paymentService = $paymentService; } /** diff --git a/server/src/Http/Controllers/Internal/v1/WalletController.php b/server/src/Http/Controllers/Internal/v1/WalletController.php index c977595..7fad893 100644 --- a/server/src/Http/Controllers/Internal/v1/WalletController.php +++ b/server/src/Http/Controllers/Internal/v1/WalletController.php @@ -21,8 +21,15 @@ class WalletController extends LedgerResourceController */ public $resource = 'wallet'; - public function __construct(protected WalletService $walletService) + /** + * The WalletService instance. + */ + protected WalletService $walletService; + + public function __construct(WalletService $walletService) { + parent::__construct(); + $this->walletService = $walletService; } // ========================================================================= From 275a014ad009e8d234b2f61befe74c32a9eebadc Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 23:27:39 -0500 Subject: [PATCH 047/209] refactor(wallet): remove WalletTransaction in favour of core Transaction model - Delete WalletTransaction model, controller, resource, filter (backend) - Delete ledger-wallet-transaction model, adapter, serializer (frontend) - Delete wallet-transaction-actions service (frontend) - Delete all app/ re-exports for wallet-transaction - Update WalletService: all deposit/withdraw/transfer now create Transaction records with owner_uuid=wallet.uuid, owner_type=Wallet::class - Update WalletController: getTransactions queries Transaction by owner_uuid - Update WalletApiController: getTransactions and topUp use TransactionResource - Update LedgerService: getCashFlowSummary queries Transaction instead of WalletTransaction - Update ReportController: period stats query Transaction instead of WalletTransaction - Update Wallet model: transactions/completedTransactions/credits/debits relationships now use Transaction with owner_uuid foreign key - Remove wallet-transactions route from routes.php - Update ledger adapter/serializer comments to reference ledger-transaction --- addon/adapters/ledger-wallet-transaction.js | 1 - addon/adapters/ledger.js | 2 +- addon/models/ledger-wallet-transaction.js | 61 ----- .../serializers/ledger-wallet-transaction.js | 1 - addon/serializers/ledger.js | 2 +- addon/services/wallet-transaction-actions.js | 25 -- app/adapters/ledger-wallet-transaction.js | 1 - app/models/ledger-wallet-transaction.js | 1 - app/serializers/ledger-wallet-transaction.js | 1 - app/services/wallet-transaction-actions.js | 1 - .../Api/v1/WalletApiController.php | 16 +- .../Internal/v1/ReportController.php | 8 +- .../Internal/v1/WalletController.php | 25 +- .../v1/WalletTransactionController.php | 23 -- .../Http/Filter/WalletTransactionFilter.php | 64 ----- .../Http/Resources/v1/WalletTransaction.php | 48 ---- server/src/Models/Wallet.php | 26 +- server/src/Models/WalletTransaction.php | 234 ------------------ server/src/Services/LedgerService.php | 24 +- server/src/Services/WalletService.php | 142 +++++------ server/src/routes.php | 5 - 21 files changed, 120 insertions(+), 591 deletions(-) delete mode 100644 addon/adapters/ledger-wallet-transaction.js delete mode 100644 addon/models/ledger-wallet-transaction.js delete mode 100644 addon/serializers/ledger-wallet-transaction.js delete mode 100644 addon/services/wallet-transaction-actions.js delete mode 100644 app/adapters/ledger-wallet-transaction.js delete mode 100644 app/models/ledger-wallet-transaction.js delete mode 100644 app/serializers/ledger-wallet-transaction.js delete mode 100644 app/services/wallet-transaction-actions.js delete mode 100644 server/src/Http/Controllers/Internal/v1/WalletTransactionController.php delete mode 100644 server/src/Http/Filter/WalletTransactionFilter.php delete mode 100644 server/src/Http/Resources/v1/WalletTransaction.php delete mode 100644 server/src/Models/WalletTransaction.php diff --git a/addon/adapters/ledger-wallet-transaction.js b/addon/adapters/ledger-wallet-transaction.js deleted file mode 100644 index 35354ab..0000000 --- a/addon/adapters/ledger-wallet-transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ledger'; diff --git a/addon/adapters/ledger.js b/addon/adapters/ledger.js index 19f8c1a..9094155 100644 --- a/addon/adapters/ledger.js +++ b/addon/adapters/ledger.js @@ -7,7 +7,7 @@ export default class LedgerAdapter extends ApplicationAdapter { /** * Strip the 'ledger-' prefix from the model name before building the URL path. - * e.g. 'ledger-account' -> 'accounts', 'ledger-wallet-transaction' -> 'wallet-transactions' + * e.g. 'ledger-account' -> 'accounts', 'ledger-transaction' -> 'transactions' */ pathForType(modelName) { return pluralize(dasherize(modelName)).replace('ledger-', ''); diff --git a/addon/models/ledger-wallet-transaction.js b/addon/models/ledger-wallet-transaction.js deleted file mode 100644 index 85fd76f..0000000 --- a/addon/models/ledger-wallet-transaction.js +++ /dev/null @@ -1,61 +0,0 @@ -import Model, { attr } from '@ember-data/model'; -import { computed } from '@ember/object'; -import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns'; - -export default class LedgerWalletTransactionModel extends Model { - @attr('string') public_id; - @attr('string') wallet_uuid; - @attr('string') type; - @attr('string') direction; - @attr('string') status; - @attr('string') currency; - @attr('number') amount; - @attr('number') balance_after; - @attr('string') reference; - @attr('string') description; - @attr('string') notes; - @attr('raw') meta; - @attr('date') created_at; - @attr('date') updated_at; - - @computed('created_at') get createdAtAgo() { - if (!isValidDate(this.created_at)) { - return null; - } - return formatDistanceToNow(this.created_at); - } - - @computed('created_at') get createdAt() { - if (!isValidDate(this.created_at)) { - return null; - } - return formatDate(this.created_at, 'PP HH:mm'); - } - - @computed('created_at') get createdAtShort() { - if (!isValidDate(this.created_at)) { - return null; - } - return formatDate(this.created_at, 'dd, MMM'); - } - @computed('updated_at') get updatedAtAgo() { - if (!isValidDate(this.updated_at)) { - return null; - } - return formatDistanceToNow(this.updated_at); - } - - @computed('updated_at') get updatedAt() { - if (!isValidDate(this.updated_at)) { - return null; - } - return formatDate(this.updated_at, 'PP HH:mm'); - } - - @computed('updated_at') get updatedAtShort() { - if (!isValidDate(this.updated_at)) { - return null; - } - return formatDate(this.updated_at, 'dd, MMM'); - } -} diff --git a/addon/serializers/ledger-wallet-transaction.js b/addon/serializers/ledger-wallet-transaction.js deleted file mode 100644 index 35354ab..0000000 --- a/addon/serializers/ledger-wallet-transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ledger'; diff --git a/addon/serializers/ledger.js b/addon/serializers/ledger.js index 0eb5db1..d12a708 100644 --- a/addon/serializers/ledger.js +++ b/addon/serializers/ledger.js @@ -13,7 +13,7 @@ const LedgerSerializerBase = ApplicationSerializer.extend(EmbeddedRecordsMixin); * * Payload key -> Ember model name: 'account' -> 'ledger-account' * Ember model name -> payload key: 'ledger-account' -> 'account' - * 'ledger-wallet-transaction' -> 'wallet_transaction' + * 'ledger-transaction' -> 'transaction' */ export default class LedgerSerializer extends LedgerSerializerBase { /** diff --git a/addon/services/wallet-transaction-actions.js b/addon/services/wallet-transaction-actions.js deleted file mode 100644 index 5fd9fe5..0000000 --- a/addon/services/wallet-transaction-actions.js +++ /dev/null @@ -1,25 +0,0 @@ -import ResourceActionService from '@fleetbase/ember-core/services/resource-action'; - -export default class WalletTransactionActionsService extends ResourceActionService { - constructor() { - super(...arguments); - this.initialize('ledger-wallet-transaction', { - permissionPrefix: 'ledger', - mountPrefix: 'console.ledger', - }); - } - - transition = { - view: (walletTransaction) => this.transitionTo('payments.wallets.index.details.transactions', walletTransaction), - }; - - panel = { - view: (walletTransaction, options = {}) => { - return this.resourceContextPanel.open({ - walletTransaction, - tabs: [{ label: this.intl.t('common.overview'), component: 'wallet-transaction/details' }], - ...options, - }); - }, - }; -} diff --git a/app/adapters/ledger-wallet-transaction.js b/app/adapters/ledger-wallet-transaction.js deleted file mode 100644 index e0eff48..0000000 --- a/app/adapters/ledger-wallet-transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/adapters/ledger-wallet-transaction'; diff --git a/app/models/ledger-wallet-transaction.js b/app/models/ledger-wallet-transaction.js deleted file mode 100644 index 942a445..0000000 --- a/app/models/ledger-wallet-transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/models/ledger-wallet-transaction'; diff --git a/app/serializers/ledger-wallet-transaction.js b/app/serializers/ledger-wallet-transaction.js deleted file mode 100644 index a77daf9..0000000 --- a/app/serializers/ledger-wallet-transaction.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/serializers/ledger-wallet-transaction'; diff --git a/app/services/wallet-transaction-actions.js b/app/services/wallet-transaction-actions.js deleted file mode 100644 index 9f9b742..0000000 --- a/app/services/wallet-transaction-actions.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@fleetbase/ledger-engine/services/wallet-transaction-actions'; diff --git a/server/src/Http/Controllers/Api/v1/WalletApiController.php b/server/src/Http/Controllers/Api/v1/WalletApiController.php index 00069db..3b2da9d 100644 --- a/server/src/Http/Controllers/Api/v1/WalletApiController.php +++ b/server/src/Http/Controllers/Api/v1/WalletApiController.php @@ -3,10 +3,10 @@ namespace Fleetbase\Ledger\Http\Controllers\Api\v1; use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Ledger\Http\Resources\v1\Transaction as TransactionResource; use Fleetbase\Ledger\Http\Resources\v1\Wallet as WalletResource; -use Fleetbase\Ledger\Http\Resources\v1\WalletTransaction as WalletTransactionResource; +use Fleetbase\Ledger\Models\Transaction; use Fleetbase\Ledger\Models\Wallet; -use Fleetbase\Ledger\Models\WalletTransaction; use Fleetbase\Ledger\Services\WalletService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -51,10 +51,10 @@ public function getWallet(Request $request): WalletResource * GET /api/v1/ledger/wallet/balance * * Returns: - * - balance (int) Balance in smallest currency unit (cents) + * - balance (int) Balance in smallest currency unit (cents) * - formatted_balance (string) Human-readable balance (e.g., "10.50") - * - currency (string) ISO 4217 currency code - * - status (string) Wallet status + * - currency (string) ISO 4217 currency code + * - status (string) Wallet status */ public function getBalance(Request $request): JsonResponse { @@ -82,7 +82,7 @@ public function getTransactions(Request $request): AnonymousResourceCollection $subject = $this->resolveSubject($request); $wallet = $this->walletService->getOrCreateWallet($subject); - $transactions = WalletTransaction::where('wallet_uuid', $wallet->uuid) + $transactions = Transaction::where('owner_uuid', $wallet->uuid) ->when($request->filled('type'), fn ($q) => $q->where('type', $request->input('type'))) ->when($request->filled('direction'), fn ($q) => $q->where('direction', $request->input('direction'))) ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) @@ -91,7 +91,7 @@ public function getTransactions(Request $request): AnonymousResourceCollection ->orderBy('created_at', 'desc') ->paginate($request->input('limit', 25)); - return WalletTransactionResource::collection($transactions); + return TransactionResource::collection($transactions); } /** @@ -139,7 +139,7 @@ public function topUp(Request $request): JsonResponse ]; if ($result['transaction']) { - $response['transaction'] = new WalletTransactionResource($result['transaction']); + $response['transaction'] = new TransactionResource($result['transaction']); } return response()->json($response); diff --git a/server/src/Http/Controllers/Internal/v1/ReportController.php b/server/src/Http/Controllers/Internal/v1/ReportController.php index 2fa6853..8154a89 100644 --- a/server/src/Http/Controllers/Internal/v1/ReportController.php +++ b/server/src/Http/Controllers/Internal/v1/ReportController.php @@ -4,7 +4,7 @@ use Fleetbase\Http\Controllers\Controller; use Fleetbase\Ledger\Models\Wallet; -use Fleetbase\Ledger\Models\WalletTransaction; +use Fleetbase\Ledger\Models\Transaction; use Fleetbase\Ledger\Services\LedgerService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -339,8 +339,8 @@ public function walletSummary(Request $request): JsonResponse }); // Period credits and debits - $periodStats = WalletTransaction::where('company_uuid', $companyUuid) - ->where('status', WalletTransaction::STATUS_COMPLETED) + $periodStats = Transaction::where('company_uuid', $companyUuid) + ->where('status', 'completed') ->whereBetween(DB::raw('DATE(created_at)'), [$dateFrom, $dateTo]) ->select( 'direction', @@ -354,7 +354,7 @@ public function walletSummary(Request $request): JsonResponse ->map(function ($rows) { $result = ['credits' => 0, 'debits' => 0, 'credit_count' => 0, 'debit_count' => 0]; foreach ($rows as $row) { - if ($row->direction === WalletTransaction::DIRECTION_CREDIT) { + if ($row->direction === 'credit') { $result['credits'] = (int) $row->total; $result['credit_count'] = (int) $row->count; } else { diff --git a/server/src/Http/Controllers/Internal/v1/WalletController.php b/server/src/Http/Controllers/Internal/v1/WalletController.php index 7fad893..c096092 100644 --- a/server/src/Http/Controllers/Internal/v1/WalletController.php +++ b/server/src/Http/Controllers/Internal/v1/WalletController.php @@ -3,10 +3,10 @@ namespace Fleetbase\Ledger\Http\Controllers\Internal\v1; use Fleetbase\Ledger\Http\Controllers\LedgerResourceController; +use Fleetbase\Ledger\Http\Resources\v1\Transaction as TransactionResource; use Fleetbase\Ledger\Http\Resources\v1\Wallet as WalletResource; -use Fleetbase\Ledger\Http\Resources\v1\WalletTransaction as WalletTransactionResource; +use Fleetbase\Ledger\Models\Transaction; use Fleetbase\Ledger\Models\Wallet; -use Fleetbase\Ledger\Models\WalletTransaction; use Fleetbase\Ledger\Services\WalletService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -60,7 +60,7 @@ public function transfer(string $id, Request $request): JsonResponse return response()->json([ 'from_wallet' => new WalletResource($fromWallet->fresh()), 'to_wallet' => new WalletResource($toWallet->fresh()), - 'transaction' => new WalletTransactionResource($result), + 'transaction' => new TransactionResource($result), ]); } @@ -70,10 +70,10 @@ public function transfer(string $id, Request $request): JsonResponse public function topUp(string $id, Request $request): JsonResponse { $request->validate([ - 'amount' => 'required|integer|min:1', - 'gateway_uuid' => 'required|uuid', - 'payment_method_token' => 'required|string', - 'description' => 'nullable|string|max:500', + 'amount' => 'required|integer|min:1', + 'gateway_uuid' => 'required|uuid', + 'payment_method_token' => 'required|string', + 'description' => 'nullable|string|max:500', ]); $wallet = $this->resolveWallet($id); @@ -93,7 +93,7 @@ public function topUp(string $id, Request $request): JsonResponse ]; if ($result['transaction']) { - $response['transaction'] = new WalletTransactionResource($result['transaction']); + $response['transaction'] = new TransactionResource($result['transaction']); } return response()->json($response); @@ -116,13 +116,13 @@ public function payout(string $id, Request $request): JsonResponse wallet: $wallet, amount: $request->integer('amount'), description: $request->input('description', 'Driver payout'), - type: WalletTransaction::TYPE_PAYOUT, + type: 'payout', options: ['reference' => $request->input('reference')] ); return response()->json([ 'wallet' => new WalletResource($wallet->fresh()), - 'transaction' => new WalletTransactionResource($transaction), + 'transaction' => new TransactionResource($transaction), ]); } @@ -132,12 +132,13 @@ public function payout(string $id, Request $request): JsonResponse /** * Get the transaction history for a specific wallet. + * Queries the core Transaction model filtered by owner (wallet). */ public function getTransactions(string $id, Request $request): AnonymousResourceCollection { $wallet = $this->resolveWallet($id); - $transactions = WalletTransaction::where('wallet_uuid', $wallet->uuid) + $transactions = Transaction::where('owner_uuid', $wallet->uuid) ->when($request->filled('type'), fn ($q) => $q->where('type', $request->input('type'))) ->when($request->filled('direction'), fn ($q) => $q->where('direction', $request->input('direction'))) ->when($request->filled('status'), fn ($q) => $q->where('status', $request->input('status'))) @@ -146,7 +147,7 @@ public function getTransactions(string $id, Request $request): AnonymousResource ->orderBy('created_at', 'desc') ->paginate($request->input('limit', 25)); - return WalletTransactionResource::collection($transactions); + return TransactionResource::collection($transactions); } // ========================================================================= diff --git a/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php b/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php deleted file mode 100644 index 5813392..0000000 --- a/server/src/Http/Controllers/Internal/v1/WalletTransactionController.php +++ /dev/null @@ -1,23 +0,0 @@ -builder - ->where('company_uuid', $this->session->get('company')) - ->with(['wallet']); - } - - public function queryForPublic(): void - { - $this->builder->where('company_uuid', $this->session->get('company')); - } - - public function query(?string $searchQuery): void - { - $this->builder->where(function ($q) use ($searchQuery) { - $q->searchWhere('description', $searchQuery) - ->orWhere('reference', 'like', "%{$searchQuery}%") - ->orWhere('public_id', 'like', "%{$searchQuery}%"); - }); - } - - public function type(?string $type): void - { - $this->builder->where('type', $type); - } - - public function direction(?string $direction): void - { - $this->builder->where('direction', $direction); - } - - public function status(?string $status): void - { - $this->builder->where('status', $status); - } - - public function wallet(?string $wallet): void - { - $this->builder->where('wallet_uuid', $wallet); - } - - public function publicId(?string $publicId): void - { - $this->builder->searchWhere('public_id', $publicId); - } - - public function createdAt($createdAt): void - { - $createdAt = \Fleetbase\Support\Utils::dateRange($createdAt); - if (is_array($createdAt)) { - $this->builder->whereBetween('created_at', $createdAt); - } else { - $this->builder->whereDate('created_at', $createdAt); - } - } -} diff --git a/server/src/Http/Resources/v1/WalletTransaction.php b/server/src/Http/Resources/v1/WalletTransaction.php deleted file mode 100644 index 7de793d..0000000 --- a/server/src/Http/Resources/v1/WalletTransaction.php +++ /dev/null @@ -1,48 +0,0 @@ - $this->when(Http::isInternalRequest(), $this->id, $this->public_id), - 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid), - 'public_id' => $this->public_id, - 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid), - 'wallet_uuid' => $this->when(Http::isInternalRequest(), $this->wallet_uuid), - 'wallet' => $this->whenLoaded('wallet'), - 'type' => $this->type, - 'direction' => $this->direction, - 'status' => $this->status, - 'amount' => $this->amount, - 'formatted_amount' => $this->formatted_amount, - 'balance_after' => $this->balance_after, - 'currency' => $this->currency, - 'description' => $this->description, - 'reference' => $this->reference, - 'subject_uuid' => $this->when(Http::isInternalRequest(), $this->subject_uuid), - 'subject_type' => $this->when(Http::isInternalRequest(), $this->subject_type), - 'subject' => $this->whenLoaded('subject'), - 'meta' => $this->meta, - 'created_at' => $this->created_at, - 'updated_at' => $this->updated_at, - ]; - } -} diff --git a/server/src/Models/Wallet.php b/server/src/Models/Wallet.php index 35230fb..9888857 100644 --- a/server/src/Models/Wallet.php +++ b/server/src/Models/Wallet.php @@ -11,6 +11,7 @@ use Fleetbase\Traits\HasUuid; use Fleetbase\Traits\Searchable; use Fleetbase\Traits\TracksApiCredential; +use Fleetbase\Ledger\Models\Transaction; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\SoftDeletes; @@ -22,7 +23,7 @@ * Wallets are polymorphic — they can belong to a Driver, Customer, or Company. * * Balance is always stored as an integer in the smallest currency unit (cents). - * Every balance change MUST produce a corresponding WalletTransaction record. + * Every balance change MUST produce a corresponding Transaction record. * * Wallet types (inferred from subject_type): * - driver : Earnings wallet for FleetOps drivers @@ -125,10 +126,11 @@ public function subject(): MorphTo /** * All transactions on this wallet. + * Transactions are linked via owner_uuid / owner_type on the core Transaction model. */ public function transactions(): HasMany { - return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') + return $this->hasMany(Transaction::class, 'owner_uuid', 'uuid') ->orderBy('created_at', 'desc'); } @@ -137,8 +139,8 @@ public function transactions(): HasMany */ public function completedTransactions(): HasMany { - return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') - ->where('status', WalletTransaction::STATUS_COMPLETED) + return $this->hasMany(Transaction::class, 'owner_uuid', 'uuid') + ->where('status', 'completed') ->orderBy('created_at', 'desc'); } @@ -147,9 +149,9 @@ public function completedTransactions(): HasMany */ public function credits(): HasMany { - return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') - ->where('direction', WalletTransaction::DIRECTION_CREDIT) - ->where('status', WalletTransaction::STATUS_COMPLETED); + return $this->hasMany(Transaction::class, 'owner_uuid', 'uuid') + ->where('direction', 'credit') + ->where('status', 'completed'); } /** @@ -157,9 +159,9 @@ public function credits(): HasMany */ public function debits(): HasMany { - return $this->hasMany(WalletTransaction::class, 'wallet_uuid', 'uuid') - ->where('direction', WalletTransaction::DIRECTION_DEBIT) - ->where('status', WalletTransaction::STATUS_COMPLETED); + return $this->hasMany(Transaction::class, 'owner_uuid', 'uuid') + ->where('direction', 'debit') + ->where('status', 'completed'); } // ------------------------------------------------------------------------- @@ -286,7 +288,7 @@ public function close(): void /** * Credit the wallet balance by the given amount and return the new balance. * This method ONLY updates the balance column. Callers MUST also create - * a WalletTransaction record to maintain the audit trail. + * a Transaction record to maintain the audit trail. * * @param int $amount Amount in smallest currency unit (cents) * @@ -303,7 +305,7 @@ public function credit(int $amount): int /** * Debit the wallet balance by the given amount and return the new balance. * This method ONLY updates the balance column. Callers MUST also create - * a WalletTransaction record to maintain the audit trail. + * a Transaction record to maintain the audit trail. * * @param int $amount Amount in smallest currency unit (cents) * diff --git a/server/src/Models/WalletTransaction.php b/server/src/Models/WalletTransaction.php deleted file mode 100644 index 74a6bde..0000000 --- a/server/src/Models/WalletTransaction.php +++ /dev/null @@ -1,234 +0,0 @@ - 'integer', - 'balance_after' => 'integer', - 'meta' => 'array', - ]; - - /** - * The attributes that should be appended. - */ - protected $appends = ['public_id']; - - // ------------------------------------------------------------------------- - // Transaction Type Constants - // ------------------------------------------------------------------------- - - public const TYPE_DEPOSIT = 'deposit'; - public const TYPE_WITHDRAWAL = 'withdrawal'; - public const TYPE_TRANSFER_IN = 'transfer_in'; - public const TYPE_TRANSFER_OUT = 'transfer_out'; - public const TYPE_PAYOUT = 'payout'; - public const TYPE_FEE = 'fee'; - public const TYPE_REFUND = 'refund'; - public const TYPE_ADJUSTMENT = 'adjustment'; - public const TYPE_EARNING = 'earning'; - - // ------------------------------------------------------------------------- - // Direction Constants - // ------------------------------------------------------------------------- - - public const DIRECTION_CREDIT = 'credit'; - public const DIRECTION_DEBIT = 'debit'; - - // ------------------------------------------------------------------------- - // Status Constants - // ------------------------------------------------------------------------- - - public const STATUS_PENDING = 'pending'; - public const STATUS_COMPLETED = 'completed'; - public const STATUS_FAILED = 'failed'; - public const STATUS_REVERSED = 'reversed'; - - // ------------------------------------------------------------------------- - // Relationships - // ------------------------------------------------------------------------- - - /** - * The wallet this transaction belongs to. - */ - public function wallet(): BelongsTo - { - return $this->belongsTo(Wallet::class, 'wallet_uuid', 'uuid'); - } - - /** - * The gateway transaction that triggered this wallet transaction (if any). - */ - public function gatewayTransaction(): BelongsTo - { - return $this->belongsTo(GatewayTransaction::class, 'gateway_transaction_uuid', 'uuid'); - } - - /** - * Polymorphic subject — the entity this transaction relates to. - * Uses the 'subject' naming convention per Fleetbase standards. - * - * Can be: Driver, Customer, Order, Invoice, etc. - */ - public function subject(): MorphTo - { - return $this->morphTo(__FUNCTION__, 'subject_type', 'subject_uuid'); - } - - // ------------------------------------------------------------------------- - // Scopes - // ------------------------------------------------------------------------- - - /** - * Scope to credits only. - */ - public function scopeCredits($query) - { - return $query->where('direction', self::DIRECTION_CREDIT); - } - - /** - * Scope to debits only. - */ - public function scopeDebits($query) - { - return $query->where('direction', self::DIRECTION_DEBIT); - } - - /** - * Scope to completed transactions only. - */ - public function scopeCompleted($query) - { - return $query->where('status', self::STATUS_COMPLETED); - } - - /** - * Scope to a specific type. - */ - public function scopeOfType($query, string $type) - { - return $query->where('type', $type); - } - - // ------------------------------------------------------------------------- - // Helpers - // ------------------------------------------------------------------------- - - /** - * Get the amount formatted as a decimal string. - * e.g., 1050 cents → "10.50". - */ - public function getFormattedAmountAttribute(): string - { - return number_format($this->amount / 100, 2); - } - - /** - * Whether this transaction is a credit (money in). - */ - public function isCredit(): bool - { - return $this->direction === self::DIRECTION_CREDIT; - } - - /** - * Whether this transaction is a debit (money out). - */ - public function isDebit(): bool - { - return $this->direction === self::DIRECTION_DEBIT; - } - - /** - * Whether this transaction has completed. - */ - public function isCompleted(): bool - { - return $this->status === self::STATUS_COMPLETED; - } -} diff --git a/server/src/Services/LedgerService.php b/server/src/Services/LedgerService.php index 6d50f76..f2261ba 100644 --- a/server/src/Services/LedgerService.php +++ b/server/src/Services/LedgerService.php @@ -6,8 +6,7 @@ use Fleetbase\Ledger\Models\Invoice; use Fleetbase\Ledger\Models\Journal; use Fleetbase\Ledger\Models\Wallet; -use Fleetbase\Ledger\Models\WalletTransaction; -use Fleetbase\Models\Transaction; +use Fleetbase\Ledger\Models\Transaction; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; @@ -464,8 +463,8 @@ public function getCashFlowSummary(string $companyUuid, ?string $startDate = nul $endDate = $endDate ?? now()->toDateString(); // Derive cash flows from wallet transactions (most reliable cash proxy) - $walletStats = WalletTransaction::where('company_uuid', $companyUuid) - ->where('status', WalletTransaction::STATUS_COMPLETED) + $walletStats = Transaction::where('company_uuid', $companyUuid) + ->where('status', 'completed') ->whereBetween(DB::raw('DATE(created_at)'), [$startDate, $endDate]) ->select( 'type', @@ -481,19 +480,8 @@ public function getCashFlowSummary(string $companyUuid, ?string $startDate = nul $financing = []; $investing = []; - $operatingTypes = [ - WalletTransaction::TYPE_EARNING, - WalletTransaction::TYPE_FEE, - WalletTransaction::TYPE_ADJUSTMENT, - WalletTransaction::TYPE_REFUND, - ]; - $financingTypes = [ - WalletTransaction::TYPE_DEPOSIT, - WalletTransaction::TYPE_WITHDRAWAL, - WalletTransaction::TYPE_PAYOUT, - WalletTransaction::TYPE_TRANSFER_IN, - WalletTransaction::TYPE_TRANSFER_OUT, - ]; + $operatingTypes = ['earning', 'fee', 'adjustment', 'refund']; + $financingTypes = ['deposit', 'withdrawal', 'payout', 'transfer_in', 'transfer_out']; foreach ($walletStats as $row) { $entry = [ @@ -560,7 +548,7 @@ protected function computeNetFlow(array $items): int { $net = 0; foreach ($items as $item) { - if ($item['direction'] === WalletTransaction::DIRECTION_CREDIT) { + if ($item['direction'] === 'credit') { $net += $item['total']; } else { $net -= $item['total']; diff --git a/server/src/Services/WalletService.php b/server/src/Services/WalletService.php index 736632c..daa5a5b 100644 --- a/server/src/Services/WalletService.php +++ b/server/src/Services/WalletService.php @@ -4,8 +4,8 @@ use Fleetbase\Ledger\DTO\PurchaseRequest; use Fleetbase\Ledger\Models\Account; +use Fleetbase\Ledger\Models\Transaction; use Fleetbase\Ledger\Models\Wallet; -use Fleetbase\Ledger\Models\WalletTransaction; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -18,7 +18,7 @@ * This service is the single entry point for all wallet operations. * Every balance change MUST go through this service to ensure: * 1. Correct double-entry journal entries are created - * 2. WalletTransaction audit records are persisted + * 2. Transaction audit records are persisted * 3. Wallet balance is updated atomically within a DB transaction * * Monetary values are always in the smallest currency unit (cents). @@ -93,7 +93,7 @@ public function provisionBatch(iterable $subjects, string $currency = 'USD'): ar * CREDIT Wallet Liability (liability increases — we owe more to wallet holder) * * @param int $amount Amount in smallest currency unit (cents) - * @param string $type WalletTransaction type (default: 'deposit') + * @param string $type Transaction type (default: 'deposit') * @param array $options Optional: source_account, reference, subject, meta, gateway_transaction_uuid * * @throws \Exception if wallet is not active or cannot credit @@ -102,9 +102,9 @@ public function deposit( Wallet $wallet, int $amount, string $description = '', - string $type = WalletTransaction::TYPE_DEPOSIT, + string $type = 'deposit', array $options = [], - ): WalletTransaction { + ): Transaction { if (!$wallet->canCredit()) { throw new \Exception("Wallet [{$wallet->public_id}] cannot accept credits (status: {$wallet->status})."); } @@ -133,22 +133,23 @@ public function deposit( // Update wallet balance $newBalance = $wallet->credit($amount); - // Create WalletTransaction audit record - $transaction = WalletTransaction::create([ - 'company_uuid' => $wallet->company_uuid, - 'wallet_uuid' => $wallet->uuid, - 'gateway_transaction_uuid' => $options['gateway_transaction_uuid'] ?? null, - 'type' => $type, - 'direction' => WalletTransaction::DIRECTION_CREDIT, - 'status' => WalletTransaction::STATUS_COMPLETED, - 'amount' => $amount, - 'balance_after' => $newBalance, - 'currency' => $wallet->currency, - 'description' => $description ?: "Deposit to wallet {$wallet->public_id}", - 'reference' => $options['reference'] ?? null, - 'subject_uuid' => $options['subject_uuid'] ?? null, - 'subject_type' => $options['subject_type'] ?? null, - 'meta' => $options['meta'] ?? null, + // Create Transaction audit record (owner = wallet) + $transaction = Transaction::create([ + 'company_uuid' => $wallet->company_uuid, + 'owner_uuid' => $wallet->uuid, + 'owner_type' => Wallet::class, + 'gateway_transaction_id' => $options['gateway_transaction_uuid'] ?? null, + 'type' => $type, + 'direction' => 'credit', + 'status' => 'completed', + 'amount' => $amount, + 'balance_after' => $newBalance, + 'currency' => $wallet->currency, + 'description' => $description ?: "Deposit to wallet {$wallet->public_id}", + 'reference' => $options['reference'] ?? null, + 'subject_uuid' => $options['subject_uuid'] ?? null, + 'subject_type' => $options['subject_type'] ?? null, + 'meta' => $options['meta'] ?? null, ]); Log::channel('ledger')->info('Wallet deposit completed.', [ @@ -174,7 +175,7 @@ public function deposit( * CREDIT Cash / Dest Account (asset decreases — money paid out) * * @param int $amount Amount in smallest currency unit (cents) - * @param string $type WalletTransaction type (default: 'withdrawal') + * @param string $type Transaction type (default: 'withdrawal') * @param array $options Optional: destination_account, reference, subject, meta * * @throws \Exception if wallet cannot debit or has insufficient balance @@ -183,9 +184,9 @@ public function withdraw( Wallet $wallet, int $amount, string $description = '', - string $type = WalletTransaction::TYPE_WITHDRAWAL, + string $type = 'withdrawal', array $options = [], - ): WalletTransaction { + ): Transaction { if (!$wallet->canDebit()) { throw new \Exception("Wallet [{$wallet->public_id}] cannot be debited (status: {$wallet->status})."); } @@ -218,22 +219,23 @@ public function withdraw( // Update wallet balance $newBalance = $wallet->debit($amount); - // Create WalletTransaction audit record - $transaction = WalletTransaction::create([ - 'company_uuid' => $wallet->company_uuid, - 'wallet_uuid' => $wallet->uuid, - 'gateway_transaction_uuid' => $options['gateway_transaction_uuid'] ?? null, - 'type' => $type, - 'direction' => WalletTransaction::DIRECTION_DEBIT, - 'status' => WalletTransaction::STATUS_COMPLETED, - 'amount' => $amount, - 'balance_after' => $newBalance, - 'currency' => $wallet->currency, - 'description' => $description ?: "Withdrawal from wallet {$wallet->public_id}", - 'reference' => $options['reference'] ?? null, - 'subject_uuid' => $options['subject_uuid'] ?? null, - 'subject_type' => $options['subject_type'] ?? null, - 'meta' => $options['meta'] ?? null, + // Create Transaction audit record (owner = wallet) + $transaction = Transaction::create([ + 'company_uuid' => $wallet->company_uuid, + 'owner_uuid' => $wallet->uuid, + 'owner_type' => Wallet::class, + 'gateway_transaction_id' => $options['gateway_transaction_uuid'] ?? null, + 'type' => $type, + 'direction' => 'debit', + 'status' => 'completed', + 'amount' => $amount, + 'balance_after' => $newBalance, + 'currency' => $wallet->currency, + 'description' => $description ?: "Withdrawal from wallet {$wallet->public_id}", + 'reference' => $options['reference'] ?? null, + 'subject_uuid' => $options['subject_uuid'] ?? null, + 'subject_type' => $options['subject_type'] ?? null, + 'meta' => $options['meta'] ?? null, ]); Log::channel('ledger')->info('Wallet withdrawal completed.', [ @@ -260,7 +262,7 @@ public function withdraw( * * @param int $amount Amount in smallest currency unit (cents) * - * @return array{from: WalletTransaction, to: WalletTransaction} + * @return array{from: Transaction, to: Transaction} * * @throws \Exception if either wallet cannot operate or source has insufficient balance */ @@ -310,15 +312,16 @@ public function transfer( $fromNewBalance = $fromWallet->debit($amount); $toNewBalance = $toWallet->credit($amount); - // Create WalletTransaction records for both sides $reference = $options['reference'] ?? null; - $fromTransaction = WalletTransaction::create([ + // Create Transaction records for both sides (owner = respective wallet) + $fromTransaction = Transaction::create([ 'company_uuid' => $fromWallet->company_uuid, - 'wallet_uuid' => $fromWallet->uuid, - 'type' => WalletTransaction::TYPE_TRANSFER_OUT, - 'direction' => WalletTransaction::DIRECTION_DEBIT, - 'status' => WalletTransaction::STATUS_COMPLETED, + 'owner_uuid' => $fromWallet->uuid, + 'owner_type' => Wallet::class, + 'type' => 'transfer_out', + 'direction' => 'debit', + 'status' => 'completed', 'amount' => $amount, 'balance_after' => $fromNewBalance, 'currency' => $fromWallet->currency, @@ -330,12 +333,13 @@ public function transfer( ]), ]); - $toTransaction = WalletTransaction::create([ + $toTransaction = Transaction::create([ 'company_uuid' => $toWallet->company_uuid, - 'wallet_uuid' => $toWallet->uuid, - 'type' => WalletTransaction::TYPE_TRANSFER_IN, - 'direction' => WalletTransaction::DIRECTION_CREDIT, - 'status' => WalletTransaction::STATUS_COMPLETED, + 'owner_uuid' => $toWallet->uuid, + 'owner_type' => Wallet::class, + 'type' => 'transfer_in', + 'direction' => 'credit', + 'status' => 'completed', 'amount' => $amount, 'balance_after' => $toNewBalance, 'currency' => $toWallet->currency, @@ -348,9 +352,9 @@ public function transfer( ]); Log::channel('ledger')->info('Wallet transfer completed.', [ - 'from_wallet' => $fromWallet->uuid, - 'to_wallet' => $toWallet->uuid, - 'amount' => $amount, + 'from_wallet' => $fromWallet->uuid, + 'to_wallet' => $toWallet->uuid, + 'amount' => $amount, ]); return [ @@ -370,7 +374,7 @@ public function transfer( * This method: * 1. Initiates a charge via the PaymentService * 2. On success, deposits the amount into the wallet - * 3. Links the GatewayTransaction to the WalletTransaction + * 3. Links the GatewayTransaction to the Transaction record * * For asynchronous gateways (QPay), the wallet is credited when the * PaymentSucceeded event fires via the HandleSuccessfulPayment listener. @@ -381,7 +385,7 @@ public function transfer( * @param string $gatewayUuid UUID or public_id of the gateway to charge * @param array $paymentData Payment data (payment_method_token, customer_id, etc.) * - * @return array{wallet: Wallet, transaction: WalletTransaction|null, gateway_response: GatewayResponse} + * @return array{wallet: Wallet, transaction: Transaction|null, gateway_response: GatewayResponse} */ public function topUp( Wallet $wallet, @@ -420,7 +424,7 @@ public function topUp( wallet: $wallet, amount: $amount, description: $description ?: 'Top-up via payment gateway', - type: WalletTransaction::TYPE_DEPOSIT, + type: 'deposit', options: [ 'reference' => $gatewayResponse->gatewayTransactionId, 'gateway_transaction_uuid' => $gatewayTransaction?->uuid, @@ -447,7 +451,7 @@ public function topUp( * Credit earnings to a driver's wallet after order completion. * * This is the primary method for paying drivers. It credits the driver's - * wallet and creates an "earning" WalletTransaction record. + * wallet and creates an "earning" Transaction record. * * Double-entry accounting: * DEBIT Driver Earnings Payable (expense — we owe the driver) @@ -463,14 +467,14 @@ public function creditEarnings( string $currency = 'USD', string $description = '', array $options = [], - ): WalletTransaction { + ): Transaction { $wallet = $this->getOrCreateWallet($driver, $currency); return $this->deposit( wallet: $wallet, amount: $amount, description: $description ?: 'Earnings credited', - type: WalletTransaction::TYPE_EARNING, + type: 'earning', options: array_merge($options, [ 'subject_uuid' => $driver->uuid, 'subject_type' => get_class($driver), @@ -495,14 +499,14 @@ public function processPayout( int $amount, string $description = '', array $options = [], - ): WalletTransaction { + ): Transaction { $wallet = $this->getOrCreateWallet($driver, $options['currency'] ?? 'USD'); return $this->withdraw( wallet: $wallet, amount: $amount, description: $description ?: 'Driver payout', - type: WalletTransaction::TYPE_PAYOUT, + type: 'payout', options: array_merge($options, [ 'subject_uuid' => $driver->uuid, 'subject_type' => get_class($driver), @@ -524,14 +528,14 @@ public function processPayout( */ public function recalculateBalance(Wallet $wallet): int { - $credits = WalletTransaction::where('wallet_uuid', $wallet->uuid) - ->where('direction', WalletTransaction::DIRECTION_CREDIT) - ->where('status', WalletTransaction::STATUS_COMPLETED) + $credits = Transaction::where('owner_uuid', $wallet->uuid) + ->where('direction', 'credit') + ->where('status', 'completed') ->sum('amount'); - $debits = WalletTransaction::where('wallet_uuid', $wallet->uuid) - ->where('direction', WalletTransaction::DIRECTION_DEBIT) - ->where('status', WalletTransaction::STATUS_COMPLETED) + $debits = Transaction::where('owner_uuid', $wallet->uuid) + ->where('direction', 'debit') + ->where('status', 'completed') ->sum('amount'); $correctBalance = (int) ($credits - $debits); diff --git a/server/src/routes.php b/server/src/routes.php index 828f66f..018b7d1 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -108,11 +108,6 @@ function ($router, $controller) { } ); - // ---------------------------------------------------------------- - // Wallet Transactions (company-wide read-only feed) - // ---------------------------------------------------------------- - $router->fleetbaseRoutes('wallet-transactions'); - // ---------------------------------------------------------------- // Transactions (core-api Transaction records — read-only) // ---------------------------------------------------------------- From 468f0263e146113cd06f4222b4aee26a38fd4155 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Sun, 1 Mar 2026 23:35:00 -0500 Subject: [PATCH 048/209] feat(columns): implement full columns getter for wallets and gateways index controllers Wallets: - Default visible: name (anchor), type (humanized select), currency, formatted_balance, status (status cell), created_at - Toggleable hidden: public_id, is_frozen (boolean), owner_type, updated_at - queryParams expanded: public_id, name, type, status, currency, is_frozen, owner_type, created_at, updated_at - Row actions dropdown: view, delete - balance column uses formatted_balance valuePath with balance sortParam Gateways: - Default visible: name (anchor), driver (multi-option filter), environment (select), is_default (boolean), status (status cell), created_at - Toggleable hidden: public_id, code, description, updated_at - queryParams expanded: public_id, name, code, driver, environment, status, is_default, created_at, updated_at - Row actions dropdown: view, edit, delete - driver uses multi-option filter with known driver values (stripe, braintree, etc.) --- addon/controllers/payments/gateways/index.js | 141 ++++++++++++++++++- addon/controllers/payments/wallets/index.js | 133 ++++++++++++++++- 2 files changed, 270 insertions(+), 4 deletions(-) diff --git a/addon/controllers/payments/gateways/index.js b/addon/controllers/payments/gateways/index.js index 6b3ed85..77f70ec 100644 --- a/addon/controllers/payments/gateways/index.js +++ b/addon/controllers/payments/gateways/index.js @@ -7,14 +7,34 @@ export default class PaymentsGatewaysIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'driver', 'environment', 'status']; + @tracked queryParams = [ + 'page', + 'limit', + 'sort', + 'query', + 'public_id', + 'name', + 'code', + 'driver', + 'environment', + 'status', + 'is_default', + 'created_at', + 'updated_at', + ]; @tracked page = 1; @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; + @tracked public_id = null; + @tracked name = null; + @tracked code = null; @tracked driver = null; @tracked environment = null; @tracked status = null; + @tracked is_default = null; + @tracked created_at = null; + @tracked updated_at = null; @tracked table = null; get actionButtons() { @@ -46,12 +66,14 @@ export default class PaymentsGatewaysIndexController extends Controller { get columns() { return [ + // ── Default visible columns ────────────────────────────────────── { sticky: true, label: this.intl.t('column.name'), valuePath: 'name', cellComponent: 'table/cell/anchor', action: this.gatewayActions.transition.view, + width: 200, resizable: true, sortable: true, filterable: true, @@ -61,20 +83,29 @@ export default class PaymentsGatewaysIndexController extends Controller { { label: this.intl.t('column.driver'), valuePath: 'driver', + cellComponent: 'table/cell/base', + humanize: true, + width: 130, resizable: true, sortable: true, filterable: true, filterParam: 'driver', - filterComponent: 'filter/string', + filterComponent: 'filter/multi-option', + filterOptions: ['stripe', 'braintree', 'paypal', 'square', 'qpay', 'cash'], }, { label: this.intl.t('column.environment'), valuePath: 'environment', + cellComponent: 'table/cell/base', + humanize: true, + width: 110, resizable: true, sortable: true, filterable: true, filterParam: 'environment', filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', filterOptions: [ { label: 'Live', value: 'live' }, { label: 'Sandbox', value: 'sandbox' }, @@ -84,22 +115,128 @@ export default class PaymentsGatewaysIndexController extends Controller { label: this.intl.t('column.default'), valuePath: 'is_default', cellComponent: 'table/cell/boolean', + width: 80, resizable: true, + sortable: true, + filterable: true, + filterParam: 'is_default', + filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', + filterOptions: [ + { label: 'Yes', value: 'true' }, + { label: 'No', value: 'false' }, + ], }, { label: this.intl.t('column.status'), valuePath: 'status', cellComponent: 'table/cell/status', + width: 100, resizable: true, sortable: true, filterable: true, filterParam: 'status', filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', filterOptions: [ { label: 'Active', value: 'active' }, { label: 'Inactive', value: 'inactive' }, ], }, + { + label: this.intl.t('column.created-at'), + valuePath: 'createdAt', + sortParam: 'created_at', + filterParam: 'created_at', + width: 150, + resizable: true, + sortable: true, + filterable: true, + filterComponent: 'filter/date', + }, + // ── Hidden / toggleable columns ────────────────────────────────── + { + label: this.intl.t('column.id'), + valuePath: 'public_id', + width: 120, + hidden: true, + resizable: true, + sortable: false, + filterable: true, + filterParam: 'public_id', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.code'), + valuePath: 'code', + hidden: true, + resizable: true, + sortable: true, + filterable: true, + filterParam: 'code', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.description'), + valuePath: 'description', + hidden: true, + resizable: true, + sortable: false, + filterable: true, + filterParam: 'description', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.updated-at'), + valuePath: 'updatedAt', + sortParam: 'updated_at', + filterParam: 'updated_at', + hidden: true, + resizable: true, + sortable: true, + filterable: true, + filterComponent: 'filter/date', + }, + // ── Row actions dropdown ───────────────────────────────────────── + { + label: '', + cellComponent: 'table/cell/dropdown', + ddButtonText: false, + ddButtonIcon: 'ellipsis-h', + ddButtonIconPrefix: 'fas', + ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.gateway') }), + cellClassNames: 'overflow-visible', + wrapperClass: 'flex items-center justify-end mx-2', + sticky: 'right', + width: 60, + actions: [ + { + label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.gateway') }), + icon: 'eye', + fn: this.gatewayActions.transition.view, + permission: 'ledger view gateway', + }, + { + label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.gateway') }), + icon: 'pencil', + fn: this.gatewayActions.edit, + permission: 'ledger update gateway', + }, + { + label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.gateway') }), + icon: 'trash', + fn: this.gatewayActions.delete, + className: 'text-red-500 hover:text-red-700', + permission: 'ledger delete gateway', + }, + ], + sortable: false, + filterable: false, + resizable: false, + searchable: false, + }, ]; } } diff --git a/addon/controllers/payments/wallets/index.js b/addon/controllers/payments/wallets/index.js index 2a5ebe3..de14674 100644 --- a/addon/controllers/payments/wallets/index.js +++ b/addon/controllers/payments/wallets/index.js @@ -7,14 +7,34 @@ export default class PaymentsWalletsIndexController extends Controller { @service tableContext; @service intl; - @tracked queryParams = ['page', 'limit', 'sort', 'query', 'type', 'status', 'currency']; + @tracked queryParams = [ + 'page', + 'limit', + 'sort', + 'query', + 'public_id', + 'name', + 'type', + 'status', + 'currency', + 'is_frozen', + 'owner_type', + 'created_at', + 'updated_at', + ]; @tracked page = 1; @tracked limit = 30; @tracked sort = '-created_at'; @tracked query = null; + @tracked public_id = null; + @tracked name = null; @tracked type = null; @tracked status = null; @tracked currency = null; + @tracked is_frozen = null; + @tracked owner_type = null; + @tracked created_at = null; + @tracked updated_at = null; @tracked table = null; get actionButtons() { @@ -46,12 +66,14 @@ export default class PaymentsWalletsIndexController extends Controller { get columns() { return [ + // ── Default visible columns ────────────────────────────────────── { sticky: true, label: this.intl.t('column.name'), valuePath: 'name', cellComponent: 'table/cell/anchor', action: this.walletActions.transition.view, + width: 200, resizable: true, sortable: true, filterable: true, @@ -61,11 +83,16 @@ export default class PaymentsWalletsIndexController extends Controller { { label: this.intl.t('column.type'), valuePath: 'type', + cellComponent: 'table/cell/base', + humanize: true, + width: 110, resizable: true, sortable: true, filterable: true, filterParam: 'type', filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', filterOptions: [ { label: 'Driver', value: 'driver' }, { label: 'Customer', value: 'customer' }, @@ -76,6 +103,7 @@ export default class PaymentsWalletsIndexController extends Controller { { label: this.intl.t('column.currency'), valuePath: 'currency', + width: 90, resizable: true, sortable: true, filterable: true, @@ -84,25 +112,126 @@ export default class PaymentsWalletsIndexController extends Controller { }, { label: this.intl.t('column.balance'), - valuePath: 'balance', + valuePath: 'formatted_balance', + sortParam: 'balance', + width: 130, resizable: true, sortable: true, + filterable: false, }, { label: this.intl.t('column.status'), valuePath: 'status', cellComponent: 'table/cell/status', + width: 100, resizable: true, sortable: true, filterable: true, filterParam: 'status', filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', filterOptions: [ { label: 'Active', value: 'active' }, { label: 'Inactive', value: 'inactive' }, { label: 'Frozen', value: 'frozen' }, + { label: 'Suspended', value: 'suspended' }, ], }, + { + label: this.intl.t('column.created-at'), + valuePath: 'createdAt', + sortParam: 'created_at', + filterParam: 'created_at', + width: 150, + resizable: true, + sortable: true, + filterable: true, + filterComponent: 'filter/date', + }, + // ── Hidden / toggleable columns ────────────────────────────────── + { + label: this.intl.t('column.id'), + valuePath: 'public_id', + width: 120, + hidden: true, + resizable: true, + sortable: false, + filterable: true, + filterParam: 'public_id', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.frozen'), + valuePath: 'is_frozen', + cellComponent: 'table/cell/boolean', + width: 80, + hidden: true, + resizable: true, + sortable: true, + filterable: true, + filterParam: 'is_frozen', + filterComponent: 'filter/select', + filterOptionLabel: 'label', + filterOptionValue: 'value', + filterOptions: [ + { label: 'Yes', value: 'true' }, + { label: 'No', value: 'false' }, + ], + }, + { + label: this.intl.t('column.owner-type'), + valuePath: 'owner_type', + hidden: true, + resizable: true, + sortable: false, + filterable: true, + filterParam: 'owner_type', + filterComponent: 'filter/string', + }, + { + label: this.intl.t('column.updated-at'), + valuePath: 'updatedAt', + sortParam: 'updated_at', + filterParam: 'updated_at', + hidden: true, + resizable: true, + sortable: true, + filterable: true, + filterComponent: 'filter/date', + }, + // ── Row actions dropdown ───────────────────────────────────────── + { + label: '', + cellComponent: 'table/cell/dropdown', + ddButtonText: false, + ddButtonIcon: 'ellipsis-h', + ddButtonIconPrefix: 'fas', + ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.wallet') }), + cellClassNames: 'overflow-visible', + wrapperClass: 'flex items-center justify-end mx-2', + sticky: 'right', + width: 60, + actions: [ + { + label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.wallet') }), + icon: 'eye', + fn: this.walletActions.transition.view, + permission: 'ledger view wallet', + }, + { + label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.wallet') }), + icon: 'trash', + fn: this.walletActions.delete, + className: 'text-red-500 hover:text-red-700', + permission: 'ledger delete wallet', + }, + ], + sortable: false, + filterable: false, + resizable: false, + searchable: false, + }, ]; } } From 6f024e4cfe327ee4b9011b2fd699334a4ea4d4ec Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Mon, 2 Mar 2026 12:43:18 +0800 Subject: [PATCH 049/209] few minor fixes --- addon/extension.js | 7 ++++++- addon/routes/payments/gateways/index.js | 4 ++-- server/src/Models/Account.php | 5 +++++ server/src/Models/Gateway.php | 5 +++++ server/src/Models/Invoice.php | 5 +++++ server/src/Models/InvoiceItem.php | 5 +++++ server/src/Models/Journal.php | 5 +++++ server/src/Models/Wallet.php | 5 +++++ 8 files changed, 38 insertions(+), 3 deletions(-) diff --git a/addon/extension.js b/addon/extension.js index 719684f..ede4290 100644 --- a/addon/extension.js +++ b/addon/extension.js @@ -6,7 +6,12 @@ export default { const widgetService = universe.getService('universe/widget-service'); // Register Ledger in the console header navigation - menuService.registerHeaderMenuItem('Ledger', 'console.ledger', { icon: 'calculator', priority: 4 }); + menuService.registerHeaderMenuItem('Ledger', 'console.ledger', { + icon: 'calculator', + priority: 4, + description: 'Accounting and invoice management.', + shortcuts: [{ title: 'Transactions', description: 'Ledger transaction records.', route: 'console.ledger.payments.transactions' }], + }); // Register dashboard and widgets this.registerWidgets(widgetService); diff --git a/addon/routes/payments/gateways/index.js b/addon/routes/payments/gateways/index.js index 685a0bb..4d43a75 100644 --- a/addon/routes/payments/gateways/index.js +++ b/addon/routes/payments/gateways/index.js @@ -4,7 +4,7 @@ import { inject as service } from '@ember/service'; export default class PaymentsGatewaysIndexRoute extends Route { @service store; - model() { - return this.store.query('ledger-gateway'); + model(params) { + return this.store.query('ledger-gateway', params); } } diff --git a/server/src/Models/Account.php b/server/src/Models/Account.php index 953ee93..a2241e9 100644 --- a/server/src/Models/Account.php +++ b/server/src/Models/Account.php @@ -46,6 +46,11 @@ class Account extends Model */ protected $publicIdType = 'account'; + /** + * The response payload key to use. + */ + protected $payloadKey = 'account'; + /** * The attributes that can be queried. * diff --git a/server/src/Models/Gateway.php b/server/src/Models/Gateway.php index 0afdd93..00e9839 100644 --- a/server/src/Models/Gateway.php +++ b/server/src/Models/Gateway.php @@ -45,6 +45,11 @@ class Gateway extends Model */ protected $publicIdPrefix = 'gateway'; + /** + * The response payload key to use. + */ + protected $payloadKey = 'gateway'; + /** * The attributes that are mass assignable. */ diff --git a/server/src/Models/Invoice.php b/server/src/Models/Invoice.php index 25e0582..e8b7937 100644 --- a/server/src/Models/Invoice.php +++ b/server/src/Models/Invoice.php @@ -44,6 +44,11 @@ class Invoice extends Model */ protected $publicIdType = 'invoice'; + /** + * The response payload key to use. + */ + protected $payloadKey = 'invoice'; + /** * The attributes that can be queried. * diff --git a/server/src/Models/InvoiceItem.php b/server/src/Models/InvoiceItem.php index 32d6494..e6dc80c 100644 --- a/server/src/Models/InvoiceItem.php +++ b/server/src/Models/InvoiceItem.php @@ -22,6 +22,11 @@ class InvoiceItem extends Model */ protected $table = 'ledger_invoice_items'; + /** + * The response payload key to use. + */ + protected $payloadKey = 'invoice_item'; + /** * The attributes that are mass assignable. * diff --git a/server/src/Models/Journal.php b/server/src/Models/Journal.php index 166ed75..f6ede11 100644 --- a/server/src/Models/Journal.php +++ b/server/src/Models/Journal.php @@ -28,6 +28,11 @@ class Journal extends Model */ public $publicIdPrefix = 'journal'; + /** + * The response payload key to use. + */ + protected $payloadKey = 'journal'; + /** * The database table used by the model. * diff --git a/server/src/Models/Wallet.php b/server/src/Models/Wallet.php index 9888857..1cd120c 100644 --- a/server/src/Models/Wallet.php +++ b/server/src/Models/Wallet.php @@ -65,6 +65,11 @@ class Wallet extends Model */ protected $publicIdType = 'wallet'; + /** + * The response payload key to use. + */ + protected $payloadKey = 'wallet'; + /** * The attributes that can be queried. */ From 3014618e2d57f6aab05f7b28d253d85c2a478927 Mon Sep 17 00:00:00 2001 From: Fleetbase Dev Date: Mon, 2 Mar 2026 02:44:03 -0500 Subject: [PATCH 050/209] feat(forms): implement complete form components for all 6 Ledger domain models Follows the fleetops vehicle/form.hbs pattern: - Root
- ContentPanel sections with @title, @open, @wrapperClass="bordered-top" - grid grid-cols-1 lg:grid-cols-2 no-input-group-padding layout - InputGroup + Input/Textarea/PowerSelect/Toggle/ModelSelect inputs - cannot-write @resource on all inputs for permission-aware disabling - Spacer @height="100px" at bottom of each form invoice/form.hbs: Sections: Identification (number, status, currency), Customer (uuid, type), Dates (issued_at, due_date), Amounts (subtotal, tax, discount, total, amount_paid), Notes (textarea) transaction/form.hbs: Sections: Core (type, direction, status, currency), Amounts (amount, fee, tax, net), Gateway & Payment (gateway, gateway_transaction_id, payment_method, reference), Description & Notes (description textarea, notes textarea) wallet/form.hbs: Sections: Wallet Information (name, type, currency, status), Owner (owner_uuid, owner_type), Settings (is_frozen toggle) gateway/form.hbs (rewritten from scratch): Sections: Identification (name, code, driver PowerSelect with capabilities badges, environment, status, is_default toggle, description), Dynamic Configuration (renders configSchema fields as text/password/select/boolean) gateway/form.js (rewritten): Loads available drivers from API, hydrates configSchema on driver select, pre-fills existing config values, persists config back to @resource.config account/form.hbs: Sections: Account Information (name, code, type, currency, status), Description (textarea) journal/form.hbs: Sections: Entry Information (number, entry_date, type, currency, amount), Double-Entry (debit account ModelSelect + code, credit account ModelSelect + code), Description (textarea) journal/form.js: Loads existing debit/credit accounts from store on init, setDebitAccount/setCreditAccount actions update uuid/name/code on resource --- addon/components/account/form.hbs | 98 ++++++++++ addon/components/gateway/form.hbs | 260 +++++++++++++++++--------- addon/components/gateway/form.js | 76 +++----- addon/components/invoice/form.hbs | 187 ++++++++++++++++++ addon/components/journal/form.hbs | 170 +++++++++++++++++ addon/components/journal/form.js | 48 +++++ addon/components/transaction/form.hbs | 200 ++++++++++++++++++++ addon/components/wallet/form.hbs | 119 ++++++++++++ 8 files changed, 1022 insertions(+), 136 deletions(-) create mode 100644 addon/components/account/form.hbs create mode 100644 addon/components/invoice/form.hbs create mode 100644 addon/components/journal/form.hbs create mode 100644 addon/components/journal/form.js create mode 100644 addon/components/transaction/form.hbs create mode 100644 addon/components/wallet/form.hbs diff --git a/addon/components/account/form.hbs b/addon/components/account/form.hbs new file mode 100644 index 0000000..6042f5a --- /dev/null +++ b/addon/components/account/form.hbs @@ -0,0 +1,98 @@ +
+ {{! ACCOUNT DETAILS }} + +
+ + {{! Identification }} +
+ Account Information +
+ + + + + + + + + + +
+ +
{{option}}
+
+
+
+ + +
+ +
{{option}}
+
+
+
+ + +
+ +
{{option}}
+
+
+
+ + {{! Description }} +
+ Description +
+ + +