diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 263e5eb89..000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/dist
-/src-capacitor
-/src-cordova
-/.quasar
-/node_modules
-.eslintrc.js
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 5c33d2118..000000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,75 +0,0 @@
-export default {
-    // https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
-    // This option interrupts the configuration hierarchy at this file
-    // Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
-    root: true,
-
-    parserOptions: {
-        ecmaVersion: '2021', // Allows for the parsing of modern ECMAScript features
-    },
-
-    env: {
-        node: true,
-        browser: true,
-        'vue/setup-compiler-macros': true,
-    },
-
-    // Rules order is important, please avoid shuffling them
-    extends: [
-        // Base ESLint recommended rules
-        'eslint:recommended',
-
-        // Uncomment any of the lines below to choose desired strictness,
-        // but leave only one uncommented!
-        // See https://eslint.vuejs.org/rules/#available-rules
-        // 'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
-        'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
-        // 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
-
-        // https://github.com/prettier/eslint-config-prettier#installation
-        // usage with Prettier, provided by 'eslint-config-prettier'.
-        'prettier',
-    ],
-
-    plugins: [
-        // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files
-        // required to lint *.vue files
-        'vue',
-
-        // https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674
-        // Prettier has not been included as plugin to avoid performance impact
-        // add it as an extension for your IDE
-    ],
-
-    globals: {
-        ga: 'readonly', // Google Analytics
-        cordova: 'readonly',
-        __statics: 'readonly',
-        __QUASAR_SSR__: 'readonly',
-        __QUASAR_SSR_SERVER__: 'readonly',
-        __QUASAR_SSR_CLIENT__: 'readonly',
-        __QUASAR_SSR_PWA__: 'readonly',
-        process: 'readonly',
-        Capacitor: 'readonly',
-        chrome: 'readonly',
-    },
-
-    // add your custom rules here
-    rules: {
-        'prefer-promise-reject-errors': 'off',
-        'no-unused-vars': 'warn',
-        'vue/no-multiple-template-root': 'off',
-        // allow debugger during development only
-        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
-    },
-    overrides: [
-        {
-            files: ['test/cypress/**/*.*'],
-            extends: [
-                // Add Cypress-specific lint rules, globals and Cypress plugin
-                // See https://github.com/cypress-io/eslint-plugin-cypress#rules
-                'plugin:cypress/recommended',
-            ],
-        },
-    ],
-};
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 000000000..ba1902263
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+    "extends": ["plugin:cypress/recommended"]
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10b7c73f7..3b654a1ad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,398 @@
+# Version 25.12 - 2025-03-25
+
+### Added 🆕
+
+- chore: add junit-merge dependency to package.json by:alexm
+- chore: downgrade version from 25.14.0 to 25.12.0 in package.json by:alexm
+- chore: reduce page load timeout in Cypress configuration by:alexm
+- chore: refs #6695 update Cypress to version 14.1.0 and simplify test execution in Jenkinsfile by:alexm
+- chore: refs #8602 add comments for clarity in Cypress commands file by:pablone
+- chore: refs #8602 enhance Cypress support files with detailed comments and organization by:pablone
+- ci: refs #6695 feat jenkins parallel e2e by:alexm
+- feat: integrate vue-router to enhance routing capabilities in ZoneCard component by:alexm
+- feat: refs #6695 implement parallel Cypress testing and enhance timeout configurations by:alexm
+- feat: refs #6695 update Cypress parallel test execution to use 3 instances by:alexm
+- feat: refs #6802 add dash placeholder for empty department names in InvoiceOut list by:jgallego
+- feat: refs #6802 add DepartmentDescriptorProxy to InvoiceOutList and update translations by:jgallego
+- feat: refs #6802 add DepartmentDescriptorProxy to various components and update department handling by:jgallego
+- feat: refs #7587 add 'ticketClaimed' translation and implement claims retrieval in TicketDescriptor by:jtubau
+- feat: refs #7949 show new field in ticket sales by:Jon
+- feat: refs #8045 added new logic to show the correct icon and the correct path to redirect by:Jon
+- feat: refs #8045 modified icon and route to redirect from CardDescriptor by:Jon
+- feat: refs #8074 modified spinner size by:Jon
+- feat: refs #8600 added calendar e2e and modified basic data by:Jon
+- feat: refs #8600 added deliveryDays and modified warehouse E2Es by:Jon
+- feat: refs #8600 added new tests for zoneSummary & zoneLocations by:provira
+- feat: refs #8602 add custom Cypress commands for improved element interaction and request handling by:pablone
+- feat: refs #8602 add new Cypress command for clicking buttons with icons by:pablone
+- feat: refs #8602 add remove functionality for tag filters in EntryBuys component by:pablone
+- feat: refs #8602 add sorting options for select fields and update locale files with supplier name by:pablone
+- feat: refs #8602 refactor EntryBuys component and enhance observation tests by:pablone
+- feat: refs #8602 remove unused state property from useArrayDataStore by:pablone
+- feat: refs #8602 remove unused URL property from VnTable in ClaimList component by:pablone
+- feat: refs #8602 skip warehouse creation and removal test in ZoneWarehouse spec by:pablone
+- feat: refs #8602 streamline beforeSaveFn execution in CrudModel component by:pablone
+- feat: refs #8602 streamline beforeSaveFn execution in VnTable component by:pablone
+- feat: refs #8602 streamline filter logic in EntryBuys component by:pablone
+- feat: refs #8602 update entry components and tests, add data-cy attributes for Cypress integration by:pablone
+- feat: refs #8602 update localization for purchased spaces and enhance Entry components with new labels by:pablone
+- feat: refs #8606 adapt module to VnCatdBeta by:Jon
+- feat: refs #8612 added summary button & changed e2e tests by:provira
+- feat: refs #8612 changed shelving to VnTable & created e2e tests by:provira
+- feat: refs #8616 add summary prop to CardDescriptor in RoadmapDescriptor and WorkerDescriptor by:jtubau
+- feat: refs #8616 add VnCheckbox component to VnFilter and update prop types in VnFilterPanel and VnSearchbar by:jtubau
+- feat: refs #8630 add Agency and Vehicle descriptor components with summary props by:jtubau
+- feat: refs #8638 add AWB field to travel and entry forms, update translations and styles by:pablone
+- feat: refs #8638 add data attributes for transfer buys functionality in EntryBuys.vue and corresponding tests by:pablone
+- feat: refs #8648 enhance roadmapList tests with improved selectors and additional scenarios by:jtubau
+- feat: refs #8664 add CmrFilter component and integrate it into CmrList for enhanced filtering options by:jtubau
+- feat: refs #8721 add ticket navigation and update route columns by:jtubau
+- feat: run.sh build neccessary images by:alexm
+- feat: update Jenkinsfile to pull Docker images for back and db services by:alexm
+- feat: update labels and add department selection in InvoiceOut filter and list by:jgallego
+- refactor: refs #8626 update button styles and improve route redirection logic by:jtubau
+- style: refs #8041 new variable by:benjaminedc
+
+### Changed 📦
+
+- feat: refs #8602 refactor EntryBuys component and enhance observation tests by:pablone
+- refactor(cypress): refs #6695 simplify parallel test execution script by:alexm
+- refactor: deleted useless (origin/Warmfix-DepartmentIcon) by:Jon
+- refactor: refs #6695 enable ClaimNotes test suite by:alexm
+- refactor: refs #6695 fix invoiceOutSummary by:alexm
+- refactor: refs #6695 improve notification check and extend waitForElement timeout by:alexm
+- refactor: refs #6695 remove mocha dependency and optimize Cypress command execution by:alexm
+- refactor: refs #6695 skips by:alexm
+- refactor: refs #6695 skip zoneWarehouse by:alexm
+- refactor: refs #6695 streamline Cypress test execution and remove deprecated configurations by:alexm
+- refactor: refs #6802 replace salesPerson references with department in claims and tickets by:jgallego
+- refactor: refs #6802 replace 'salesPerson' terminology with 'team' across multiple locales and components by:jgallego
+- refactor: refs #6802 update import paths for DepartmentDescriptorProxy to use Worker directory by:jgallego
+- refactor: refs #6802 update InvoiceOutNegativeBases to use Department instead of Worker by:jgallego
+- refactor: refs #6802 update TicketFilter and TicketSale components to use departmentFk and adjust API endpoints by:jgallego
+- refactor: refs #8041 unify class link and unify titles to VnTitles by:benjaminedc
+- refactor: refs #8045 modified icon and module const by:Jon
+- refactor: refs #8197 rename VnCardBeta to VnCard by:alexm
+- refactor: refs #8197 simplify menu retrieval logic in LeftMenu component by:alexm
+- refactor: refs #8322 changed Wagon component to use VnSection/VnCardBeta by:provira
+- refactor: refs #8322 remove keyBinding from Wagon router module by:alexm
+- refactor: refs #8322 update WagonCard component and routing structure by:alexm
+- refactor: refs #8370 modified function to get the correct date by:Jon
+- refactor: refs #8472 remove added div and add class to VnInput by:jtubau
+- refactor: refs #8472 unified styling for the more-create-dialog slot to ensure consistency across all scenarios by:jtubau
+- refactor: refs #8472 update class names from q-span-2 to col-span-2 for consistency in layout by:jtubau
+- refactor: refs #8600 changed test case description by:provira
+- refactor: refs #8600 modified make invoice and send dialog e2es by:Jon
+- refactor: refs #8600 modified upcomingDeliveries e2e and created deliveryDays by:Jon
+- refactor: refs #8600 modified zoneSummary e2e by:Jon
+- refactor: refs #8602 remove redundant date input test from entryList.spec.js by:pablone
+- refactor: refs #8606 clear some warnings by:Jon
+- refactor: refs #8606 deleted code and fixed translation by:Jon
+- refactor: refs #8606 merged previous and e2e changes and corrected minor errors by:Jon
+- refactor: refs #8606 requested changes by:Jon
+- refactor: refs #8616 integrate summary dialog and update navigation in Agency and Vehicle components by:jtubau
+- refactor: refs #8616 integrate VnSelectWorker component in RouteList and optimize format functions by:jtubau
+- refactor: refs #8616 simplify template bindings and improve link generation in VehicleSummary by:jtubau
+- refactor: refs #8616 update routing components for AgencyList and RouteRoadmap in route.js by:jtubau
+- refactor: refs #8619 simplify empty data check in RouteDescriptor component by:jtubau
+- refactor: refs #8626 add cardVisible property to RouteList columns by:jtubau
+- refactor: refs #8626 add formatting for agency and vehicle columns in RouteList by:jtubau
+- refactor: refs #8626 enhance Worker and Agency components with data attributes and improved routing by:jtubau
+- refactor: refs #8626 improve test messages and selectors in route tests by:jtubau
+- refactor: refs #8626 update button styles and improve route redirection logic by:jtubau
+- refactor: refs #8626 update RouteList columns and enable AgencyWorkCenter tests by:jtubau
+- refactor: refs #8630 add vehicle translations and enhance route list columns by:jtubau
+- refactor: refs #8648 update roadmap deletion test to use current element text by:jtubau
+- refactor: refs #8664 enhance CmrList component with query initialization and user parameters by:jtubau
+- refactor: refs #8664 localization files by:jtubau
+- refactor: refs #8664 remove CmrFilter and replace with VnSearchbar in CmrList by:jtubau
+- refactor: remove unnecessary login and reload calls in ClaimDevelopment tests by:alexm
+- refactor: simplify client selection in order creation test by:alexm
+- refactor: update client ID input selector and remove viewport setting by:alexm
+- test: refs #8197 comment out ticket list tests for refactoring by:alexm
+- test: refs #8626 refactor notification check in routeList.spec.js by:jtubau
+- test: refs #8626 refactor routeList.spec.js to use a constant for summary URL by:jtubau
+- test: refs #8626 refactor routeList.spec.js to use selectors and improve readability by:jtubau
+
+### Fixed 🛠️
+
+- fix: add --init flag to Docker container for Cypress tests by:alexm
+- fix: agency list filters by:jtubau
+- fix: align Article label to the left in EntryBuys component by:alexm
+- fix: card descriptor imports by:Jon
+- fix: card descriptor merge by:Jon
+- fix(ClaimAction): update shelving options to use URL instead of static data by:jgallego
+- fix(ClaimSummary): clean url by:alexm
+- fix(cypress.config.js): refs #6695 update reporter to junit and remove unused dependencies by:alexm
+- fix(cypressParallel.sh): refs #6695 improve script readability by:alexm
+- fix(cypressParallel.sh): refs #6695 improve test execution output for clarity by:alexm
+- fix(cypressParallel.sh): refs #6695 simplify test execution output format by:alexm
+- fix(cypress scripts): refs #6695 improve cleanup process and adjust output redirection by:alexm
+- fix: fixed department descriptor icon by:Jon
+- fix: fixed submodule descriptors icons by:Jon
+- fix(invoiceOutSummary.spec.js): refs #6695 remove unnecessary visibility check for descriptor by:alexm
+- fix(Jenkinsfile): reduce parallel Cypress test execution from 3 to 2 by:alexm
+- fix(Jenkinsfile): refs #6695 add credentials for Docker login in E2E stage by:alexm
+- fix(Jenkinsfile): refs #6695 change parallel test execution from 4 to 2 by:alexm
+- fix(Jenkinsfile): refs #6695 increase parallel test execution from 2 to 4 by:alexm
+- fix(Jenkinsfile): refs #6695 update parallel test execution to 4 by:alexm
+- fix(LeftMenu): refs #8197 handle missing children in findRoute and update menu structure by:alexm
+- fix: refs #6695 update Cypress configuration and test result paths by:alexm
+- fix: refs #6695 update Jenkinsfile to build Docker image correctly and modify logout test visit method by:alexm
+- fix: refs #6695 update Jenkinsfile to remove specific e2e XML files and adjust Cypress parallel execution by:alexm
+- fix: refs #6695 update Jenkinsfile to source cypressParallel.sh correctly by:alexm
+- fix: refs #6695 update visit method in TicketLackDetail.spec.js to prevent page reload by:alexm
+- fix: refs #6802 update import path for DepartmentDescriptorProxy in OrderList.vue by:jgallego
+- fix: refs #6802 update OrderFilter to use department relation instead of salesPerson by:jgallego
+- fix: refs #8041 update redirection from preview to summary in ShelvingList tests by:benjaminedc
+- fix: refs #8041 update selector for summary header in ParkingList tests by:benjaminedc
+- fix: refs #8041 update summaryHeader selector in ParkingList test by:benjaminedc
+- fix: refs #8322 update order property for WagonList component by:alexm
+- fix: refs #8370 change param rely on month by:Jon
+- fix: refs #8417 added data-cy to all files and fixed test by:provira
+- fix: refs #8417 added data-cy to delete button by:provira
+- fix: refs #8417 fixed claimPhoto e2e by:provira
+- fix: refs #8417 fixed claimPhoto e2e test by:provira
+- fix: refs #8417 fixed e2e test by:provira
+- fix: refs #8417 fixed e2e test case by:provira
+- fix: refs #8417 fixed failing test case by:provira
+- fix: refs #8417 fixed invoiceOutSummary e2e test by:provira
+- fix: refs #8417 removed .only by:provira
+- fix: refs #8583 basicData, business, summary by:carlossa
+- fix: refs #8583 basicData e2e by:carlossa
+- fix: refs #8583 basicData timeControl by:carlossa
+- fix: refs #8583 cypressconf by:carlossa
+- fix: refs #8583 dataCy operator by:carlossa
+- fix: refs #8583 fix AddCard by:carlossa
+- fix: refs #8583 mutual create by:carlossa
+- fix: refs #8583 operator by:carlossa
+- fix: refs #8583 remove workerTimeControl by:carlossa
+- fix: refs #8583 tMutual, tNotes, TOperator by:carlossa
+- fix: refs #8583 wBusiness by:carlossa
+- fix: refs #8583 wBusiness e2e by:carlossa
+- fix: refs #8583 workerBasicData & workerTimeControl by:carlossa
+- fix: refs #8583 workerBusiness by:carlossa
+- fix: refs #8583 workerBusiness e2e by:carlossa
+- fix: refs #8583 workerBusiness test by:carlossa
+- fix: refs #8583 workerE2E by:carlossa
+- fix: refs #8583 worker mutual e2e by:carlossa
+- fix: refs #8583 workerSummary test by:carlossa
+- fix: refs #8583 workerTimeControl by:carlossa
+- fix: refs #8583 workerTimeControl e2e by:carlossa
+- fix: refs #8600 e2e by:Jon
+- fix: refs #8600 fixed calendar e2e by:Jon
+- fix: refs #8600 fixed e2e and skip client ones by:Jon
+- fix: refs #8600 fixed e2e by:Jon
+- fix: refs #8600 fixed invoiceOut summary e2e by:Jon
+- fix: refs #8600 fixed zoneList & added test case to zoneSummary by:provira
+- fix: refs #8600 zone basic data e2e and skip intermitent invoice out summary it by:Jon
+- fix: refs #8602 delete unused entryDms and stockBought test files (origin/8581-e2eInvoiceIn) by:pablone
+- fix: refs #8606 deleted code by:Jon
+- fix: refs #8612 changed QCheckbox for VnCheckbox by:provira
+- fix: refs #8612 fixed shelving e2e tests by:provira
+- fix: refs #8616 add conditional for SupplierDescriptorProxy and bind attributes in CardDescriptor by:jtubau
+- fix: refs #8616 remove redundant v-on binding from QCheckbox in VnCheckbox.vue by:jtubau
+- fix: refs #8616 update binding syntax for is-editable prop in AgencyList.vue by:jtubau
+- fix: refs #8616 update FormModel prop from 'update-url' to 'url-update' in Agency and RoadMap BasicData by:jtubau
+- fix: refs #8619 handle empty ticket records in RouteDescriptor component by:jtubau
+- fix: refs #8619 update route descriptor to handle empty ticket records and adjust test cases by:jtubau
+- fix: refs #8626 remove duplicate ref attribute from RouteList.vue by:jtubau
+- fix: refs #8630 remove duplicated locations by:jtubau
+- fix: refs #8638 restore invoiceInBasicData by:pablone
+- fix: refs #8638 update comment formatting in VnTable.vue by:pablone
+- fix: refs #8638 update null check for maxlength validation in VnInput.vue by:pablone
+- fix: simplify menu structure in monitor router module (origin/fix_monitor_leftMenu) by:Javier Segarra
+- refactor: refs #6695 fix invoiceOutSummary by:alexm
+- refactor: refs #8606 deleted code and fixed translation by:Jon
+- test: fix intermitent e2e by:alexm
+- test: fix orderList e2e, unestables by:alexm
+- test(OrderList): fix inconsistency by:alexm
+- test(TicketList): fix inconsistency by:alexm
+
+# Version 25.10 - 2025-03-11
+
+### Added 🆕
+
+- chore: refs #6695 empty commit by:alexm
+- chore: refs #6695 get docker compose version by:alexm
+- chore: refs #6695 try use docker compose by:alexm
+- feat: add --browser chromium by:Javier Segarra
+- feat: docker pull back image by:alexm
+- feat(jenkinsE2E): refs #6695 new image by:alexm
+- feat(jenkinsE2E): refs #6695 try fix db by:alexm
+- feat(jenkinsE2E): refs #6695 try new sintax by:alexm
+- feat(Jenkinsfile): refs #8714 add CHANGE_TARGET environment variable logging (origin/8714-devToTest, 8714-devToTest) by:alexm
+- feat: refs #6695 add additional test directories for Cypress integration tests in Jenkinsfile by:alexm
+- feat: refs #6695 add cypress-cache volume to docker-compose.e2e.yml by:alexm
+- feat: refs #6695 add Dockerfile for Cypress setup and update Jenkinsfile for installation steps by:alexm
+- feat: refs #6695 add setup and e2e testing by:alexm
+- feat: refs #6695 better stages for e2e by:alexm
+- feat: refs #6695 better stages for e2e rollback by:alexm
+- feat: refs #6695 install Cypress during Jenkins pipeline setup by:alexm
+- feat: refs #6695 jenkins run e2e by:alexm
+- feat: refs #6695 jenkins run e2e front deteach by:alexm
+- feat: refs #6695 jenkins run e2e rebuild by:alexm
+- feat: refs #6695 jenkins run e2e remove ports by:alexm
+- feat: refs #6695 jenkins run e2e try down and rm by:alexm
+- feat: refs #6695 jenkins run e2e try fix db by:alexm
+- feat: refs #6695 jenkins run e2e whitout rebuild by:alexm
+- feat: refs #6695 pull salix-back image and use by:alexm
+- feat: refs #6695 run e2e in docker by:alexm
+- feat: refs #6695 run front by:alexm
+- feat: refs #6695 run front quasar build by:alexm
+- feat: refs #6695 run parallel e2e in local by:alexm
+- feat: refs #6695 update cypress cache path command in Jenkinsfile by:alexm
+- feat: refs #6695 update cypress-cache volume path in docker-compose.e2e.yml by:alexm
+- feat: refs #6695 update cypress command in Jenkinsfile and docker-compose.e2e.yml by:alexm
+- feat: refs #6695 update Docker configurations and Cypress settings for improved local development (origin/6695-docker_push_2, 6695-docker_push_2) by:alexm
+- feat: refs #6695 when failure, clean by:alexm
+- feat: refs #7937 add import claim button to ClaimAction component by:jgallego
+- feat: refs #7937 add shelving selection to claim actions with data fetching by:jgallego
+- feat: refs #8348 Added grouping by:guillermo
+- feat: refs #8402 added lost filters from Salix by:Jon
+- feat: refs #8484 add addressId to createForm in CustomerDescriptor by:jorgep
+- feat: refs #8484 overwrite Cypress visit command to ensure main element exists by:jorgep
+- feat: refs #8555 added new filter field and translations by:Jon
+- feat: refs #8593 added summary button & modified e2e tests by:provira
+- feat: refs #8593 changed parking to VnTable and modified e2e tests by:provira
+- feat: refs #8599 added new test and translations by:Jon
+- feat: refs #8599 modified tests to be more complete and added new ones by:Jon
+- feat: refs #8697 enable data-cy attribute for VnTable, update test cases to remove skips and adjust selectors by:pablone
+- feat: rename test:unit by test:front by:Javier Segarra
+- feat: try run salix back by:alexm
+- fix: style w-80 by:Javier Segarra
+- Merge pull request 'fix: style' (!1425) from warmfix_vntable_card_style into test by:Javier Segarra
+
+### Changed 📦
+
+- ci: refs #6695 Docker & Jenkinsfile fixes/refactor by:Juan Ferrer Toribio
+- ci: refs #6695 refactor Cypress setup in Jenkinsfile and replace local docker-compose with new configuration by:alexm
+- perf: refs #6695 only necessary by:alexm
+- refactor: adjust translation to standardize it by:Jon
+- refactor: refs #6695 comment out vnComponent tests in Jenkinsfile by:alexm
+- refactor: refs #6695 improve group size calculation for parallel test execution in Jenkinsfile by:alexm
+- refactor: refs #6695 improve parallel test execution logic in Jenkinsfile by:alexm
+- refactor: refs #6695 simplify Docker cleanup commands in Jenkinsfile by:alexm
+- refactor: refs #6695 update Docker setup for Cypress and remove obsolete files by:alexm
+- refactor: refs #6695 update E2E test execution to support parallel groups and improve by:alexm
+- refactor: refs #6695 update Jenkinsfile and Dockerfile to use 'developer' by:alexm
+- refactor: refs #6695 update Jenkinsfile to run E2E tests in parallel and simplify docker-compose command by:alexm
+- refactor: refs #6897 clean up Cypress configuration and improve entry list filtering (origin/6897-fixEntryE2e) by:pablone
+- refactor: refs #7414 update VnLog component to change display order value changes on update action by:jtubau
+- refactor: refs #7937 align columns to the right and add shelvingCode to ClaimSummaryAction by:jgallego
+- refactor: refs #8484 add data-cy attribute for claim photo image and update test to use it by:jorgep
+- refactor: refs #8484 clean up test files by removing commented issue references and updating test cases by:jorgep
+- refactor: refs #8484 enhance login command with session management and clean up unused commands by:jtubau
+- refactor: refs #8484 improve search input behavior and enhance visit command with DOM content load by:jtubau
+- refactor: refs #8484 improve selectOption command with retry logic for visibility checks by:jtubau
+- refactor: refs #8484 remove comment in wagonCreate.spec.js by:jtubau
+- refactor: refs #8484 remove redundant visit command overwrite by:jorgep
+- refactor: refs #8484 remove unnecessary domContentLoad calls from client tests by:jorgep
+- refactor: refs #8484 remove unnecessary intercepts and waits in ticket and zone tests by:jorgep
+- refactor: refs #8484 simplify image dialog test by using aliases for elements by:jorgep
+- refactor: refs #8484 streamline assertions in ClaimNotes test by:jorgep
+- refactor: refs #8484 streamline login command and remove commented code by:jorgep
+- refactor: refs #8484 update specPattern to include all spec files and remove data-cy attribute by:jorgep
+- refactor: refs #8594 update vehicle summary tests to use expected variable for consistency by:jtubau
+- refactor: refs #8599 corrected it name by:Jon
+- refactor: refs #8599 invoice out list e2e by:Jon
+- refactor: refs #8599 requested changes by:Jon
+- refactor: refs #8606 modified table height and deleted void file by:Jon
+- refactor: refs #8606 modified table width and order by:Jon
+- refactor: refs #8606 modified upcoming deliveries view by:Jon
+- refactor: refs #8606 translations by:Jon
+- refactor: refs #8618 simplify selectors and improve test readability in routeExtendedList.spec.js by:jtubau
+- refactor: refs #8620 update RouteAutonomous to notify on data save and change invoice reference display by:jtubau
+- refactor: remove default browser setting from Cypress configuration by:alexm
+- refactor: remove unused variables by:alexm
+- refactor: skip claimNotes by:alexm
+- refactor: update labels and conditions in Claim components by:jgallego
+- refactor: use constant for account input selector in VnAccountNumber tests by:alexm
+
+### Fixed 🛠️
+
+- build: refs #6695 cypress-setup fix volume by:alexm
+- build: refs #6695 cypress-setup fix volume (origin/6695-docker_push, 6695-docker_push) by:alexm
+- ci: refs #6695 cypress reporter fix by:Juan Ferrer Toribio
+- ci: refs #6695 Docker & Jenkinsfile fixes/refactor by:Juan Ferrer Toribio
+- ci: refs #6695 JUnit report fixes by:Juan Ferrer Toribio
+- ci: refs #6695 vitest junit file fix by:Juan Ferrer Toribio
+- feat(jenkinsE2E): refs #6695 try fix db by:alexm
+- feat: refs #6695 jenkins run e2e try fix db by:alexm
+- fix: add data-cy attribute to card button for improved testing by:jtubau
+- fix: added lost code by:Jon
+- fix: add --init flag to Cypress Docker container for improved stability by:alexm
+- fix: add mapper before Save by:Javier Segarra
+- fix: cy.domContentLoad(); not exist by:alexm
+- fix: elements position by:Javier Segarra
+- fix: fixed select not filtering when typing by:Jon
+- fix: fixed wagonTypeCreate test (origin/wagonTypeTestFix) by:PAU ROVIRA ROSALENY
+- fix: fix sctions by:carlossa
+- fix(Jenkinsfile): enhance Docker registry credentials handling with dynamic URL (origin/warmFix_use_withDockerRegistry, warmFix_use_withDockerRegistry) by:alexm
+- fix(Jenkinsfile): update Docker registry credentials handling in E2E stage by:alexm
+- fix: junit report by:alexm
+- fix: merge revert by:alexm
+- fix: merge test to dev by:alexm
+- fix: prevent 'cypress run' error to show junit by:alexm
+- fix: refs #6695 add --volumes flag to docker-compose down command by:alexm
+- fix: refs #6695 checkErrors(folderName) by:alexm
+- fix: refs #6695 clientBasicData by:alexm
+- fix: refs #6695 dockerFile by:alexm
+- fix: refs #6695 e2e.sh by:alexm
+- fix: refs #6695 e2e stockBought by:alexm
+- fix: refs #6695 fix e2e's by:alexm
+- fix: refs #6695 storage by:alexm
+- fix: refs #6695 try by:alexm
+- fix: refs #6695 try parallel by:alexm
+- fix: refs #6695 update Cypress cache handling and increase wait timeout for elements by:alexm
+- fix: refs #6695 update Cypress configuration and Docker setup for improved testing by:alexm
+- fix: refs #6695 update E2E stages to run tests in parallel for specific folders by:alexm
+- fix: refs #6695 update remove Cypress installation by:alexm
+- fix: refs #6695 zoneWarehouse est by:alexm
+- fix: refs #6943 e2e clientList, formModel by:carlossa
+- fix: refs #6943 formModel workerDepartment by:carlossa
+- fix: refs #7323 e2e (origin/7323-fixe2e) by:carlossa
+- fix: refs #7323 notification manager by:carlossa
+- fix: refs #7414 updated default value rendering for non-update scenarios by:jtubau
+- fix: refs #7414 update VnLog.vue to correctly display log actions and values by:jtubau
+- fix: refs #7937 update claimId in ClaimAction test to reflect correct value (origin/7937-claimAgile) by:jgallego
+- fix: refs #8484 ensure document is fully loaded before visiting pages in tests by:jorgep
+- fix: refs #8484 fixed some tests to enable previously skipped cases and enhance functionality by:jtubau
+- fix: refs #8484 remove unused addressId from createForm in CustomerDescriptor.vue by:jtubau
+- fix: refs #8484 rollback by:jorgep
+- fix: refs #8484 update Boss field type to 'selectWorker' and add selectWorkerOption command by:jtubau
+- fix: refs #8484 update Boss type from 'selectWorker' to 'select' by:jorgep
+- fix: refs #8484 update parking list URL to correct shelving path in integration test by:jtubau
+- fix: refs #8484 update selector for buyLabel button in myEntry test by:jtubau
+- fix: refs #8484 update selector for removing wagon type in wagonCreate.spec.js by:jtubau
+- fix: refs #8484 update wagon type deletion selector and clean up unused code in commands.js by:jtubau
+- fix: refs #8593 fixed parking e2e tests by:provira
+- fix: refs #8606 fixed list e2e test by:Jon
+- fix: refs #8620 add module name to InvoiceInSummary by:jtubau
+- fix: refs #8623 fixed different errors by:Jon
+- fix: remove info by:carlossa
+- fix: remove old end-to-end test files before building Docker image by:alexm
+- fix: revert cypress.config by:alexm
+- fix: style w-80 by:Javier Segarra
+- fix: unnecessary function by:alexm
+- fix: update docker-compose command to remove volumes on teardown by:alexm
+- fix: update Jenkinsfile to remove specific end-to-end test files by:alexm
+- fix: update Jenkinsfile to use environment variable for Docker registry credentials by:alexm
+- fix: warmFix vnInput dataCy by:alexm
+- Merge pull request 'fix: style' (!1425) from warmfix_vntable_card_style into test by:Javier Segarra
+- revert: browser chromium package.json by:Javier Segarra
+- Revert "revert 1015acefb7e400be2d8b5958dba69b4d98276b34" by:alexm
+- test: refs #6695 e2e fix allowedHosts by:alexm
+- test: refs #6695 e2e fix back image by:alexm
+- test: refs #6695 e2e fix base urls by:alexm
+- test: refs #6695 e2e fix command by:alexm
+- test: refs #6695 e2e fix connection db by:alexm
+- test: refs #6695 e2e fix network by:alexm
+- test: refs #6695 e2e fix sequential by:alexm
+- test: refs #6695 fix e2e by:alexm
+- test: refs #6695 fix e2e command by:alexm
+- test: refs #6695 fix selectOption command by:alexm
+
 # Version 25.08 - 2025-03-04
 
 ### Added 🆕
diff --git a/Jenkinsfile b/Jenkinsfile
index df2421a0e..a9db9d369 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -115,21 +115,27 @@ pipeline {
                     steps {
                         script {
                             sh 'rm -f junit/e2e-*.xml'
+                            sh 'rm -rf test/cypress/screenshots'
                             env.COMPOSE_TAG = PROTECTED_BRANCH.contains(env.CHANGE_TARGET) ? env.CHANGE_TARGET : 'dev'
 
                             def image = docker.build('lilium-dev', '-f docs/Dockerfile.dev docs')
 
                             sh 'docker login --username $CREDS_USR --password $CREDS_PSW $REGISTRY'
+                            sh "docker-compose ${env.COMPOSE_PARAMS} pull back"
+                            sh "docker-compose ${env.COMPOSE_PARAMS} pull db"
                             sh "docker-compose ${env.COMPOSE_PARAMS} up -d"
 
+                            def modules = sh(script: 'node test/cypress/docker/find/find.js', returnStdout: true).trim()
+                            echo "E2E MODULES: ${modules}"
                             image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") {
-                                sh 'sh test/cypress/cypressParallel.sh 3'
+                                sh "sh test/cypress/docker/cypressParallel.sh 1 '${modules}'"
                             }
                         }
                     }
                     post {
                         always {
                             sh "docker-compose ${env.COMPOSE_PARAMS} down -v"
+                            archiveArtifacts artifacts: 'test/cypress/screenshots/**/*', allowEmptyArchive: true
                             junit(
                                 testResults: 'junit/e2e-*.xml',
                                 allowEmptyResults: true
@@ -179,3 +185,4 @@ pipeline {
         }
     }
 }
+
diff --git a/README.md b/README.md
index 262e12e58..8eff99137 100644
--- a/README.md
+++ b/README.md
@@ -32,8 +32,26 @@ pnpm run test:front
 pnpm run test:e2e
 ```
 
+### Run e2e parallel
+
+```bash
+pnpm run test:e2e:parallel
+```
+
+### View e2e parallel report
+
+```bash
+pnpm run test:e2e:summary
+```
+
 ### Build the app for production
 
 ```bash
 quasar build
 ```
+
+### Serve the app for production
+
+```bash
+quasar build quasar serve dist/spa --host 0.0.0.0 --proxy=./proxy-serve.js
+```
diff --git a/docs/Dockerfile.dev b/docs/Dockerfile.dev
index 84a4d80bc..3117e2c20 100644
--- a/docs/Dockerfile.dev
+++ b/docs/Dockerfile.dev
@@ -25,6 +25,8 @@ RUN apt-get update \
         libnss3 \
         libxss1 \
         libxtst6 \
+        mesa-vulkan-drivers \
+        vulkan-tools \
         xauth \
         xvfb \
     && apt-get clean \
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 000000000..70f738bbe
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,87 @@
+import cypress from 'eslint-plugin-cypress';
+import eslint from 'eslint-plugin-import';
+import globals from 'globals';
+import js from '@eslint/js';
+import vue from 'eslint-plugin-vue';
+export default {
+    plugins: { vue, eslint, cypress },
+    languageOptions: {
+        globals: {
+            ...globals.node,
+            ...globals.browser,
+            ...vue.configs['vue3-strongly-recommended'].globals,
+            ...cypress.environments.globals.globals,
+            ga: 'readonly',
+            cordova: 'readonly',
+            __statics: 'readonly',
+            __QUASAR_SSR__: 'readonly',
+            __QUASAR_SSR_SERVER__: 'readonly',
+            __QUASAR_SSR_CLIENT__: 'readonly',
+            __QUASAR_SSR_PWA__: 'readonly',
+            process: 'readonly',
+            Capacitor: 'readonly',
+            chrome: 'readonly',
+        },
+
+        ecmaVersion: 2020,
+        sourceType: 'module',
+
+        parserOptions: {
+            parser: '@babel/eslint-parser',
+        },
+    },
+    rules: {
+        ...vue.rules['flat/strongly-recommended'],
+        ...js.configs.recommended.rules,
+        semi: 'off',
+        'generator-star-spacing': 'warn',
+        'arrow-parens': 'warn',
+        'no-var': 'error',
+        'prefer-const': 'error',
+        'prefer-template': 'warn',
+        'prefer-destructuring': 'off',
+        'prefer-spread': 'warn',
+        'prefer-rest-params': 'warn',
+        'prefer-object-spread': 'warn',
+        'prefer-arrow-callback': 'warn',
+        'prefer-numeric-literals': 'warn',
+        'prefer-exponentiation-operator': 'warn',
+        'prefer-regex-literals': 'warn',
+        'one-var': [
+            'error',
+            {
+                let: 'never',
+                const: 'never',
+            },
+        ],
+        'no-void': 'off',
+        'prefer-promise-reject-errors': 'error',
+        'multiline-ternary': 'warn',
+        'no-restricted-imports': 'warn',
+        'no-import-assign': 'warn',
+        'no-duplicate-imports': 'warn',
+        'no-useless-rename': 'warn',
+        'eslint/no-named-as-default': 'warn',
+        'eslint/no-named-as-default-member': 'warn',
+        'no-unsafe-optional-chaining': 'warn',
+        'no-undef': 'error',
+        'no-unused-vars': 'error',
+        'no-console': 'error',
+        'no-debugger': 'error',
+        'no-useless-escape': 'error',
+        'no-prototype-builtins': 'error',
+        'no-async-promise-executor': 'error',
+        'no-irregular-whitespace': 'error',
+        'no-constant-condition': 'error',
+        'no-unsafe-finally': 'error',
+        'no-extend-native': 'error',
+    },
+    ignores: [
+        '/dist',
+        '/src-capacitor',
+        '/src-cordova',
+        '/.quasar',
+        '/node_modules',
+        '.eslintrc.js',
+    ],
+};
diff --git a/package.json b/package.json
index 33b730b9e..19b4c7a6f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
     "name": "salix-front",
-    "version": "25.12.0",
+    "version": "25.16.0",
     "description": "Salix frontend",
     "productName": "Salix",
     "author": "Verdnatura",
@@ -9,14 +9,17 @@
     "type": "module",
     "scripts": {
         "resetDatabase": "cd ../salix && gulp docker",
-        "lint": "eslint --ext .js,.vue ./",
+        "lint": "eslint \"**/*.{vue,js}\" ",
+        "lint:fix": "eslint \"**/*.{vue,js}\" --fix ",
         "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
         "test:e2e": "cypress open",
         "test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
-        "test:e2e:parallel": "bash ./test/cypress/cypressParallel.sh",
+        "test:e2e:parallel": "bash ./test/cypress/run.sh",
         "test:e2e:summary": "bash ./test/cypress/summary.sh",
         "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
         "test:front": "vitest",
+        "test:ui": "vitest --ui",
+        "test:coverage": "vitest run --coverage",
         "test:front:ci": "vitest run",
         "commitlint": "commitlint --edit",
         "prepare": "npx husky install",
@@ -26,42 +29,53 @@
         "docs:preview": "vitepress preview docs"
     },
     "dependencies": {
+        "@eslint/eslintrc": "^3.2.0",
+        "@eslint/js": "^9.20.0",
         "@quasar/cli": "^2.4.1",
         "@quasar/extras": "^1.16.16",
         "axios": "^1.4.0",
         "chromium": "^3.0.3",
         "croppie": "^2.6.5",
+        "es-module-lexer": "^1.6.0",
+        "fast-glob": "^3.3.3",
         "moment": "^2.30.1",
         "pinia": "^2.1.3",
         "quasar": "^2.17.7",
         "validator": "^13.9.0",
         "vue": "^3.5.13",
-        "vue-i18n": "^9.3.0",
+        "vue-i18n": "^9.4.0",
         "vue-router": "^4.2.5"
     },
     "devDependencies": {
         "@commitlint/cli": "^19.2.1",
         "@commitlint/config-conventional": "^19.1.0",
-        "@intlify/unplugin-vue-i18n": "^0.8.2",
+        "@eslint/eslintrc": "^3.2.0",
+        "@eslint/js": "^9.20.0",
+        "@intlify/unplugin-vue-i18n": "^4.0.0",
         "@pinia/testing": "^0.1.2",
         "@quasar/app-vite": "^2.0.8",
         "@quasar/quasar-app-extension-qcalendar": "^4.0.2",
         "@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
+        "@vitest/ui": "3.1.1",
+        "@vue/compiler-sfc": "^3.5.13",
         "@vue/test-utils": "^2.4.4",
         "autoprefixer": "^10.4.14",
         "cypress": "^14.1.0",
         "cypress-mochawesome-reporter": "^3.8.2",
         "eslint": "^9.18.0",
         "eslint-config-prettier": "^10.0.1",
+        "eslint-import-resolver-alias": "^1.1.2",
         "eslint-plugin-cypress": "^4.1.0",
+        "eslint-plugin-import": "^2.31.0",
         "eslint-plugin-vue": "^9.32.0",
+        "globals": "^16.0.0",
         "husky": "^8.0.0",
+        "junit-merge": "^2.0.0",
         "mocha": "^11.1.0",
         "postcss": "^8.4.23",
         "prettier": "^3.4.2",
         "sass": "^1.83.4",
-        "vitepress": "^1.6.3",
-        "vitest": "^0.34.0",
+        "vitest": "^3.0.3",
         "xunit-viewer": "^10.6.1"
     },
     "engines": {
@@ -75,4 +89,4 @@
         "vite": "^6.0.11",
         "vitest": "^0.31.1"
     }
-}
\ No newline at end of file
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 168fb9e0d..02d82f325 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,39 +5,51 @@ settings:
   excludeLinksFromLockfile: false
 
 dependencies:
+  '@eslint/eslintrc':
+    specifier: ^3.2.0
+    version: 3.3.1
+  '@eslint/js':
+    specifier: ^9.20.0
+    version: 9.24.0
   '@quasar/cli':
     specifier: ^2.4.1
-    version: 2.4.1
+    version: 2.5.0
   '@quasar/extras':
     specifier: ^1.16.16
     version: 1.16.17
   axios:
     specifier: ^1.4.0
-    version: 1.7.9
+    version: 1.8.4
   chromium:
     specifier: ^3.0.3
     version: 3.0.3
   croppie:
     specifier: ^2.6.5
     version: 2.6.5
+  es-module-lexer:
+    specifier: ^1.6.0
+    version: 1.6.0
+  fast-glob:
+    specifier: ^3.3.3
+    version: 3.3.3
   moment:
     specifier: ^2.30.1
     version: 2.30.1
   pinia:
     specifier: ^2.1.3
-    version: 2.3.1(typescript@5.7.3)(vue@3.5.13)
+    version: 2.3.1(typescript@5.8.3)(vue@3.5.13)
   quasar:
     specifier: ^2.17.7
-    version: 2.17.7
+    version: 2.18.1
   validator:
     specifier: ^13.9.0
-    version: 13.12.0
+    version: 13.15.0
   vue:
     specifier: ^3.5.13
-    version: 3.5.13(typescript@5.7.3)
+    version: 3.5.13(typescript@5.8.3)
   vue-i18n:
-    specifier: ^9.3.0
-    version: 9.14.2(vue@3.5.13)
+    specifier: ^9.4.0
+    version: 9.14.4(vue@3.5.13)
   vue-router:
     specifier: ^4.2.5
     version: 4.5.0(vue@3.5.13)
@@ -45,52 +57,70 @@ dependencies:
 devDependencies:
   '@commitlint/cli':
     specifier: ^19.2.1
-    version: 19.7.1(@types/node@22.13.5)(typescript@5.7.3)
+    version: 19.8.0(@types/node@22.14.0)(typescript@5.8.3)
   '@commitlint/config-conventional':
     specifier: ^19.1.0
-    version: 19.7.1
+    version: 19.8.0
   '@intlify/unplugin-vue-i18n':
-    specifier: ^0.8.2
-    version: 0.8.2(vue-i18n@9.14.2)
+    specifier: ^4.0.0
+    version: 4.0.0(vue-i18n@9.14.4)
   '@pinia/testing':
     specifier: ^0.1.2
     version: 0.1.7(pinia@2.3.1)(vue@3.5.13)
   '@quasar/app-vite':
     specifier: ^2.0.8
-    version: 2.1.0(@types/node@22.13.5)(eslint@9.20.1)(pinia@2.3.1)(quasar@2.17.7)(sass@1.85.0)(typescript@5.7.3)(vue-router@4.5.0)(vue@3.5.13)
+    version: 2.2.0(@types/node@22.14.0)(eslint@9.24.0)(pinia@2.3.1)(quasar@2.18.1)(sass@1.86.3)(typescript@5.8.3)(vue-router@4.5.0)(vue@3.5.13)
   '@quasar/quasar-app-extension-qcalendar':
     specifier: ^4.0.2
     version: 4.1.2
   '@quasar/quasar-app-extension-testing-unit-vitest':
     specifier: ^0.4.0
-    version: 0.4.0(@vue/test-utils@2.4.6)(quasar@2.17.7)(typescript@5.7.3)(vite@6.2.0)(vitest@0.34.6)(vue@3.5.13)
+    version: 0.4.0(@vitest/ui@3.1.1)(@vue/test-utils@2.4.6)(quasar@2.18.1)(typescript@5.8.3)(vite@6.2.5)(vitest@3.1.1)(vue@3.5.13)
+  '@vitest/ui':
+    specifier: 3.1.1
+    version: 3.1.1(vitest@3.1.1)
+  '@vue/compiler-sfc':
+    specifier: ^3.5.13
+    version: 3.5.13
   '@vue/test-utils':
     specifier: ^2.4.4
     version: 2.4.6
   autoprefixer:
     specifier: ^10.4.14
-    version: 10.4.20(postcss@8.5.3)
+    version: 10.4.21(postcss@8.5.3)
   cypress:
     specifier: ^14.1.0
-    version: 14.1.0
+    version: 14.2.1
   cypress-mochawesome-reporter:
     specifier: ^3.8.2
-    version: 3.8.2(cypress@14.1.0)(mocha@11.1.0)
+    version: 3.8.2(cypress@14.2.1)(mocha@11.1.0)
   eslint:
     specifier: ^9.18.0
-    version: 9.20.1
+    version: 9.24.0
   eslint-config-prettier:
     specifier: ^10.0.1
-    version: 10.0.1(eslint@9.20.1)
+    version: 10.1.1(eslint@9.24.0)
+  eslint-import-resolver-alias:
+    specifier: ^1.1.2
+    version: 1.1.2(eslint-plugin-import@2.31.0)
   eslint-plugin-cypress:
     specifier: ^4.1.0
-    version: 4.1.0(eslint@9.20.1)
+    version: 4.2.0(eslint@9.24.0)
+  eslint-plugin-import:
+    specifier: ^2.31.0
+    version: 2.31.0(eslint@9.24.0)
   eslint-plugin-vue:
     specifier: ^9.32.0
-    version: 9.32.0(eslint@9.20.1)
+    version: 9.33.0(eslint@9.24.0)
+  globals:
+    specifier: ^16.0.0
+    version: 16.0.0
   husky:
     specifier: ^8.0.0
     version: 8.0.3
+  junit-merge:
+    specifier: ^2.0.0
+    version: 2.0.0
   mocha:
     specifier: ^11.1.0
     version: 11.1.0
@@ -99,182 +129,19 @@ devDependencies:
     version: 8.5.3
   prettier:
     specifier: ^3.4.2
-    version: 3.5.1
+    version: 3.5.3
   sass:
     specifier: ^1.83.4
-    version: 1.85.0
-  vitepress:
-    specifier: ^1.6.3
-    version: 1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(react-dom@19.0.0)(react@19.0.0)(sass@1.85.0)(search-insights@2.17.3)(typescript@5.7.3)
+    version: 1.86.3
   vitest:
-    specifier: ^0.34.0
-    version: 0.34.6(sass@1.85.0)
+    specifier: ^3.0.3
+    version: 3.1.1(@types/node@22.14.0)(@vitest/ui@3.1.1)(sass@1.86.3)
   xunit-viewer:
     specifier: ^10.6.1
-    version: 10.6.1(@babel/runtime@7.26.9)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.3)(codemirror@6.0.1)(react-dom@19.0.0)(react@19.0.0)
+    version: 10.6.1(@babel/runtime@7.27.0)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.5)(codemirror@6.0.1)(react-dom@19.1.0)(react@19.1.0)
 
 packages:
 
-  /@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)(search-insights@2.17.3):
-    resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==}
-    dependencies:
-      '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)(search-insights@2.17.3)
-      '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)
-    transitivePeerDependencies:
-      - '@algolia/client-search'
-      - algoliasearch
-      - search-insights
-    dev: true
-
-  /@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)(search-insights@2.17.3):
-    resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==}
-    peerDependencies:
-      search-insights: '>= 1 < 3'
-    dependencies:
-      '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)
-      search-insights: 2.17.3
-    transitivePeerDependencies:
-      - '@algolia/client-search'
-      - algoliasearch
-    dev: true
-
-  /@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3):
-    resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==}
-    peerDependencies:
-      '@algolia/client-search': '>= 4.9.1 < 6'
-      algoliasearch: '>= 4.9.1 < 6'
-    dependencies:
-      '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)
-      '@algolia/client-search': 5.20.3
-      algoliasearch: 5.20.3
-    dev: true
-
-  /@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3):
-    resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==}
-    peerDependencies:
-      '@algolia/client-search': '>= 4.9.1 < 6'
-      algoliasearch: '>= 4.9.1 < 6'
-    dependencies:
-      '@algolia/client-search': 5.20.3
-      algoliasearch: 5.20.3
-    dev: true
-
-  /@algolia/client-abtesting@5.20.3:
-    resolution: {integrity: sha512-wPOzHYSsW+H97JkBLmnlOdJSpbb9mIiuNPycUCV5DgzSkJFaI/OFxXfZXAh1gqxK+hf0miKue1C9bltjWljrNA==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/client-analytics@5.20.3:
-    resolution: {integrity: sha512-XE3iduH9lA7iTQacDGofBQyIyIgaX8qbTRRdj1bOCmfzc9b98CoiMwhNwdTifmmMewmN0EhVF3hP8KjKWwX7Yw==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/client-common@5.20.3:
-    resolution: {integrity: sha512-IYRd/A/R3BXeaQVT2805lZEdWo54v39Lqa7ABOxIYnUvX2vvOMW1AyzCuT0U7Q+uPdD4UW48zksUKRixShcWxA==}
-    engines: {node: '>= 14.0.0'}
-    dev: true
-
-  /@algolia/client-insights@5.20.3:
-    resolution: {integrity: sha512-QGc/bmDUBgzB71rDL6kihI2e1Mx6G6PxYO5Ks84iL3tDcIel1aFuxtRF14P8saGgdIe1B6I6QkpkeIddZ6vWQw==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/client-personalization@5.20.3:
-    resolution: {integrity: sha512-zuM31VNPDJ1LBIwKbYGz/7+CSm+M8EhlljDamTg8AnDilnCpKjBebWZR5Tftv/FdWSro4tnYGOIz1AURQgZ+tQ==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/client-query-suggestions@5.20.3:
-    resolution: {integrity: sha512-Nn872PuOI8qzi1bxMMhJ0t2AzVBqN01jbymBQOkypvZHrrjZPso3iTpuuLLo9gi3yc/08vaaWTAwJfPhxPwJUw==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/client-search@5.20.3:
-    resolution: {integrity: sha512-9+Fm1ahV8/2goSIPIqZnVitV5yHW5E5xTdKy33xnqGd45A9yVv5tTkudWzEXsbfBB47j9Xb3uYPZjAvV5RHbKA==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/ingestion@1.20.3:
-    resolution: {integrity: sha512-5GHNTiZ3saLjTNyr6WkP5hzDg2eFFAYWomvPcm9eHWskjzXt8R0IOiW9kkTS6I6hXBwN5H9Zna5mZDSqqJdg+g==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/monitoring@1.20.3:
-    resolution: {integrity: sha512-KUWQbTPoRjP37ivXSQ1+lWMfaifCCMzTnEcEnXwAmherS5Tp7us6BAqQDMGOD4E7xyaS2I8pto6WlOzxH+CxmA==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/recommend@5.20.3:
-    resolution: {integrity: sha512-oo/gG77xTTTclkrdFem0Kmx5+iSRFiwuRRdxZETDjwzCI7svutdbwBgV/Vy4D4QpYaX4nhY/P43k84uEowCE4Q==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
-  /@algolia/requester-browser-xhr@5.20.3:
-    resolution: {integrity: sha512-BkkW7otbiI/Er1AiEPZs1h7lxbtSO9p09jFhv3/iT8/0Yz0CY79VJ9iq+Wv1+dq/l0OxnMpBy8mozrieGA3mXQ==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-    dev: true
-
-  /@algolia/requester-fetch@5.20.3:
-    resolution: {integrity: sha512-eAVlXz7UNzTsA1EDr+p0nlIH7WFxo7k3NMxYe8p38DH8YVWLgm2MgOVFUMNg9HCi6ZNOi/A2w/id2ZZ4sKgUOw==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-    dev: true
-
-  /@algolia/requester-node-http@5.20.3:
-    resolution: {integrity: sha512-FqR3pQPfHfQyX1wgcdK6iyqu86yP76MZd4Pzj1y/YLMj9rRmRCY0E0AffKr//nrOFEwv6uY8BQY4fd9/6b0ZCg==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-common': 5.20.3
-    dev: true
-
   /@babel/code-frame@7.26.2:
     resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
     engines: {node: '>=6.9.0'}
@@ -292,65 +159,65 @@ packages:
     resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
     engines: {node: '>=6.9.0'}
 
-  /@babel/parser@7.26.9:
-    resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==}
+  /@babel/parser@7.27.0:
+    resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==}
     engines: {node: '>=6.0.0'}
     hasBin: true
     dependencies:
-      '@babel/types': 7.26.9
+      '@babel/types': 7.27.0
 
-  /@babel/runtime@7.26.9:
-    resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==}
+  /@babel/runtime@7.27.0:
+    resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==}
     engines: {node: '>=6.9.0'}
     dependencies:
       regenerator-runtime: 0.14.1
     dev: true
 
-  /@babel/types@7.26.9:
-    resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==}
+  /@babel/types@7.27.0:
+    resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/helper-string-parser': 7.25.9
       '@babel/helper-validator-identifier': 7.25.9
 
-  /@bufbuild/protobuf@2.2.3:
-    resolution: {integrity: sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==}
+  /@bufbuild/protobuf@2.2.5:
+    resolution: {integrity: sha512-/g5EzJifw5GF8aren8wZ/G5oMuPoGeS6MQD3ca8ddcvdXR5UELUfdTZITCGNhNXynY/AYl3Z4plmxdj/tRl/hQ==}
     dev: true
 
   /@codemirror/autocomplete@6.18.6:
     resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==}
     dependencies:
-      '@codemirror/language': 6.10.8
+      '@codemirror/language': 6.11.0
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
       '@lezer/common': 1.2.3
     dev: true
 
-  /@codemirror/commands@6.8.0:
-    resolution: {integrity: sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==}
+  /@codemirror/commands@6.8.1:
+    resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==}
     dependencies:
-      '@codemirror/language': 6.10.8
+      '@codemirror/language': 6.11.0
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
       '@lezer/common': 1.2.3
     dev: true
 
-  /@codemirror/language@6.10.8:
-    resolution: {integrity: sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==}
+  /@codemirror/language@6.11.0:
+    resolution: {integrity: sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==}
     dependencies:
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
       '@lezer/common': 1.2.3
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
       style-mod: 4.1.2
     dev: true
 
-  /@codemirror/lint@6.8.4:
-    resolution: {integrity: sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==}
+  /@codemirror/lint@6.8.5:
+    resolution: {integrity: sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==}
     dependencies:
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
       crelt: 1.0.6
     dev: true
 
@@ -358,7 +225,7 @@ packages:
     resolution: {integrity: sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg==}
     dependencies:
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
       crelt: 1.0.6
     dev: true
 
@@ -371,14 +238,14 @@ packages:
   /@codemirror/theme-one-dark@6.1.2:
     resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==}
     dependencies:
-      '@codemirror/language': 6.10.8
+      '@codemirror/language': 6.11.0
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
       '@lezer/highlight': 1.2.1
     dev: true
 
-  /@codemirror/view@6.36.3:
-    resolution: {integrity: sha512-N2bilM47QWC8Hnx0rMdDxO2x2ImJ1FvZWXubwKgjeoOrWwEiFrtpA7SFHcuZ+o2Ze2VzbkgbzWVj4+V18LVkeg==}
+  /@codemirror/view@6.36.5:
+    resolution: {integrity: sha512-cd+FZEUlu3GQCYnguYm3EkhJ8KJVisqqUsCOKedBoAt/d9c76JUUap6U0UrpElln5k6VyrEOYliMuDAKIeDQLg==}
     dependencies:
       '@codemirror/state': 6.5.2
       style-mod: 4.1.2
@@ -392,16 +259,16 @@ packages:
     dev: true
     optional: true
 
-  /@commitlint/cli@19.7.1(@types/node@22.13.5)(typescript@5.7.3):
-    resolution: {integrity: sha512-iObGjR1tE/PfDtDTEfd+tnRkB3/HJzpQqRTyofS2MPPkDn1mp3DBC8SoPDayokfAy+xKhF8+bwRCJO25Nea0YQ==}
+  /@commitlint/cli@19.8.0(@types/node@22.14.0)(typescript@5.8.3):
+    resolution: {integrity: sha512-t/fCrLVu+Ru01h0DtlgHZXbHV2Y8gKocTR5elDOqIRUzQd0/6hpt2VIWOj9b3NDo7y4/gfxeR2zRtXq/qO6iUg==}
     engines: {node: '>=v18'}
     hasBin: true
     dependencies:
-      '@commitlint/format': 19.5.0
-      '@commitlint/lint': 19.7.1
-      '@commitlint/load': 19.6.1(@types/node@22.13.5)(typescript@5.7.3)
-      '@commitlint/read': 19.5.0
-      '@commitlint/types': 19.5.0
+      '@commitlint/format': 19.8.0
+      '@commitlint/lint': 19.8.0
+      '@commitlint/load': 19.8.0(@types/node@22.14.0)(typescript@5.8.3)
+      '@commitlint/read': 19.8.0
+      '@commitlint/types': 19.8.0
       tinyexec: 0.3.2
       yargs: 17.7.2
     transitivePeerDependencies:
@@ -409,27 +276,27 @@ packages:
       - typescript
     dev: true
 
-  /@commitlint/config-conventional@19.7.1:
-    resolution: {integrity: sha512-fsEIF8zgiI/FIWSnykdQNj/0JE4av08MudLTyYHm4FlLWemKoQvPNUYU2M/3tktWcCEyq7aOkDDgtjrmgWFbvg==}
+  /@commitlint/config-conventional@19.8.0:
+    resolution: {integrity: sha512-9I2kKJwcAPwMoAj38hwqFXG0CzS2Kj+SAByPUQ0SlHTfb7VUhYVmo7G2w2tBrqmOf7PFd6MpZ/a1GQJo8na8kw==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/types': 19.5.0
+      '@commitlint/types': 19.8.0
       conventional-changelog-conventionalcommits: 7.0.2
     dev: true
 
-  /@commitlint/config-validator@19.5.0:
-    resolution: {integrity: sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw==}
+  /@commitlint/config-validator@19.8.0:
+    resolution: {integrity: sha512-+r5ZvD/0hQC3w5VOHJhGcCooiAVdynFlCe2d6I9dU+PvXdV3O+fU4vipVg+6hyLbQUuCH82mz3HnT/cBQTYYuA==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/types': 19.5.0
+      '@commitlint/types': 19.8.0
       ajv: 8.17.1
     dev: true
 
-  /@commitlint/ensure@19.5.0:
-    resolution: {integrity: sha512-Kv0pYZeMrdg48bHFEU5KKcccRfKmISSm9MvgIgkpI6m+ohFTB55qZlBW6eYqh/XDfRuIO0x4zSmvBjmOwWTwkg==}
+  /@commitlint/ensure@19.8.0:
+    resolution: {integrity: sha512-kNiNU4/bhEQ/wutI1tp1pVW1mQ0QbAjfPRo5v8SaxoVV+ARhkB8Wjg3BSseNYECPzWWfg/WDqQGIfV1RaBFQZg==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/types': 19.5.0
+      '@commitlint/types': 19.8.0
       lodash.camelcase: 4.3.0
       lodash.kebabcase: 4.1.1
       lodash.snakecase: 4.1.1
@@ -437,48 +304,48 @@ packages:
       lodash.upperfirst: 4.3.1
     dev: true
 
-  /@commitlint/execute-rule@19.5.0:
-    resolution: {integrity: sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg==}
+  /@commitlint/execute-rule@19.8.0:
+    resolution: {integrity: sha512-fuLeI+EZ9x2v/+TXKAjplBJWI9CNrHnyi5nvUQGQt4WRkww/d95oVRsc9ajpt4xFrFmqMZkd/xBQHZDvALIY7A==}
     engines: {node: '>=v18'}
     dev: true
 
-  /@commitlint/format@19.5.0:
-    resolution: {integrity: sha512-yNy088miE52stCI3dhG/vvxFo9e4jFkU1Mj3xECfzp/bIS/JUay4491huAlVcffOoMK1cd296q0W92NlER6r3A==}
+  /@commitlint/format@19.8.0:
+    resolution: {integrity: sha512-EOpA8IERpQstxwp/WGnDArA7S+wlZDeTeKi98WMOvaDLKbjptuHWdOYYr790iO7kTCif/z971PKPI2PkWMfOxg==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/types': 19.5.0
+      '@commitlint/types': 19.8.0
       chalk: 5.4.1
     dev: true
 
-  /@commitlint/is-ignored@19.7.1:
-    resolution: {integrity: sha512-3IaOc6HVg2hAoGleRK3r9vL9zZ3XY0rf1RsUf6jdQLuaD46ZHnXBiOPTyQ004C4IvYjSWqJwlh0/u2P73aIE3g==}
+  /@commitlint/is-ignored@19.8.0:
+    resolution: {integrity: sha512-L2Jv9yUg/I+jF3zikOV0rdiHUul9X3a/oU5HIXhAJLE2+TXTnEBfqYP9G5yMw/Yb40SnR764g4fyDK6WR2xtpw==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/types': 19.5.0
+      '@commitlint/types': 19.8.0
       semver: 7.7.1
     dev: true
 
-  /@commitlint/lint@19.7.1:
-    resolution: {integrity: sha512-LhcPfVjcOcOZA7LEuBBeO00o3MeZa+tWrX9Xyl1r9PMd5FWsEoZI9IgnGqTKZ0lZt5pO3ZlstgnRyY1CJJc9Xg==}
+  /@commitlint/lint@19.8.0:
+    resolution: {integrity: sha512-+/NZKyWKSf39FeNpqhfMebmaLa1P90i1Nrb1SrA7oSU5GNN/lksA4z6+ZTnsft01YfhRZSYMbgGsARXvkr/VLQ==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/is-ignored': 19.7.1
-      '@commitlint/parse': 19.5.0
-      '@commitlint/rules': 19.6.0
-      '@commitlint/types': 19.5.0
+      '@commitlint/is-ignored': 19.8.0
+      '@commitlint/parse': 19.8.0
+      '@commitlint/rules': 19.8.0
+      '@commitlint/types': 19.8.0
     dev: true
 
-  /@commitlint/load@19.6.1(@types/node@22.13.5)(typescript@5.7.3):
-    resolution: {integrity: sha512-kE4mRKWWNju2QpsCWt428XBvUH55OET2N4QKQ0bF85qS/XbsRGG1MiTByDNlEVpEPceMkDr46LNH95DtRwcsfA==}
+  /@commitlint/load@19.8.0(@types/node@22.14.0)(typescript@5.8.3):
+    resolution: {integrity: sha512-4rvmm3ff81Sfb+mcWT5WKlyOa+Hd33WSbirTVUer0wjS1Hv/Hzr07Uv1ULIV9DkimZKNyOwXn593c+h8lsDQPQ==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/config-validator': 19.5.0
-      '@commitlint/execute-rule': 19.5.0
-      '@commitlint/resolve-extends': 19.5.0
-      '@commitlint/types': 19.5.0
+      '@commitlint/config-validator': 19.8.0
+      '@commitlint/execute-rule': 19.8.0
+      '@commitlint/resolve-extends': 19.8.0
+      '@commitlint/types': 19.8.0
       chalk: 5.4.1
-      cosmiconfig: 9.0.0(typescript@5.7.3)
-      cosmiconfig-typescript-loader: 6.1.0(@types/node@22.13.5)(cosmiconfig@9.0.0)(typescript@5.7.3)
+      cosmiconfig: 9.0.0(typescript@5.8.3)
+      cosmiconfig-typescript-loader: 6.1.0(@types/node@22.14.0)(cosmiconfig@9.0.0)(typescript@5.8.3)
       lodash.isplainobject: 4.0.6
       lodash.merge: 4.6.2
       lodash.uniq: 4.5.0
@@ -487,67 +354,67 @@ packages:
       - typescript
     dev: true
 
-  /@commitlint/message@19.5.0:
-    resolution: {integrity: sha512-R7AM4YnbxN1Joj1tMfCyBryOC5aNJBdxadTZkuqtWi3Xj0kMdutq16XQwuoGbIzL2Pk62TALV1fZDCv36+JhTQ==}
+  /@commitlint/message@19.8.0:
+    resolution: {integrity: sha512-qs/5Vi9bYjf+ZV40bvdCyBn5DvbuelhR6qewLE8Bh476F7KnNyLfdM/ETJ4cp96WgeeHo6tesA2TMXS0sh5X4A==}
     engines: {node: '>=v18'}
     dev: true
 
-  /@commitlint/parse@19.5.0:
-    resolution: {integrity: sha512-cZ/IxfAlfWYhAQV0TwcbdR1Oc0/r0Ik1GEessDJ3Lbuma/MRO8FRQX76eurcXtmhJC//rj52ZSZuXUg0oIX0Fw==}
+  /@commitlint/parse@19.8.0:
+    resolution: {integrity: sha512-YNIKAc4EXvNeAvyeEnzgvm1VyAe0/b3Wax7pjJSwXuhqIQ1/t2hD3OYRXb6D5/GffIvaX82RbjD+nWtMZCLL7Q==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/types': 19.5.0
+      '@commitlint/types': 19.8.0
       conventional-changelog-angular: 7.0.0
       conventional-commits-parser: 5.0.0
     dev: true
 
-  /@commitlint/read@19.5.0:
-    resolution: {integrity: sha512-TjS3HLPsLsxFPQj6jou8/CZFAmOP2y+6V4PGYt3ihbQKTY1Jnv0QG28WRKl/d1ha6zLODPZqsxLEov52dhR9BQ==}
+  /@commitlint/read@19.8.0:
+    resolution: {integrity: sha512-6ywxOGYajcxK1y1MfzrOnwsXO6nnErna88gRWEl3qqOOP8MDu/DTeRkGLXBFIZuRZ7mm5yyxU5BmeUvMpNte5w==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/top-level': 19.5.0
-      '@commitlint/types': 19.5.0
+      '@commitlint/top-level': 19.8.0
+      '@commitlint/types': 19.8.0
       git-raw-commits: 4.0.0
       minimist: 1.2.8
       tinyexec: 0.3.2
     dev: true
 
-  /@commitlint/resolve-extends@19.5.0:
-    resolution: {integrity: sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA==}
+  /@commitlint/resolve-extends@19.8.0:
+    resolution: {integrity: sha512-CLanRQwuG2LPfFVvrkTrBR/L/DMy3+ETsgBqW1OvRxmzp/bbVJW0Xw23LnnExgYcsaFtos967lul1CsbsnJlzQ==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/config-validator': 19.5.0
-      '@commitlint/types': 19.5.0
+      '@commitlint/config-validator': 19.8.0
+      '@commitlint/types': 19.8.0
       global-directory: 4.0.1
       import-meta-resolve: 4.1.0
       lodash.mergewith: 4.6.2
       resolve-from: 5.0.0
     dev: true
 
-  /@commitlint/rules@19.6.0:
-    resolution: {integrity: sha512-1f2reW7lbrI0X0ozZMesS/WZxgPa4/wi56vFuJENBmed6mWq5KsheN/nxqnl/C23ioxpPO/PL6tXpiiFy5Bhjw==}
+  /@commitlint/rules@19.8.0:
+    resolution: {integrity: sha512-IZ5IE90h6DSWNuNK/cwjABLAKdy8tP8OgGVGbXe1noBEX5hSsu00uRlLu6JuruiXjWJz2dZc+YSw3H0UZyl/mA==}
     engines: {node: '>=v18'}
     dependencies:
-      '@commitlint/ensure': 19.5.0
-      '@commitlint/message': 19.5.0
-      '@commitlint/to-lines': 19.5.0
-      '@commitlint/types': 19.5.0
+      '@commitlint/ensure': 19.8.0
+      '@commitlint/message': 19.8.0
+      '@commitlint/to-lines': 19.8.0
+      '@commitlint/types': 19.8.0
     dev: true
 
-  /@commitlint/to-lines@19.5.0:
-    resolution: {integrity: sha512-R772oj3NHPkodOSRZ9bBVNq224DOxQtNef5Pl8l2M8ZnkkzQfeSTr4uxawV2Sd3ui05dUVzvLNnzenDBO1KBeQ==}
+  /@commitlint/to-lines@19.8.0:
+    resolution: {integrity: sha512-3CKLUw41Cur8VMjh16y8LcsOaKbmQjAKCWlXx6B0vOUREplp6em9uIVhI8Cv934qiwkbi2+uv+mVZPnXJi1o9A==}
     engines: {node: '>=v18'}
     dev: true
 
-  /@commitlint/top-level@19.5.0:
-    resolution: {integrity: sha512-IP1YLmGAk0yWrImPRRc578I3dDUI5A2UBJx9FbSOjxe9sTlzFiwVJ+zeMLgAtHMtGZsC8LUnzmW1qRemkFU4ng==}
+  /@commitlint/top-level@19.8.0:
+    resolution: {integrity: sha512-Rphgoc/omYZisoNkcfaBRPQr4myZEHhLPx2/vTXNLjiCw4RgfPR1wEgUpJ9OOmDCiv5ZyIExhprNLhteqH4FuQ==}
     engines: {node: '>=v18'}
     dependencies:
       find-up: 7.0.0
     dev: true
 
-  /@commitlint/types@19.5.0:
-    resolution: {integrity: sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg==}
+  /@commitlint/types@19.8.0:
+    resolution: {integrity: sha512-LRjP623jPyf3Poyfb0ohMj8I3ORyBDOwXAgxxVPbSD0unJuW2mJWeiRfaQinjtccMqC5Wy1HOMfa4btKjbNxbg==}
     engines: {node: '>=v18'}
     dependencies:
       '@types/conventional-commits-parser': 5.0.1
@@ -558,8 +425,8 @@ packages:
     resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
     dev: true
 
-  /@cypress/request@3.0.7:
-    resolution: {integrity: sha512-LzxlLEMbBOPYB85uXrDqvD4MgcenjRBLIns3zyhx7vTPj/0u2eQhzXvPiGcaJrV38Q9dbkExWp6cOHPJ+EtFYg==}
+  /@cypress/request@3.0.8:
+    resolution: {integrity: sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ==}
     engines: {node: '>= 6'}
     dependencies:
       aws-sign2: 0.7.0
@@ -575,9 +442,9 @@ packages:
       json-stringify-safe: 5.0.1
       mime-types: 2.1.35
       performance-now: 2.1.0
-      qs: 6.13.1
+      qs: 6.14.0
       safe-buffer: 5.2.1
-      tough-cookie: 5.1.1
+      tough-cookie: 5.1.2
       tunnel-agent: 0.6.0
       uuid: 8.3.2
     dev: true
@@ -591,62 +458,8 @@ packages:
       - supports-color
     dev: true
 
-  /@docsearch/css@3.8.2:
-    resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==}
-    dev: true
-
-  /@docsearch/js@3.8.2(@algolia/client-search@5.20.3)(react-dom@19.0.0)(react@19.0.0)(search-insights@2.17.3):
-    resolution: {integrity: sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==}
-    dependencies:
-      '@docsearch/react': 3.8.2(@algolia/client-search@5.20.3)(react-dom@19.0.0)(react@19.0.0)(search-insights@2.17.3)
-      preact: 10.26.2
-    transitivePeerDependencies:
-      - '@algolia/client-search'
-      - '@types/react'
-      - react
-      - react-dom
-      - search-insights
-    dev: true
-
-  /@docsearch/react@3.8.2(@algolia/client-search@5.20.3)(react-dom@19.0.0)(react@19.0.0)(search-insights@2.17.3):
-    resolution: {integrity: sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==}
-    peerDependencies:
-      '@types/react': '>= 16.8.0 < 19.0.0'
-      react: '>= 16.8.0 < 19.0.0'
-      react-dom: '>= 16.8.0 < 19.0.0'
-      search-insights: '>= 1 < 3'
-    peerDependenciesMeta:
-      '@types/react':
-        optional: true
-      react:
-        optional: true
-      react-dom:
-        optional: true
-      search-insights:
-        optional: true
-    dependencies:
-      '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)(search-insights@2.17.3)
-      '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.20.3)(algoliasearch@5.20.3)
-      '@docsearch/css': 3.8.2
-      algoliasearch: 5.20.3
-      react: 19.0.0
-      react-dom: 19.0.0(react@19.0.0)
-      search-insights: 2.17.3
-    transitivePeerDependencies:
-      - '@algolia/client-search'
-    dev: true
-
-  /@esbuild/aix-ppc64@0.21.5:
-    resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [aix]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/aix-ppc64@0.24.2:
-    resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
+  /@esbuild/aix-ppc64@0.25.2:
+    resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==}
     engines: {node: '>=18'}
     cpu: [ppc64]
     os: [aix]
@@ -654,26 +467,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/aix-ppc64@0.25.0:
-    resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==}
-    engines: {node: '>=18'}
-    cpu: [ppc64]
-    os: [aix]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/android-arm64@0.21.5:
-    resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/android-arm64@0.24.2:
-    resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
+  /@esbuild/android-arm64@0.25.2:
+    resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==}
     engines: {node: '>=18'}
     cpu: [arm64]
     os: [android]
@@ -681,26 +476,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-arm64@0.25.0:
-    resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==}
-    engines: {node: '>=18'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/android-arm@0.21.5:
-    resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/android-arm@0.24.2:
-    resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
+  /@esbuild/android-arm@0.25.2:
+    resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==}
     engines: {node: '>=18'}
     cpu: [arm]
     os: [android]
@@ -708,26 +485,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-arm@0.25.0:
-    resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==}
-    engines: {node: '>=18'}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/android-x64@0.21.5:
-    resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/android-x64@0.24.2:
-    resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
+  /@esbuild/android-x64@0.25.2:
+    resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [android]
@@ -735,26 +494,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-x64@0.25.0:
-    resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/darwin-arm64@0.21.5:
-    resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/darwin-arm64@0.24.2:
-    resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
+  /@esbuild/darwin-arm64@0.25.2:
+    resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==}
     engines: {node: '>=18'}
     cpu: [arm64]
     os: [darwin]
@@ -762,26 +503,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/darwin-arm64@0.25.0:
-    resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==}
-    engines: {node: '>=18'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/darwin-x64@0.21.5:
-    resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/darwin-x64@0.24.2:
-    resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
+  /@esbuild/darwin-x64@0.25.2:
+    resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [darwin]
@@ -789,26 +512,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/darwin-x64@0.25.0:
-    resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/freebsd-arm64@0.21.5:
-    resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/freebsd-arm64@0.24.2:
-    resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
+  /@esbuild/freebsd-arm64@0.25.2:
+    resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==}
     engines: {node: '>=18'}
     cpu: [arm64]
     os: [freebsd]
@@ -816,26 +521,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/freebsd-arm64@0.25.0:
-    resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==}
-    engines: {node: '>=18'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/freebsd-x64@0.21.5:
-    resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/freebsd-x64@0.24.2:
-    resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
+  /@esbuild/freebsd-x64@0.25.2:
+    resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [freebsd]
@@ -843,26 +530,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/freebsd-x64@0.25.0:
-    resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-arm64@0.21.5:
-    resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-arm64@0.24.2:
-    resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
+  /@esbuild/linux-arm64@0.25.2:
+    resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==}
     engines: {node: '>=18'}
     cpu: [arm64]
     os: [linux]
@@ -870,26 +539,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-arm64@0.25.0:
-    resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==}
-    engines: {node: '>=18'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-arm@0.21.5:
-    resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-arm@0.24.2:
-    resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
+  /@esbuild/linux-arm@0.25.2:
+    resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==}
     engines: {node: '>=18'}
     cpu: [arm]
     os: [linux]
@@ -897,26 +548,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-arm@0.25.0:
-    resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==}
-    engines: {node: '>=18'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-ia32@0.21.5:
-    resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-ia32@0.24.2:
-    resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
+  /@esbuild/linux-ia32@0.25.2:
+    resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==}
     engines: {node: '>=18'}
     cpu: [ia32]
     os: [linux]
@@ -924,26 +557,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-ia32@0.25.0:
-    resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==}
-    engines: {node: '>=18'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-loong64@0.21.5:
-    resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
-    engines: {node: '>=12'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-loong64@0.24.2:
-    resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
+  /@esbuild/linux-loong64@0.25.2:
+    resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==}
     engines: {node: '>=18'}
     cpu: [loong64]
     os: [linux]
@@ -951,26 +566,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-loong64@0.25.0:
-    resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==}
-    engines: {node: '>=18'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-mips64el@0.21.5:
-    resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
-    engines: {node: '>=12'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-mips64el@0.24.2:
-    resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
+  /@esbuild/linux-mips64el@0.25.2:
+    resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==}
     engines: {node: '>=18'}
     cpu: [mips64el]
     os: [linux]
@@ -978,26 +575,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-mips64el@0.25.0:
-    resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==}
-    engines: {node: '>=18'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-ppc64@0.21.5:
-    resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-ppc64@0.24.2:
-    resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
+  /@esbuild/linux-ppc64@0.25.2:
+    resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==}
     engines: {node: '>=18'}
     cpu: [ppc64]
     os: [linux]
@@ -1005,26 +584,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-ppc64@0.25.0:
-    resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==}
-    engines: {node: '>=18'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-riscv64@0.21.5:
-    resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
-    engines: {node: '>=12'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-riscv64@0.24.2:
-    resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
+  /@esbuild/linux-riscv64@0.25.2:
+    resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==}
     engines: {node: '>=18'}
     cpu: [riscv64]
     os: [linux]
@@ -1032,26 +593,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-riscv64@0.25.0:
-    resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==}
-    engines: {node: '>=18'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-s390x@0.21.5:
-    resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
-    engines: {node: '>=12'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-s390x@0.24.2:
-    resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
+  /@esbuild/linux-s390x@0.25.2:
+    resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==}
     engines: {node: '>=18'}
     cpu: [s390x]
     os: [linux]
@@ -1059,26 +602,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-s390x@0.25.0:
-    resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==}
-    engines: {node: '>=18'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-x64@0.21.5:
-    resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/linux-x64@0.24.2:
-    resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
+  /@esbuild/linux-x64@0.25.2:
+    resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [linux]
@@ -1086,17 +611,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-x64@0.25.0:
-    resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/netbsd-arm64@0.24.2:
-    resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
+  /@esbuild/netbsd-arm64@0.25.2:
+    resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==}
     engines: {node: '>=18'}
     cpu: [arm64]
     os: [netbsd]
@@ -1104,26 +620,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/netbsd-arm64@0.25.0:
-    resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==}
-    engines: {node: '>=18'}
-    cpu: [arm64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/netbsd-x64@0.21.5:
-    resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/netbsd-x64@0.24.2:
-    resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
+  /@esbuild/netbsd-x64@0.25.2:
+    resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [netbsd]
@@ -1131,17 +629,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/netbsd-x64@0.25.0:
-    resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/openbsd-arm64@0.24.2:
-    resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
+  /@esbuild/openbsd-arm64@0.25.2:
+    resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==}
     engines: {node: '>=18'}
     cpu: [arm64]
     os: [openbsd]
@@ -1149,26 +638,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/openbsd-arm64@0.25.0:
-    resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==}
-    engines: {node: '>=18'}
-    cpu: [arm64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/openbsd-x64@0.21.5:
-    resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/openbsd-x64@0.24.2:
-    resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
+  /@esbuild/openbsd-x64@0.25.2:
+    resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [openbsd]
@@ -1176,26 +647,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/openbsd-x64@0.25.0:
-    resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/sunos-x64@0.21.5:
-    resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/sunos-x64@0.24.2:
-    resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
+  /@esbuild/sunos-x64@0.25.2:
+    resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [sunos]
@@ -1203,26 +656,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/sunos-x64@0.25.0:
-    resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/win32-arm64@0.21.5:
-    resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/win32-arm64@0.24.2:
-    resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
+  /@esbuild/win32-arm64@0.25.2:
+    resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==}
     engines: {node: '>=18'}
     cpu: [arm64]
     os: [win32]
@@ -1230,26 +665,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-arm64@0.25.0:
-    resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==}
-    engines: {node: '>=18'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/win32-ia32@0.21.5:
-    resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/win32-ia32@0.24.2:
-    resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
+  /@esbuild/win32-ia32@0.25.2:
+    resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==}
     engines: {node: '>=18'}
     cpu: [ia32]
     os: [win32]
@@ -1257,26 +674,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-ia32@0.25.0:
-    resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==}
-    engines: {node: '>=18'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/win32-x64@0.21.5:
-    resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/win32-x64@0.24.2:
-    resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
+  /@esbuild/win32-x64@0.25.2:
+    resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==}
     engines: {node: '>=18'}
     cpu: [x64]
     os: [win32]
@@ -1284,22 +683,13 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-x64@0.25.0:
-    resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==}
-    engines: {node: '>=18'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@eslint-community/eslint-utils@4.4.1(eslint@9.20.1):
-    resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==}
+  /@eslint-community/eslint-utils@4.5.1(eslint@9.24.0):
+    resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
     dependencies:
-      eslint: 9.20.1
+      eslint: 9.24.0
       eslint-visitor-keys: 3.4.3
     dev: true
 
@@ -1308,8 +698,8 @@ packages:
     engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
     dev: true
 
-  /@eslint/config-array@0.19.2:
-    resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==}
+  /@eslint/config-array@0.20.0:
+    resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     dependencies:
       '@eslint/object-schema': 2.1.6
@@ -1319,15 +709,27 @@ packages:
       - supports-color
     dev: true
 
-  /@eslint/core@0.11.0:
-    resolution: {integrity: sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==}
+  /@eslint/config-helpers@0.2.1:
+    resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    dev: true
+
+  /@eslint/core@0.12.0:
+    resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     dependencies:
       '@types/json-schema': 7.0.15
     dev: true
 
-  /@eslint/eslintrc@3.2.0:
-    resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==}
+  /@eslint/core@0.13.0:
+    resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    dependencies:
+      '@types/json-schema': 7.0.15
+    dev: true
+
+  /@eslint/eslintrc@3.3.1:
+    resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     dependencies:
       ajv: 6.12.6
@@ -1341,23 +743,21 @@ packages:
       strip-json-comments: 3.1.1
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  /@eslint/js@9.20.0:
-    resolution: {integrity: sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==}
+  /@eslint/js@9.24.0:
+    resolution: {integrity: sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    dev: true
 
   /@eslint/object-schema@2.1.6:
     resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     dev: true
 
-  /@eslint/plugin-kit@0.2.6:
-    resolution: {integrity: sha512-+0TjwR1eAUdZtvv/ir1mGX+v0tUoR3VEPB8Up0LLJC+whRW0GgBBtpbOkg/a/U4Dxa6l5a3l9AJ1aWIQVyoWJA==}
+  /@eslint/plugin-kit@0.2.8:
+    resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     dependencies:
-      '@eslint/core': 0.11.0
+      '@eslint/core': 0.13.0
       levn: 0.4.1
     dev: true
 
@@ -1389,24 +789,14 @@ packages:
     engines: {node: '>=18.18'}
     dev: true
 
-  /@iconify-json/simple-icons@1.2.25:
-    resolution: {integrity: sha512-2E1/gOCO97rF6usfhhiXxwzCb+UhdEsxW3lW1Sew+xZY0COY6dp82Z/r1rUt2fWKneWjuoGcNeJHHXQyG8mIuw==}
-    dependencies:
-      '@iconify/types': 2.0.0
-    dev: true
-
-  /@iconify/types@2.0.0:
-    resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
-    dev: true
-
-  /@inquirer/figures@1.0.10:
-    resolution: {integrity: sha512-Ey6176gZmeqZuY/W/nZiUyvmb1/qInjcpiZjXWi6nON+nxJpD1bxtSoBxNliGISae32n6OwbY+TSXPZ1CfS4bw==}
+  /@inquirer/figures@1.0.11:
+    resolution: {integrity: sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==}
     engines: {node: '>=18'}
     dev: true
 
-  /@intlify/bundle-utils@4.0.0(vue-i18n@9.14.2):
-    resolution: {integrity: sha512-klXrYT9VXyKEXsD6UY3pShg0O5MPC07n0TZ5RrSs5ry6T1eZVolIFGJi9c3qcDrh1qjJxgikRnPBmD7qGDqbjw==}
-    engines: {node: '>= 12'}
+  /@intlify/bundle-utils@8.0.0(vue-i18n@9.14.4):
+    resolution: {integrity: sha512-1B++zykRnMwQ+20SpsZI1JCnV/YJt9Oq7AGlEurzkWJOFtFAVqaGc/oV36PBRYeiKnTbY9VYfjBimr2Vt42wLQ==}
+    engines: {node: '>= 14.16'}
     peerDependencies:
       petite-vue-i18n: '*'
       vue-i18n: '*'
@@ -1416,47 +806,38 @@ packages:
       vue-i18n:
         optional: true
     dependencies:
-      '@intlify/message-compiler': 11.0.0-rc.1
-      '@intlify/shared': 11.0.0-rc.1
-      jsonc-eslint-parser: 1.4.1
-      source-map: 0.6.1
-      vue-i18n: 9.14.2(vue@3.5.13)
-      yaml-eslint-parser: 0.3.2
-    dev: true
-
-  /@intlify/core-base@9.14.2:
-    resolution: {integrity: sha512-DZyQ4Hk22sC81MP4qiCDuU+LdaYW91A6lCjq8AWPvY3+mGMzhGDfOCzvyR6YBQxtlPjFqMoFk9ylnNYRAQwXtQ==}
-    engines: {node: '>= 16'}
-    dependencies:
-      '@intlify/message-compiler': 9.14.2
-      '@intlify/shared': 9.14.2
-
-  /@intlify/message-compiler@11.0.0-rc.1:
-    resolution: {integrity: sha512-TGw2uBfuTFTegZf/BHtUQBEKxl7Q/dVGLoqRIdw8lFsp9g/53sYn5iD+0HxIzdYjbWL6BTJMXCPUHp9PxDTRPw==}
-    engines: {node: '>= 16'}
-    dependencies:
-      '@intlify/shared': 11.0.0-rc.1
+      '@intlify/message-compiler': 9.14.4
+      '@intlify/shared': 9.14.4
+      acorn: 8.14.1
+      escodegen: 2.1.0
+      estree-walker: 2.0.2
+      jsonc-eslint-parser: 2.4.0
+      mlly: 1.7.4
       source-map-js: 1.2.1
+      vue-i18n: 9.14.4(vue@3.5.13)
+      yaml-eslint-parser: 1.3.0
     dev: true
 
-  /@intlify/message-compiler@9.14.2:
-    resolution: {integrity: sha512-YsKKuV4Qv4wrLNsvgWbTf0E40uRv+Qiw1BeLQ0LAxifQuhiMe+hfTIzOMdWj/ZpnTDj4RSZtkXjJM7JDiiB5LQ==}
+  /@intlify/core-base@9.14.4:
+    resolution: {integrity: sha512-vtZCt7NqWhKEtHa3SD/322DlgP5uR9MqWxnE0y8Q0tjDs9H5Lxhss+b5wv8rmuXRoHKLESNgw9d+EN9ybBbj9g==}
     engines: {node: '>= 16'}
     dependencies:
-      '@intlify/shared': 9.14.2
+      '@intlify/message-compiler': 9.14.4
+      '@intlify/shared': 9.14.4
+
+  /@intlify/message-compiler@9.14.4:
+    resolution: {integrity: sha512-vcyCLiVRN628U38c3PbahrhbbXrckrM9zpy0KZVlDk2Z0OnGwv8uQNNXP3twwGtfLsCf4gu3ci6FMIZnPaqZsw==}
+    engines: {node: '>= 16'}
+    dependencies:
+      '@intlify/shared': 9.14.4
       source-map-js: 1.2.1
 
-  /@intlify/shared@11.0.0-rc.1:
-    resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==}
-    engines: {node: '>= 16'}
-    dev: true
-
-  /@intlify/shared@9.14.2:
-    resolution: {integrity: sha512-uRAHAxYPeF+G5DBIboKpPgC/Waecd4Jz8ihtkpJQD5ycb5PwXp0k/+hBGl5dAjwF7w+l74kz/PKA8r8OK//RUw==}
+  /@intlify/shared@9.14.4:
+    resolution: {integrity: sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==}
     engines: {node: '>= 16'}
 
-  /@intlify/unplugin-vue-i18n@0.8.2(vue-i18n@9.14.2):
-    resolution: {integrity: sha512-cRnzPqSEZQOmTD+p4pwc3RTS9HxreLqfID0keoqZDZweCy/CGRMLLTNd15S4TUf1vSBhPF03DItEFDr1F+8MDA==}
+  /@intlify/unplugin-vue-i18n@4.0.0(vue-i18n@9.14.4):
+    resolution: {integrity: sha512-q2Mhqa/mLi0tulfLFO4fMXXvEbkSZpI5yGhNNsLTNJJ41icEGUuyDe+j5zRZIKSkOJRgX6YbCyibTDJdRsukmw==}
     engines: {node: '>= 14.16'}
     peerDependencies:
       petite-vue-i18n: '*'
@@ -1470,9 +851,9 @@ packages:
       vue-i18n-bridge:
         optional: true
     dependencies:
-      '@intlify/bundle-utils': 4.0.0(vue-i18n@9.14.2)
-      '@intlify/shared': 11.0.0-rc.1
-      '@rollup/pluginutils': 4.2.1
+      '@intlify/bundle-utils': 8.0.0(vue-i18n@9.14.4)
+      '@intlify/shared': 9.14.4
+      '@rollup/pluginutils': 5.1.4
       '@vue/compiler-sfc': 3.5.13
       debug: 4.4.0(supports-color@8.1.1)
       fast-glob: 3.3.3
@@ -1480,10 +861,11 @@ packages:
       json5: 2.2.3
       pathe: 1.1.2
       picocolors: 1.1.1
-      source-map: 0.6.1
+      source-map-js: 1.2.1
       unplugin: 1.16.1
-      vue-i18n: 9.14.2(vue@3.5.13)
+      vue-i18n: 9.14.4(vue@3.5.13)
     transitivePeerDependencies:
+      - rollup
       - supports-color
     dev: true
 
@@ -1499,13 +881,6 @@ packages:
       wrap-ansi-cjs: /wrap-ansi@7.0.0
     dev: true
 
-  /@jest/schemas@29.6.3:
-    resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    dependencies:
-      '@sinclair/typebox': 0.27.8
-    dev: true
-
   /@jridgewell/gen-mapping@0.3.8:
     resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
     engines: {node: '>=6.0.0'}
@@ -1568,20 +943,17 @@ packages:
     dependencies:
       '@nodelib/fs.stat': 2.0.5
       run-parallel: 1.2.0
-    dev: true
 
   /@nodelib/fs.stat@2.0.5:
     resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
     engines: {node: '>= 8'}
-    dev: true
 
   /@nodelib/fs.walk@1.2.8:
     resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
     engines: {node: '>= 8'}
     dependencies:
       '@nodelib/fs.scandir': 2.1.5
-      fastq: 1.19.0
-    dev: true
+      fastq: 1.19.1
 
   /@one-ini/wasm@0.1.1:
     resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
@@ -1735,7 +1107,7 @@ packages:
     peerDependencies:
       pinia: '>=2.2.6'
     dependencies:
-      pinia: 2.3.1(typescript@5.7.3)(vue@3.5.13)
+      pinia: 2.3.1(typescript@5.8.3)(vue@3.5.13)
       vue-demi: 0.14.10(vue@3.5.13)
     transitivePeerDependencies:
       - '@vue/composition-api'
@@ -1770,8 +1142,12 @@ packages:
       config-chain: 1.1.13
     dev: false
 
-  /@quasar/app-vite@2.1.0(@types/node@22.13.5)(eslint@9.20.1)(pinia@2.3.1)(quasar@2.17.7)(sass@1.85.0)(typescript@5.7.3)(vue-router@4.5.0)(vue@3.5.13):
-    resolution: {integrity: sha512-BzT1UW6fe3X+akyNgkWNqeIXZSV2+RX4+IYXmYORh09VNKl+Vd8/oOcYWBqh3XWpy4CYkKC+H484dQmaQU6uHA==}
+  /@polka/url@1.0.0-next.28:
+    resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==}
+    dev: true
+
+  /@quasar/app-vite@2.2.0(@types/node@22.14.0)(eslint@9.24.0)(pinia@2.3.1)(quasar@2.18.1)(sass@1.86.3)(typescript@5.8.3)(vue-router@4.5.0)(vue@3.5.13):
+    resolution: {integrity: sha512-MvCfJrCbxUYvoGaK5jPq0h0hjO8mbxYOWngf+dIKrxhwb+1h5ERh6aVYEUuCtMIwTMEVfPkCez4DIfZIoReuDw==}
     engines: {node: ^30 || ^28 || ^26 || ^24 || ^22 || ^20 || ^18, npm: '>= 6.14.12', yarn: '>= 1.17.3'}
     hasBin: true
     peerDependencies:
@@ -1800,15 +1176,15 @@ packages:
     dependencies:
       '@quasar/render-ssr-error': 1.0.3
       '@quasar/ssl-certificate': 1.0.0
-      '@quasar/vite-plugin': 1.9.0(@vitejs/plugin-vue@5.2.1)(quasar@2.17.7)(vite@6.1.1)(vue@3.5.13)
+      '@quasar/vite-plugin': 1.9.0(@vitejs/plugin-vue@5.2.3)(quasar@2.18.1)(vite@6.2.5)(vue@3.5.13)
       '@types/chrome': 0.0.262
       '@types/compression': 1.7.5
       '@types/cordova': 11.0.3
       '@types/express': 4.17.21
-      '@vitejs/plugin-vue': 5.2.1(vite@6.2.0)(vue@3.5.13)
+      '@vitejs/plugin-vue': 5.2.3(vite@6.2.5)(vue@3.5.13)
       archiver: 7.0.1
       chokidar: 3.6.0
-      ci-info: 4.1.0
+      ci-info: 4.2.0
       compression: 1.8.0
       confbox: 0.1.8
       cross-spawn: 7.0.6
@@ -1816,8 +1192,8 @@ packages:
       dotenv: 16.4.7
       dotenv-expand: 11.0.7
       elementtree: 0.1.7
-      esbuild: 0.24.2
-      eslint: 9.20.1
+      esbuild: 0.25.2
+      eslint: 9.24.0
       express: 4.21.2
       fs-extra: 11.3.0
       html-minifier-terser: 7.2.0
@@ -1826,18 +1202,19 @@ packages:
       kolorist: 1.8.0
       lodash: 4.17.21
       minimist: 1.2.8
+      mlly: 1.7.4
       open: 10.1.0
-      pinia: 2.3.1(typescript@5.7.3)(vue@3.5.13)
-      quasar: 2.17.7
+      pinia: 2.3.1(typescript@5.8.3)(vue@3.5.13)
+      quasar: 2.18.1
       rollup-plugin-visualizer: 5.14.0
-      sass-embedded: 1.85.0
+      sass-embedded: 1.86.3
       semver: 7.7.1
       serialize-javascript: 6.0.2
       tinyglobby: 0.2.12
-      ts-essentials: 9.4.2(typescript@5.7.3)
-      typescript: 5.7.3
-      vite: 6.1.1(@types/node@22.13.5)(sass-embedded@1.85.0)(sass@1.85.0)
-      vue: 3.5.13(typescript@5.7.3)
+      ts-essentials: 9.4.2(typescript@5.8.3)
+      typescript: 5.8.3
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
+      vue: 3.5.13(typescript@5.8.3)
       vue-router: 4.5.0(vue@3.5.13)
       webpack-merge: 6.0.1
     transitivePeerDependencies:
@@ -1856,13 +1233,13 @@ packages:
       - yaml
     dev: true
 
-  /@quasar/cli@2.4.1:
-    resolution: {integrity: sha512-MrOmlqdkQhBxfPMbSrch3O7ClCAc0sLTLp9AWLzdB7uNaLbxcLP6zXN8+EPhDzFfMyxdG7jBP0FKEi7Wh+ezrQ==}
+  /@quasar/cli@2.5.0:
+    resolution: {integrity: sha512-2Vdltr47k7iwjSAYdtpu2ekPdGCmtrKU84wrGMs4taPRsfFyVyRBnxM1jruSvcmk54eA5chwof+ljmrui37AOA==}
     engines: {node: '>= 16', npm: '>= 5.6.0', yarn: '>= 1.6.0'}
     hasBin: true
     dependencies:
       '@quasar/ssl-certificate': 1.0.0
-      ci-info: 4.1.0
+      ci-info: 4.2.0
       compression: 1.8.0
       connect-history-api-fallback: 2.0.0
       cors: 2.8.5
@@ -1892,7 +1269,7 @@ packages:
       '@quasar/quasar-ui-qcalendar': 4.1.2
     dev: true
 
-  /@quasar/quasar-app-extension-testing-unit-vitest@0.4.0(@vue/test-utils@2.4.6)(quasar@2.17.7)(typescript@5.7.3)(vite@6.2.0)(vitest@0.34.6)(vue@3.5.13):
+  /@quasar/quasar-app-extension-testing-unit-vitest@0.4.0(@vitest/ui@3.1.1)(@vue/test-utils@2.4.6)(quasar@2.18.1)(typescript@5.8.3)(vite@6.2.5)(vitest@3.1.1)(vue@3.5.13):
     resolution: {integrity: sha512-eyzdUdmZiCueNS+5nedjMmzdbpCetSrtdGIwW6KplW1dTzRbLiNvYUjpBOxQGmJCgEhWy9zuswJ7MZ/bTql24Q==}
     engines: {node: '>= 12.22.1', npm: '>= 6.14.12', yarn: '>= 1.17.3'}
     peerDependencies:
@@ -1905,14 +1282,15 @@ packages:
       '@vitest/ui':
         optional: true
     dependencies:
+      '@vitest/ui': 3.1.1(vitest@3.1.1)
       '@vue/test-utils': 2.4.6
       happy-dom: 11.2.0
       lodash-es: 4.17.21
-      quasar: 2.17.7
-      vite-jsconfig-paths: 2.0.1(vite@6.2.0)
-      vite-tsconfig-paths: 4.3.2(typescript@5.7.3)(vite@6.2.0)
-      vitest: 0.34.6(sass@1.85.0)
-      vue: 3.5.13(typescript@5.7.3)
+      quasar: 2.18.1
+      vite-jsconfig-paths: 2.0.1(vite@6.2.5)
+      vite-tsconfig-paths: 4.3.2(typescript@5.8.3)(vite@6.2.5)
+      vitest: 3.1.1(@types/node@22.14.0)(@vitest/ui@3.1.1)(sass@1.86.3)
+      vue: 3.5.13(typescript@5.8.3)
     transitivePeerDependencies:
       - supports-color
       - typescript
@@ -1937,7 +1315,7 @@ packages:
       fs-extra: 11.3.0
       selfsigned: 2.4.1
 
-  /@quasar/vite-plugin@1.9.0(@vitejs/plugin-vue@5.2.1)(quasar@2.17.7)(vite@6.1.1)(vue@3.5.13):
+  /@quasar/vite-plugin@1.9.0(@vitejs/plugin-vue@5.2.3)(quasar@2.18.1)(vite@6.2.5)(vue@3.5.13):
     resolution: {integrity: sha512-r1MFtI2QZJ2g20pe75Zuv4aoi0uoK8oP0yEdzLWRoOLCbhtf2+StJpUza9TydYi3KcvCl9+4HUf3OAWVKoxDmQ==}
     engines: {node: '>=18'}
     peerDependencies:
@@ -1946,230 +1324,188 @@ packages:
       vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
       vue: ^3.0.0
     dependencies:
-      '@vitejs/plugin-vue': 5.2.1(vite@6.2.0)(vue@3.5.13)
-      quasar: 2.17.7
-      vite: 6.1.1(@types/node@22.13.5)(sass-embedded@1.85.0)(sass@1.85.0)
-      vue: 3.5.13(typescript@5.7.3)
+      '@vitejs/plugin-vue': 5.2.3(vite@6.2.5)(vue@3.5.13)
+      quasar: 2.18.1
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
+      vue: 3.5.13(typescript@5.8.3)
     dev: true
 
-  /@rollup/pluginutils@4.2.1:
-    resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
-    engines: {node: '>= 8.0.0'}
+  /@rollup/pluginutils@5.1.4:
+    resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
     dependencies:
+      '@types/estree': 1.0.7
       estree-walker: 2.0.2
-      picomatch: 2.3.1
+      picomatch: 4.0.2
     dev: true
 
-  /@rollup/rollup-android-arm-eabi@4.34.8:
-    resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==}
+  /@rollup/rollup-android-arm-eabi@4.39.0:
+    resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==}
     cpu: [arm]
     os: [android]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-android-arm64@4.34.8:
-    resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==}
+  /@rollup/rollup-android-arm64@4.39.0:
+    resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==}
     cpu: [arm64]
     os: [android]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-darwin-arm64@4.34.8:
-    resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==}
+  /@rollup/rollup-darwin-arm64@4.39.0:
+    resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==}
     cpu: [arm64]
     os: [darwin]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-darwin-x64@4.34.8:
-    resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==}
+  /@rollup/rollup-darwin-x64@4.39.0:
+    resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==}
     cpu: [x64]
     os: [darwin]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-freebsd-arm64@4.34.8:
-    resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==}
+  /@rollup/rollup-freebsd-arm64@4.39.0:
+    resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==}
     cpu: [arm64]
     os: [freebsd]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-freebsd-x64@4.34.8:
-    resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==}
+  /@rollup/rollup-freebsd-x64@4.39.0:
+    resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==}
     cpu: [x64]
     os: [freebsd]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-arm-gnueabihf@4.34.8:
-    resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==}
+  /@rollup/rollup-linux-arm-gnueabihf@4.39.0:
+    resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==}
     cpu: [arm]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-arm-musleabihf@4.34.8:
-    resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==}
+  /@rollup/rollup-linux-arm-musleabihf@4.39.0:
+    resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==}
     cpu: [arm]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-arm64-gnu@4.34.8:
-    resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==}
+  /@rollup/rollup-linux-arm64-gnu@4.39.0:
+    resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==}
     cpu: [arm64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-arm64-musl@4.34.8:
-    resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==}
+  /@rollup/rollup-linux-arm64-musl@4.39.0:
+    resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==}
     cpu: [arm64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-loongarch64-gnu@4.34.8:
-    resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==}
+  /@rollup/rollup-linux-loongarch64-gnu@4.39.0:
+    resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==}
     cpu: [loong64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-powerpc64le-gnu@4.34.8:
-    resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==}
+  /@rollup/rollup-linux-powerpc64le-gnu@4.39.0:
+    resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==}
     cpu: [ppc64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-riscv64-gnu@4.34.8:
-    resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==}
+  /@rollup/rollup-linux-riscv64-gnu@4.39.0:
+    resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==}
     cpu: [riscv64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-s390x-gnu@4.34.8:
-    resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==}
+  /@rollup/rollup-linux-riscv64-musl@4.39.0:
+    resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==}
+    cpu: [riscv64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@rollup/rollup-linux-s390x-gnu@4.39.0:
+    resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==}
     cpu: [s390x]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-x64-gnu@4.34.8:
-    resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==}
+  /@rollup/rollup-linux-x64-gnu@4.39.0:
+    resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==}
     cpu: [x64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-x64-musl@4.34.8:
-    resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==}
+  /@rollup/rollup-linux-x64-musl@4.39.0:
+    resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==}
     cpu: [x64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-win32-arm64-msvc@4.34.8:
-    resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==}
+  /@rollup/rollup-win32-arm64-msvc@4.39.0:
+    resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==}
     cpu: [arm64]
     os: [win32]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-win32-ia32-msvc@4.34.8:
-    resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==}
+  /@rollup/rollup-win32-ia32-msvc@4.39.0:
+    resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==}
     cpu: [ia32]
     os: [win32]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-win32-x64-msvc@4.34.8:
-    resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==}
+  /@rollup/rollup-win32-x64-msvc@4.39.0:
+    resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==}
     cpu: [x64]
     os: [win32]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@shikijs/core@2.5.0:
-    resolution: {integrity: sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==}
-    dependencies:
-      '@shikijs/engine-javascript': 2.5.0
-      '@shikijs/engine-oniguruma': 2.5.0
-      '@shikijs/types': 2.5.0
-      '@shikijs/vscode-textmate': 10.0.2
-      '@types/hast': 3.0.4
-      hast-util-to-html: 9.0.5
-    dev: true
-
-  /@shikijs/engine-javascript@2.5.0:
-    resolution: {integrity: sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==}
-    dependencies:
-      '@shikijs/types': 2.5.0
-      '@shikijs/vscode-textmate': 10.0.2
-      oniguruma-to-es: 3.1.1
-    dev: true
-
-  /@shikijs/engine-oniguruma@2.5.0:
-    resolution: {integrity: sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==}
-    dependencies:
-      '@shikijs/types': 2.5.0
-      '@shikijs/vscode-textmate': 10.0.2
-    dev: true
-
-  /@shikijs/langs@2.5.0:
-    resolution: {integrity: sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==}
-    dependencies:
-      '@shikijs/types': 2.5.0
-    dev: true
-
-  /@shikijs/themes@2.5.0:
-    resolution: {integrity: sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==}
-    dependencies:
-      '@shikijs/types': 2.5.0
-    dev: true
-
-  /@shikijs/transformers@2.5.0:
-    resolution: {integrity: sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==}
-    dependencies:
-      '@shikijs/core': 2.5.0
-      '@shikijs/types': 2.5.0
-    dev: true
-
-  /@shikijs/types@2.5.0:
-    resolution: {integrity: sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==}
-    dependencies:
-      '@shikijs/vscode-textmate': 10.0.2
-      '@types/hast': 3.0.4
-    dev: true
-
-  /@shikijs/vscode-textmate@10.0.2:
-    resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
-    dev: true
-
-  /@sinclair/typebox@0.27.8:
-    resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+  /@rtsao/scc@1.1.0:
+    resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
     dev: true
 
   /@sindresorhus/is@4.6.0:
@@ -2204,7 +1540,7 @@ packages:
     resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
     dependencies:
       '@types/connect': 3.4.38
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
     dev: true
 
   /@types/cacheable-request@6.0.3:
@@ -2212,20 +1548,10 @@ packages:
     dependencies:
       '@types/http-cache-semantics': 4.0.4
       '@types/keyv': 3.1.4
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
       '@types/responselike': 1.0.3
     dev: false
 
-  /@types/chai-subset@1.3.5:
-    resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==}
-    dependencies:
-      '@types/chai': 4.3.20
-    dev: true
-
-  /@types/chai@4.3.20:
-    resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==}
-    dev: true
-
   /@types/chrome@0.0.262:
     resolution: {integrity: sha512-TOoj3dqSYE13PD2fRuMQ6X6pggEvL9rRk/yOYOyWE6sfqRWxsJm4VoVm+wr9pkr4Sht/M5t7FFL4vXato8d1gA==}
     dependencies:
@@ -2242,13 +1568,13 @@ packages:
   /@types/connect@3.4.38:
     resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
     dependencies:
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
     dev: true
 
   /@types/conventional-commits-parser@5.0.1:
     resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==}
     dependencies:
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
     dev: true
 
   /@types/cordova@11.0.3:
@@ -2258,17 +1584,17 @@ packages:
   /@types/cors@2.8.17:
     resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==}
     dependencies:
-      '@types/node': 22.13.5
+      '@types/node': 22.14.0
     dev: true
 
-  /@types/estree@1.0.6:
-    resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
+  /@types/estree@1.0.7:
+    resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
     dev: true
 
   /@types/express-serve-static-core@4.19.6:
     resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==}
     dependencies:
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
       '@types/qs': 6.9.18
       '@types/range-parser': 1.2.7
       '@types/send': 0.17.4
@@ -2297,12 +1623,6 @@ packages:
     resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==}
     dev: true
 
-  /@types/hast@3.0.4:
-    resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
-    dependencies:
-      '@types/unist': 3.0.3
-    dev: true
-
   /@types/http-cache-semantics@4.0.4:
     resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
     dev: false
@@ -2314,7 +1634,7 @@ packages:
   /@types/http-proxy@1.17.16:
     resolution: {integrity: sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==}
     dependencies:
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
     dev: false
 
   /@types/json-schema@7.0.15:
@@ -2328,30 +1648,9 @@ packages:
   /@types/keyv@3.1.4:
     resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
     dependencies:
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
     dev: false
 
-  /@types/linkify-it@5.0.0:
-    resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
-    dev: true
-
-  /@types/markdown-it@14.1.2:
-    resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
-    dependencies:
-      '@types/linkify-it': 5.0.0
-      '@types/mdurl': 2.0.0
-    dev: true
-
-  /@types/mdast@4.0.4:
-    resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
-    dependencies:
-      '@types/unist': 3.0.3
-    dev: true
-
-  /@types/mdurl@2.0.0:
-    resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
-    dev: true
-
   /@types/mime@1.3.5:
     resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
     dev: true
@@ -2359,18 +1658,12 @@ packages:
   /@types/node-forge@1.3.11:
     resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
     dependencies:
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
 
-  /@types/node@22.13.4:
-    resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==}
+  /@types/node@22.14.0:
+    resolution: {integrity: sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==}
     dependencies:
-      undici-types: 6.20.0
-
-  /@types/node@22.13.5:
-    resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==}
-    dependencies:
-      undici-types: 6.20.0
-    dev: true
+      undici-types: 6.21.0
 
   /@types/qs@6.9.18:
     resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==}
@@ -2383,21 +1676,21 @@ packages:
   /@types/responselike@1.0.3:
     resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
     dependencies:
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
     dev: false
 
   /@types/send@0.17.4:
     resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
     dependencies:
       '@types/mime': 1.3.5
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
     dev: true
 
   /@types/serve-static@1.15.7:
     resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
     dependencies:
       '@types/http-errors': 2.0.4
-      '@types/node': 22.13.4
+      '@types/node': 22.14.0
       '@types/send': 0.17.4
     dev: true
 
@@ -2409,24 +1702,16 @@ packages:
     resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==}
     dev: true
 
-  /@types/unist@3.0.3:
-    resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
-    dev: true
-
-  /@types/web-bluetooth@0.0.20:
-    resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
-    dev: true
-
   /@types/yauzl@2.10.3:
     resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
     requiresBuild: true
     dependencies:
-      '@types/node': 22.13.5
+      '@types/node': 22.14.0
     dev: true
     optional: true
 
-  /@uiw/codemirror-extensions-basic-setup@4.23.8(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/view@6.36.3):
-    resolution: {integrity: sha512-XJR/8AEVcE7ufy1BhW2nCN9qSVDYEdCtYLfvhaMwl6Q3qcaYYCGE2K5QbFCy7LsdP/3uZKvc1OskuqatoOPdhQ==}
+  /@uiw/codemirror-extensions-basic-setup@4.23.10(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/view@6.36.5):
+    resolution: {integrity: sha512-zpbmSeNs3OU/f/Eyd6brFnjsBUYwv2mFjWxlAsIRSwTlW+skIT60rQHFBSfsj/5UVSxSLWVeUYczN7AyXvgTGQ==}
     peerDependencies:
       '@codemirror/autocomplete': '>=6.0.0'
       '@codemirror/commands': '>=6.0.0'
@@ -2437,16 +1722,16 @@ packages:
       '@codemirror/view': '>=6.0.0'
     dependencies:
       '@codemirror/autocomplete': 6.18.6
-      '@codemirror/commands': 6.8.0
-      '@codemirror/language': 6.10.8
-      '@codemirror/lint': 6.8.4
+      '@codemirror/commands': 6.8.1
+      '@codemirror/language': 6.11.0
+      '@codemirror/lint': 6.8.5
       '@codemirror/search': 6.5.10
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
     dev: true
 
-  /@uiw/react-codemirror@4.23.8(@babel/runtime@7.26.9)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.3)(codemirror@6.0.1)(react-dom@19.0.0)(react@19.0.0):
-    resolution: {integrity: sha512-/NA5Pj4MmXkLSlmlUm4yfEmRLntrNq5TkQKBSINn7TukXQ4fc+C6Bk0U60Qa4rkvCSgwzZdQ2exyP0t0+2GtqA==}
+  /@uiw/react-codemirror@4.23.10(@babel/runtime@7.27.0)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.5)(codemirror@6.0.1)(react-dom@19.1.0)(react@19.1.0):
+    resolution: {integrity: sha512-AbN4eVHOL4ckRuIXpZxkzEqL/1ChVA+BSdEnAKjIB68pLQvKsVoYbiFP8zkXkYc4+Fcgq5KbAjvYqdo4ewemKw==}
     peerDependencies:
       '@babel/runtime': '>=7.11.0'
       '@codemirror/state': '>=6.0.0'
@@ -2456,15 +1741,15 @@ packages:
       react: '>=16.8.0'
       react-dom: '>=16.8.0'
     dependencies:
-      '@babel/runtime': 7.26.9
-      '@codemirror/commands': 6.8.0
+      '@babel/runtime': 7.27.0
+      '@codemirror/commands': 6.8.1
       '@codemirror/state': 6.5.2
       '@codemirror/theme-one-dark': 6.1.2
-      '@codemirror/view': 6.36.3
-      '@uiw/codemirror-extensions-basic-setup': 4.23.8(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/view@6.36.3)
+      '@codemirror/view': 6.36.5
+      '@uiw/codemirror-extensions-basic-setup': 4.23.10(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/view@6.36.5)
       codemirror: 6.0.1
-      react: 19.0.0
-      react-dom: 19.0.0(react@19.0.0)
+      react: 19.1.0
+      react-dom: 19.1.0(react@19.1.0)
     transitivePeerDependencies:
       - '@codemirror/autocomplete'
       - '@codemirror/language'
@@ -2472,74 +1757,97 @@ packages:
       - '@codemirror/search'
     dev: true
 
-  /@ungap/structured-clone@1.3.0:
-    resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
-    dev: true
-
-  /@vitejs/plugin-vue@5.2.1(vite@5.4.14)(vue@3.5.13):
-    resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==}
+  /@vitejs/plugin-vue@5.2.3(vite@6.2.5)(vue@3.5.13):
+    resolution: {integrity: sha512-IYSLEQj4LgZZuoVpdSUCw3dIynTWQgPlaRP6iAvMle4My0HdYwr5g5wQAfwOeHQBmYwEkqF70nRpSilr6PoUDg==}
     engines: {node: ^18.0.0 || >=20.0.0}
     peerDependencies:
       vite: ^5.0.0 || ^6.0.0
       vue: ^3.2.25
     dependencies:
-      vite: 5.4.14(@types/node@22.13.5)(sass@1.85.0)
-      vue: 3.5.13(typescript@5.7.3)
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
+      vue: 3.5.13(typescript@5.8.3)
     dev: true
 
-  /@vitejs/plugin-vue@5.2.1(vite@6.2.0)(vue@3.5.13):
-    resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==}
-    engines: {node: ^18.0.0 || >=20.0.0}
+  /@vitest/expect@3.1.1:
+    resolution: {integrity: sha512-q/zjrW9lgynctNbwvFtQkGK9+vvHA5UzVi2V8APrp1C6fG6/MuYYkmlx4FubuqLycCeSdHD5aadWfua/Vr0EUA==}
+    dependencies:
+      '@vitest/spy': 3.1.1
+      '@vitest/utils': 3.1.1
+      chai: 5.2.0
+      tinyrainbow: 2.0.0
+    dev: true
+
+  /@vitest/mocker@3.1.1(vite@6.2.5):
+    resolution: {integrity: sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA==}
     peerDependencies:
+      msw: ^2.4.9
       vite: ^5.0.0 || ^6.0.0
-      vue: ^3.2.25
-    dependencies:
-      vite: 6.2.0(@types/node@22.13.5)(sass@1.85.0)
-      vue: 3.5.13(typescript@5.7.3)
-    dev: true
-
-  /@vitest/expect@0.34.6:
-    resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==}
-    dependencies:
-      '@vitest/spy': 0.34.6
-      '@vitest/utils': 0.34.6
-      chai: 4.5.0
-    dev: true
-
-  /@vitest/runner@0.34.6:
-    resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==}
-    dependencies:
-      '@vitest/utils': 0.34.6
-      p-limit: 4.0.0
-      pathe: 1.1.2
-    dev: true
-
-  /@vitest/snapshot@0.34.6:
-    resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==}
+    peerDependenciesMeta:
+      msw:
+        optional: true
+      vite:
+        optional: true
     dependencies:
+      '@vitest/spy': 3.1.1
+      estree-walker: 3.0.3
       magic-string: 0.30.17
-      pathe: 1.1.2
-      pretty-format: 29.7.0
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
     dev: true
 
-  /@vitest/spy@0.34.6:
-    resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==}
+  /@vitest/pretty-format@3.1.1:
+    resolution: {integrity: sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA==}
     dependencies:
-      tinyspy: 2.2.1
+      tinyrainbow: 2.0.0
     dev: true
 
-  /@vitest/utils@0.34.6:
-    resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==}
+  /@vitest/runner@3.1.1:
+    resolution: {integrity: sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA==}
     dependencies:
-      diff-sequences: 29.6.3
-      loupe: 2.3.7
-      pretty-format: 29.7.0
+      '@vitest/utils': 3.1.1
+      pathe: 2.0.3
+    dev: true
+
+  /@vitest/snapshot@3.1.1:
+    resolution: {integrity: sha512-bByMwaVWe/+1WDf9exFxWWgAixelSdiwo2p33tpqIlM14vW7PRV5ppayVXtfycqze4Qhtwag5sVhX400MLBOOw==}
+    dependencies:
+      '@vitest/pretty-format': 3.1.1
+      magic-string: 0.30.17
+      pathe: 2.0.3
+    dev: true
+
+  /@vitest/spy@3.1.1:
+    resolution: {integrity: sha512-+EmrUOOXbKzLkTDwlsc/xrwOlPDXyVk3Z6P6K4oiCndxz7YLpp/0R0UsWVOKT0IXWjjBJuSMk6D27qipaupcvQ==}
+    dependencies:
+      tinyspy: 3.0.2
+    dev: true
+
+  /@vitest/ui@3.1.1(vitest@3.1.1):
+    resolution: {integrity: sha512-2HpiRIYg3dlvAJBV9RtsVswFgUSJK4Sv7QhpxoP0eBGkYwzGIKP34PjaV00AULQi9Ovl6LGyZfsetxDWY5BQdQ==}
+    peerDependencies:
+      vitest: 3.1.1
+    dependencies:
+      '@vitest/utils': 3.1.1
+      fflate: 0.8.2
+      flatted: 3.3.3
+      pathe: 2.0.3
+      sirv: 3.0.1
+      tinyglobby: 0.2.12
+      tinyrainbow: 2.0.0
+      vitest: 3.1.1(@types/node@22.14.0)(@vitest/ui@3.1.1)(sass@1.86.3)
+    dev: true
+
+  /@vitest/utils@3.1.1:
+    resolution: {integrity: sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg==}
+    dependencies:
+      '@vitest/pretty-format': 3.1.1
+      loupe: 3.1.3
+      tinyrainbow: 2.0.0
     dev: true
 
   /@vue/compiler-core@3.5.13:
     resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
     dependencies:
-      '@babel/parser': 7.26.9
+      '@babel/parser': 7.27.0
       '@vue/shared': 3.5.13
       entities: 4.5.0
       estree-walker: 2.0.2
@@ -2554,7 +1862,7 @@ packages:
   /@vue/compiler-sfc@3.5.13:
     resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==}
     dependencies:
-      '@babel/parser': 7.26.9
+      '@babel/parser': 7.27.0
       '@vue/compiler-core': 3.5.13
       '@vue/compiler-dom': 3.5.13
       '@vue/compiler-ssr': 3.5.13
@@ -2573,30 +1881,6 @@ packages:
   /@vue/devtools-api@6.6.4:
     resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
 
-  /@vue/devtools-api@7.7.2:
-    resolution: {integrity: sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==}
-    dependencies:
-      '@vue/devtools-kit': 7.7.2
-    dev: true
-
-  /@vue/devtools-kit@7.7.2:
-    resolution: {integrity: sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==}
-    dependencies:
-      '@vue/devtools-shared': 7.7.2
-      birpc: 0.2.19
-      hookable: 5.5.3
-      mitt: 3.0.1
-      perfect-debounce: 1.0.0
-      speakingurl: 14.0.1
-      superjson: 2.2.2
-    dev: true
-
-  /@vue/devtools-shared@7.7.2:
-    resolution: {integrity: sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==}
-    dependencies:
-      rfdc: 1.4.1
-    dev: true
-
   /@vue/reactivity@3.5.13:
     resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==}
     dependencies:
@@ -2623,7 +1907,7 @@ packages:
     dependencies:
       '@vue/compiler-ssr': 3.5.13
       '@vue/shared': 3.5.13
-      vue: 3.5.13(typescript@5.7.3)
+      vue: 3.5.13(typescript@5.8.3)
 
   /@vue/shared@3.5.13:
     resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==}
@@ -2631,81 +1915,8 @@ packages:
   /@vue/test-utils@2.4.6:
     resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==}
     dependencies:
-      js-beautify: 1.15.3
-      vue-component-type-helpers: 2.2.2
-    dev: true
-
-  /@vueuse/core@12.7.0(typescript@5.7.3):
-    resolution: {integrity: sha512-jtK5B7YjZXmkGNHjviyGO4s3ZtEhbzSgrbX+s5o+Lr8i2nYqNyHuPVOeTdM1/hZ5Tkxg/KktAuAVDDiHMraMVA==}
-    dependencies:
-      '@types/web-bluetooth': 0.0.20
-      '@vueuse/metadata': 12.7.0
-      '@vueuse/shared': 12.7.0(typescript@5.7.3)
-      vue: 3.5.13(typescript@5.7.3)
-    transitivePeerDependencies:
-      - typescript
-    dev: true
-
-  /@vueuse/integrations@12.7.0(axios@1.7.9)(focus-trap@7.6.4)(typescript@5.7.3):
-    resolution: {integrity: sha512-IEq7K4bCl7mn3uKJaWtNXnd1CAPaHLUMuyj5K1/k/pVcItt0VONZW8xiGxdIovJcQjkzOHjImhX5t6gija+0/g==}
-    peerDependencies:
-      async-validator: ^4
-      axios: ^1
-      change-case: ^5
-      drauu: ^0.4
-      focus-trap: ^7
-      fuse.js: ^7
-      idb-keyval: ^6
-      jwt-decode: ^4
-      nprogress: ^0.2
-      qrcode: ^1.5
-      sortablejs: ^1
-      universal-cookie: ^7
-    peerDependenciesMeta:
-      async-validator:
-        optional: true
-      axios:
-        optional: true
-      change-case:
-        optional: true
-      drauu:
-        optional: true
-      focus-trap:
-        optional: true
-      fuse.js:
-        optional: true
-      idb-keyval:
-        optional: true
-      jwt-decode:
-        optional: true
-      nprogress:
-        optional: true
-      qrcode:
-        optional: true
-      sortablejs:
-        optional: true
-      universal-cookie:
-        optional: true
-    dependencies:
-      '@vueuse/core': 12.7.0(typescript@5.7.3)
-      '@vueuse/shared': 12.7.0(typescript@5.7.3)
-      axios: 1.7.9
-      focus-trap: 7.6.4
-      vue: 3.5.13(typescript@5.7.3)
-    transitivePeerDependencies:
-      - typescript
-    dev: true
-
-  /@vueuse/metadata@12.7.0:
-    resolution: {integrity: sha512-4VvTH9mrjXqFN5LYa5YfqHVRI6j7R00Vy4995Rw7PQxyCL3z0Lli86iN4UemWqixxEvYfRjG+hF9wL8oLOn+3g==}
-    dev: true
-
-  /@vueuse/shared@12.7.0(typescript@5.7.3):
-    resolution: {integrity: sha512-coLlUw2HHKsm7rPN6WqHJQr18WymN4wkA/3ThFaJ4v4gWGWAQQGK+MJxLuJTBs4mojQiazlVWAKNJNpUWGRkNw==}
-    dependencies:
-      vue: 3.5.13(typescript@5.7.3)
-    transitivePeerDependencies:
-      - typescript
+      js-beautify: 1.15.4
+      vue-component-type-helpers: 2.2.8
     dev: true
 
   /JSONStream@1.3.5:
@@ -2716,9 +1927,9 @@ packages:
       through: 2.3.8
     dev: true
 
-  /abbrev@3.0.0:
-    resolution: {integrity: sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==}
-    engines: {node: ^18.17.0 || >=20.5.0}
+  /abbrev@2.0.0:
+    resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dev: true
 
   /abort-controller@3.0.0:
@@ -2735,40 +1946,17 @@ packages:
       mime-types: 2.1.35
       negotiator: 0.6.3
 
-  /acorn-jsx@5.3.2(acorn@7.4.1):
+  /acorn-jsx@5.3.2(acorn@8.14.1):
     resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
     peerDependencies:
       acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
     dependencies:
-      acorn: 7.4.1
-    dev: true
+      acorn: 8.14.1
 
-  /acorn-jsx@5.3.2(acorn@8.14.0):
-    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
-    peerDependencies:
-      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
-    dependencies:
-      acorn: 8.14.0
-    dev: true
-
-  /acorn-walk@8.3.4:
-    resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
-    engines: {node: '>=0.4.0'}
-    dependencies:
-      acorn: 8.14.0
-    dev: true
-
-  /acorn@7.4.1:
-    resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
+  /acorn@8.14.1:
+    resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
     engines: {node: '>=0.4.0'}
     hasBin: true
-    dev: true
-
-  /acorn@8.14.0:
-    resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
-    engines: {node: '>=0.4.0'}
-    hasBin: true
-    dev: true
 
   /aggregate-error@3.1.0:
     resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
@@ -2785,7 +1973,6 @@ packages:
       fast-json-stable-stringify: 2.1.0
       json-schema-traverse: 0.4.1
       uri-js: 4.4.1
-    dev: true
 
   /ajv@8.17.1:
     resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
@@ -2796,25 +1983,6 @@ packages:
       require-from-string: 2.0.2
     dev: true
 
-  /algoliasearch@5.20.3:
-    resolution: {integrity: sha512-iNC6BGvipaalFfDfDnXUje8GUlW5asj0cTMsZJwO/0rhsyLx1L7GZFAY8wW+eQ6AM4Yge2p5GSE5hrBlfSD90Q==}
-    engines: {node: '>= 14.0.0'}
-    dependencies:
-      '@algolia/client-abtesting': 5.20.3
-      '@algolia/client-analytics': 5.20.3
-      '@algolia/client-common': 5.20.3
-      '@algolia/client-insights': 5.20.3
-      '@algolia/client-personalization': 5.20.3
-      '@algolia/client-query-suggestions': 5.20.3
-      '@algolia/client-search': 5.20.3
-      '@algolia/ingestion': 1.20.3
-      '@algolia/monitoring': 1.20.3
-      '@algolia/recommend': 5.20.3
-      '@algolia/requester-browser-xhr': 5.20.3
-      '@algolia/requester-fetch': 5.20.3
-      '@algolia/requester-node-http': 5.20.3
-    dev: true
-
   /ansi-align@3.0.1:
     resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
     dependencies:
@@ -2848,11 +2016,6 @@ packages:
       color-convert: 2.0.1
     dev: true
 
-  /ansi-styles@5.2.0:
-    resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
-    engines: {node: '>=10'}
-    dev: true
-
   /ansi-styles@6.2.1:
     resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
     engines: {node: '>=12'}
@@ -2901,6 +2064,13 @@ packages:
 
   /argparse@2.0.1:
     resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+  /array-buffer-byte-length@1.0.2:
+    resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      is-array-buffer: 3.0.5
     dev: true
 
   /array-flatten@1.1.1:
@@ -2910,6 +2080,64 @@ packages:
     resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
     dev: true
 
+  /array-includes@3.1.8:
+    resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-object-atoms: 1.1.1
+      get-intrinsic: 1.3.0
+      is-string: 1.1.1
+    dev: true
+
+  /array.prototype.findlastindex@1.2.6:
+    resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-errors: 1.3.0
+      es-object-atoms: 1.1.1
+      es-shim-unscopables: 1.1.0
+    dev: true
+
+  /array.prototype.flat@1.3.3:
+    resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-shim-unscopables: 1.1.0
+    dev: true
+
+  /array.prototype.flatmap@1.3.3:
+    resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-shim-unscopables: 1.1.0
+    dev: true
+
+  /arraybuffer.prototype.slice@1.0.4:
+    resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      array-buffer-byte-length: 1.0.2
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      is-array-buffer: 3.0.5
+    dev: true
+
   /asn1@0.2.6:
     resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
     dependencies:
@@ -2921,8 +2149,9 @@ packages:
     engines: {node: '>=0.8'}
     dev: true
 
-  /assertion-error@1.1.0:
-    resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+  /assertion-error@2.0.1:
+    resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+    engines: {node: '>=12'}
     dev: true
 
   /astral-regex@2.0.0:
@@ -2930,6 +2159,11 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /async-function@1.0.0:
+    resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
   /async@3.2.6:
     resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
     dev: true
@@ -2942,15 +2176,15 @@ packages:
     engines: {node: '>= 4.0.0'}
     dev: true
 
-  /autoprefixer@10.4.20(postcss@8.5.3):
-    resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
+  /autoprefixer@10.4.21(postcss@8.5.3):
+    resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
     engines: {node: ^10 || ^12 || >=14}
     hasBin: true
     peerDependencies:
       postcss: ^8.1.0
     dependencies:
       browserslist: 4.24.4
-      caniuse-lite: 1.0.30001700
+      caniuse-lite: 1.0.30001712
       fraction.js: 4.3.7
       normalize-range: 0.1.2
       picocolors: 1.1.1
@@ -2958,6 +2192,13 @@ packages:
       postcss-value-parser: 4.2.0
     dev: true
 
+  /available-typed-arrays@1.0.7:
+    resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      possible-typed-array-names: 1.1.0
+    dev: true
+
   /aws-sign2@0.7.0:
     resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
     dev: true
@@ -2966,14 +2207,15 @@ packages:
     resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==}
     dev: true
 
-  /axios@1.7.9:
-    resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
+  /axios@1.8.4:
+    resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
     dependencies:
       follow-redirects: 1.15.9
       form-data: 4.0.2
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
       - debug
+    dev: false
 
   /b4a@1.6.7:
     resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==}
@@ -3013,10 +2255,6 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
-  /birpc@0.2.19:
-    resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==}
-    dev: true
-
   /bl@4.1.0:
     resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
     dependencies:
@@ -3104,10 +2342,10 @@ packages:
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
     hasBin: true
     dependencies:
-      caniuse-lite: 1.0.30001700
-      electron-to-chromium: 1.5.102
+      caniuse-lite: 1.0.30001712
+      electron-to-chromium: 1.5.132
       node-releases: 2.0.19
-      update-browserslist-db: 1.1.2(browserslist@4.24.4)
+      update-browserslist-db: 1.1.3(browserslist@4.24.4)
     dev: true
 
   /buffer-builder@0.2.0:
@@ -3209,17 +2447,26 @@ packages:
       es-errors: 1.3.0
       function-bind: 1.1.2
 
-  /call-bound@1.0.3:
-    resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==}
+  /call-bind@1.0.8:
+    resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
     engines: {node: '>= 0.4'}
     dependencies:
       call-bind-apply-helpers: 1.0.2
-      get-intrinsic: 1.2.7
+      es-define-property: 1.0.1
+      get-intrinsic: 1.3.0
+      set-function-length: 1.2.2
+    dev: true
+
+  /call-bound@1.0.4:
+    resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      get-intrinsic: 1.3.0
 
   /callsites@3.1.0:
     resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
     engines: {node: '>=6'}
-    dev: true
 
   /camel-case@4.1.2:
     resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
@@ -3243,29 +2490,23 @@ packages:
     engines: {node: '>=14.16'}
     dev: false
 
-  /caniuse-lite@1.0.30001700:
-    resolution: {integrity: sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==}
+  /caniuse-lite@1.0.30001712:
+    resolution: {integrity: sha512-MBqPpGYYdQ7/hfKiet9SCI+nmN5/hp4ZzveOJubl5DTAMa5oggjAuoi0Z4onBpKPFI2ePGnQuQIzF3VxDjDJig==}
     dev: true
 
   /caseless@0.12.0:
     resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
     dev: true
 
-  /ccount@2.0.1:
-    resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
-    dev: true
-
-  /chai@4.5.0:
-    resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==}
-    engines: {node: '>=4'}
+  /chai@5.2.0:
+    resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
+    engines: {node: '>=12'}
     dependencies:
-      assertion-error: 1.1.0
-      check-error: 1.0.3
-      deep-eql: 4.1.4
-      get-func-name: 2.0.2
-      loupe: 2.3.7
-      pathval: 1.1.1
-      type-detect: 4.1.0
+      assertion-error: 2.0.1
+      check-error: 2.1.1
+      deep-eql: 5.0.2
+      loupe: 3.1.3
+      pathval: 2.0.0
     dev: true
 
   /chalk@4.1.2:
@@ -3280,22 +2521,13 @@ packages:
     resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
     engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
 
-  /character-entities-html4@2.1.0:
-    resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
-    dev: true
-
-  /character-entities-legacy@3.0.0:
-    resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
-    dev: true
-
   /chardet@0.7.0:
     resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
     dev: true
 
-  /check-error@1.0.3:
-    resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
-    dependencies:
-      get-func-name: 2.0.2
+  /check-error@2.1.1:
+    resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+    engines: {node: '>= 16'}
     dev: true
 
   /check-more-types@2.24.0:
@@ -3347,8 +2579,8 @@ packages:
     engines: {node: '>=8'}
     dev: false
 
-  /ci-info@4.1.0:
-    resolution: {integrity: sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==}
+  /ci-info@4.2.0:
+    resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==}
     engines: {node: '>=8'}
 
   /clean-css@5.3.3:
@@ -3443,12 +2675,12 @@ packages:
     resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
     dependencies:
       '@codemirror/autocomplete': 6.18.6
-      '@codemirror/commands': 6.8.0
-      '@codemirror/language': 6.10.8
-      '@codemirror/lint': 6.8.4
+      '@codemirror/commands': 6.8.1
+      '@codemirror/language': 6.11.0
+      '@codemirror/lint': 6.8.5
       '@codemirror/search': 6.5.10
       '@codemirror/state': 6.5.2
-      '@codemirror/view': 6.36.3
+      '@codemirror/view': 6.36.5
     dev: true
 
   /color-convert@2.0.1:
@@ -3476,10 +2708,6 @@ packages:
     dependencies:
       delayed-stream: 1.0.0
 
-  /comma-separated-tokens@2.0.3:
-    resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
-    dev: true
-
   /commander@10.0.1:
     resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
     engines: {node: '>=14'}
@@ -3526,7 +2754,7 @@ packages:
     resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
     engines: {node: '>= 0.6'}
     dependencies:
-      mime-db: 1.53.0
+      mime-db: 1.54.0
 
   /compression@1.8.0:
     resolution: {integrity: sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==}
@@ -3633,13 +2861,6 @@ packages:
     engines: {node: '>= 0.6'}
     dev: true
 
-  /copy-anything@3.0.5:
-    resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
-    engines: {node: '>=12.13'}
-    dependencies:
-      is-what: 4.1.16
-    dev: true
-
   /core-util-is@1.0.2:
     resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
     dev: true
@@ -3654,7 +2875,7 @@ packages:
       object-assign: 4.1.1
       vary: 1.1.2
 
-  /cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.5)(cosmiconfig@9.0.0)(typescript@5.7.3):
+  /cosmiconfig-typescript-loader@6.1.0(@types/node@22.14.0)(cosmiconfig@9.0.0)(typescript@5.8.3):
     resolution: {integrity: sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==}
     engines: {node: '>=v18'}
     peerDependencies:
@@ -3662,13 +2883,13 @@ packages:
       cosmiconfig: '>=9'
       typescript: '>=5'
     dependencies:
-      '@types/node': 22.13.5
-      cosmiconfig: 9.0.0(typescript@5.7.3)
+      '@types/node': 22.14.0
+      cosmiconfig: 9.0.0(typescript@5.8.3)
       jiti: 2.4.2
-      typescript: 5.7.3
+      typescript: 5.8.3
     dev: true
 
-  /cosmiconfig@9.0.0(typescript@5.7.3):
+  /cosmiconfig@9.0.0(typescript@5.8.3):
     resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
     engines: {node: '>=14'}
     peerDependencies:
@@ -3681,7 +2902,7 @@ packages:
       import-fresh: 3.3.1
       js-yaml: 4.1.0
       parse-json: 5.2.0
-      typescript: 5.7.3
+      typescript: 5.8.3
     dev: true
 
   /crc-32@1.2.2:
@@ -3734,7 +2955,7 @@ packages:
   /csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
-  /cypress-mochawesome-reporter@3.8.2(cypress@14.1.0)(mocha@11.1.0):
+  /cypress-mochawesome-reporter@3.8.2(cypress@14.2.1)(mocha@11.1.0):
     resolution: {integrity: sha512-oJZkNzhNmN9ZD+LmZyFuPb8aWaIijyHyqYh52YOBvR6B6ckfJNCHP3A98a+/nG0H4t46CKTNwo+wNpMa4d2kjA==}
     engines: {node: '>=14'}
     hasBin: true
@@ -3742,7 +2963,7 @@ packages:
       cypress: '>=6.2.0'
     dependencies:
       commander: 10.0.1
-      cypress: 14.1.0
+      cypress: 14.2.1
       fs-extra: 10.1.0
       mochawesome: 7.1.3(mocha@11.1.0)
       mochawesome-merge: 4.4.1
@@ -3751,13 +2972,13 @@ packages:
       - mocha
     dev: true
 
-  /cypress@14.1.0:
-    resolution: {integrity: sha512-pPPj8Uu9NwjaaiXAEcjYZZmgsq6v9Zs1Nw6a+zRF+ANgYSNhH4S32SjFRsvMcuOHR/8dp4GBJhBPqIPSs+TxaA==}
+  /cypress@14.2.1:
+    resolution: {integrity: sha512-5xd0E7fUp0pjjib1D7ljkmCwFDgMkWuW06jWiz8dKrI7MNRrDo0C65i4Sh+oZ9YHjMHZRJBR0XZk1DfekOhOUw==}
     engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
     hasBin: true
     requiresBuild: true
     dependencies:
-      '@cypress/request': 3.0.7
+      '@cypress/request': 3.0.8
       '@cypress/xvfb': 1.2.4(supports-color@8.1.1)
       '@types/sinonjs__fake-timers': 8.1.1
       '@types/sizzle': 2.3.9
@@ -3768,7 +2989,7 @@ packages:
       cachedir: 2.4.0
       chalk: 4.1.2
       check-more-types: 2.24.0
-      ci-info: 4.1.0
+      ci-info: 4.2.0
       cli-cursor: 3.1.0
       cli-table3: 0.6.5
       commander: 6.2.1
@@ -3814,6 +3035,33 @@ packages:
       assert-plus: 1.0.0
     dev: true
 
+  /data-view-buffer@1.0.2:
+    resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      is-data-view: 1.0.2
+    dev: true
+
+  /data-view-byte-length@1.0.2:
+    resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      is-data-view: 1.0.2
+    dev: true
+
+  /data-view-byte-offset@1.0.1:
+    resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      is-data-view: 1.0.2
+    dev: true
+
   /dateformat@4.6.3:
     resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
     dev: true
@@ -3900,11 +3148,9 @@ packages:
       mimic-response: 3.1.0
     dev: false
 
-  /deep-eql@4.1.4:
-    resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
+  /deep-eql@5.0.2:
+    resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
     engines: {node: '>=6'}
-    dependencies:
-      type-detect: 4.1.0
     dev: true
 
   /deep-extend@0.6.0:
@@ -3958,6 +3204,15 @@ packages:
     engines: {node: '>=10'}
     dev: false
 
+  /define-data-property@1.1.4:
+    resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-define-property: 1.0.1
+      es-errors: 1.3.0
+      gopd: 1.2.0
+    dev: true
+
   /define-lazy-prop@2.0.0:
     resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
     engines: {node: '>=8'}
@@ -3967,6 +3222,15 @@ packages:
     resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
     engines: {node: '>=12'}
 
+  /define-properties@1.2.1:
+    resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-data-property: 1.1.4
+      has-property-descriptors: 1.0.2
+      object-keys: 1.1.1
+    dev: true
+
   /delayed-stream@1.0.0:
     resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
     engines: {node: '>=0.4.0'}
@@ -3975,11 +3239,6 @@ packages:
     resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
     engines: {node: '>= 0.8'}
 
-  /dequal@2.0.3:
-    resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
-    engines: {node: '>=6'}
-    dev: true
-
   /destroy@1.2.0:
     resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -3997,22 +3256,18 @@ packages:
     dev: true
     optional: true
 
-  /devlop@1.1.0:
-    resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
-    dependencies:
-      dequal: 2.0.3
-    dev: true
-
-  /diff-sequences@29.6.3:
-    resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    dev: true
-
   /diff@5.2.0:
     resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
     engines: {node: '>=0.3.1'}
     dev: true
 
+  /doctrine@2.1.0:
+    resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      esutils: 2.0.3
+    dev: true
+
   /dot-case@3.0.4:
     resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
     dependencies:
@@ -4038,7 +3293,7 @@ packages:
     resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==}
     engines: {node: '>=18'}
     dependencies:
-      type-fest: 4.35.0
+      type-fest: 4.39.1
     dev: true
 
   /dotenv-expand@11.0.7:
@@ -4085,8 +3340,8 @@ packages:
   /ee-first@1.1.1:
     resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
 
-  /electron-to-chromium@1.5.102:
-    resolution: {integrity: sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==}
+  /electron-to-chromium@1.5.132:
+    resolution: {integrity: sha512-QgX9EBvWGmvSRa74zqfnG7+Eno0Ak0vftBll0Pt2/z5b3bEGYL6OUXLgKPtvx73dn3dvwrlyVkjPKRRlhLYTEg==}
     dev: true
 
   /elementtree@0.1.7:
@@ -4096,10 +3351,6 @@ packages:
       sax: 1.1.4
     dev: true
 
-  /emoji-regex-xs@1.0.0:
-    resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
-    dev: true
-
   /emoji-regex@8.0.0:
     resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
 
@@ -4129,7 +3380,7 @@ packages:
     engines: {node: '>=10.2.0'}
     dependencies:
       '@types/cors': 2.8.17
-      '@types/node': 22.13.5
+      '@types/node': 22.14.0
       accepts: 1.3.8
       base64id: 2.0.0
       cookie: 0.7.2
@@ -4166,6 +3417,63 @@ packages:
       is-arrayish: 0.2.1
     dev: true
 
+  /es-abstract@1.23.9:
+    resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      array-buffer-byte-length: 1.0.2
+      arraybuffer.prototype.slice: 1.0.4
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      data-view-buffer: 1.0.2
+      data-view-byte-length: 1.0.2
+      data-view-byte-offset: 1.0.1
+      es-define-property: 1.0.1
+      es-errors: 1.3.0
+      es-object-atoms: 1.1.1
+      es-set-tostringtag: 2.1.0
+      es-to-primitive: 1.3.0
+      function.prototype.name: 1.1.8
+      get-intrinsic: 1.3.0
+      get-proto: 1.0.1
+      get-symbol-description: 1.1.0
+      globalthis: 1.0.4
+      gopd: 1.2.0
+      has-property-descriptors: 1.0.2
+      has-proto: 1.2.0
+      has-symbols: 1.1.0
+      hasown: 2.0.2
+      internal-slot: 1.1.0
+      is-array-buffer: 3.0.5
+      is-callable: 1.2.7
+      is-data-view: 1.0.2
+      is-regex: 1.2.1
+      is-shared-array-buffer: 1.0.4
+      is-string: 1.1.1
+      is-typed-array: 1.1.15
+      is-weakref: 1.1.1
+      math-intrinsics: 1.1.0
+      object-inspect: 1.13.4
+      object-keys: 1.1.1
+      object.assign: 4.1.7
+      own-keys: 1.0.1
+      regexp.prototype.flags: 1.5.4
+      safe-array-concat: 1.1.3
+      safe-push-apply: 1.0.0
+      safe-regex-test: 1.1.0
+      set-proto: 1.0.0
+      string.prototype.trim: 1.2.10
+      string.prototype.trimend: 1.0.9
+      string.prototype.trimstart: 1.0.8
+      typed-array-buffer: 1.0.3
+      typed-array-byte-length: 1.0.3
+      typed-array-byte-offset: 1.0.4
+      typed-array-length: 1.0.7
+      unbox-primitive: 1.1.0
+      which-typed-array: 1.1.19
+    dev: true
+
   /es-define-property@1.0.1:
     resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
     engines: {node: '>= 0.4'}
@@ -4174,6 +3482,9 @@ packages:
     resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
     engines: {node: '>= 0.4'}
 
+  /es-module-lexer@1.6.0:
+    resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
+
   /es-object-atoms@1.1.1:
     resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
     engines: {node: '>= 0.4'}
@@ -4185,105 +3496,57 @@ packages:
     engines: {node: '>= 0.4'}
     dependencies:
       es-errors: 1.3.0
-      get-intrinsic: 1.2.7
+      get-intrinsic: 1.3.0
       has-tostringtag: 1.0.2
       hasown: 2.0.2
 
-  /esbuild@0.21.5:
-    resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
-    optionalDependencies:
-      '@esbuild/aix-ppc64': 0.21.5
-      '@esbuild/android-arm': 0.21.5
-      '@esbuild/android-arm64': 0.21.5
-      '@esbuild/android-x64': 0.21.5
-      '@esbuild/darwin-arm64': 0.21.5
-      '@esbuild/darwin-x64': 0.21.5
-      '@esbuild/freebsd-arm64': 0.21.5
-      '@esbuild/freebsd-x64': 0.21.5
-      '@esbuild/linux-arm': 0.21.5
-      '@esbuild/linux-arm64': 0.21.5
-      '@esbuild/linux-ia32': 0.21.5
-      '@esbuild/linux-loong64': 0.21.5
-      '@esbuild/linux-mips64el': 0.21.5
-      '@esbuild/linux-ppc64': 0.21.5
-      '@esbuild/linux-riscv64': 0.21.5
-      '@esbuild/linux-s390x': 0.21.5
-      '@esbuild/linux-x64': 0.21.5
-      '@esbuild/netbsd-x64': 0.21.5
-      '@esbuild/openbsd-x64': 0.21.5
-      '@esbuild/sunos-x64': 0.21.5
-      '@esbuild/win32-arm64': 0.21.5
-      '@esbuild/win32-ia32': 0.21.5
-      '@esbuild/win32-x64': 0.21.5
+  /es-shim-unscopables@1.1.0:
+    resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      hasown: 2.0.2
     dev: true
 
-  /esbuild@0.24.2:
-    resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
+  /es-to-primitive@1.3.0:
+    resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      is-callable: 1.2.7
+      is-date-object: 1.1.0
+      is-symbol: 1.1.1
+    dev: true
+
+  /esbuild@0.25.2:
+    resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==}
     engines: {node: '>=18'}
     hasBin: true
     requiresBuild: true
     optionalDependencies:
-      '@esbuild/aix-ppc64': 0.24.2
-      '@esbuild/android-arm': 0.24.2
-      '@esbuild/android-arm64': 0.24.2
-      '@esbuild/android-x64': 0.24.2
-      '@esbuild/darwin-arm64': 0.24.2
-      '@esbuild/darwin-x64': 0.24.2
-      '@esbuild/freebsd-arm64': 0.24.2
-      '@esbuild/freebsd-x64': 0.24.2
-      '@esbuild/linux-arm': 0.24.2
-      '@esbuild/linux-arm64': 0.24.2
-      '@esbuild/linux-ia32': 0.24.2
-      '@esbuild/linux-loong64': 0.24.2
-      '@esbuild/linux-mips64el': 0.24.2
-      '@esbuild/linux-ppc64': 0.24.2
-      '@esbuild/linux-riscv64': 0.24.2
-      '@esbuild/linux-s390x': 0.24.2
-      '@esbuild/linux-x64': 0.24.2
-      '@esbuild/netbsd-arm64': 0.24.2
-      '@esbuild/netbsd-x64': 0.24.2
-      '@esbuild/openbsd-arm64': 0.24.2
-      '@esbuild/openbsd-x64': 0.24.2
-      '@esbuild/sunos-x64': 0.24.2
-      '@esbuild/win32-arm64': 0.24.2
-      '@esbuild/win32-ia32': 0.24.2
-      '@esbuild/win32-x64': 0.24.2
-    dev: true
-
-  /esbuild@0.25.0:
-    resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==}
-    engines: {node: '>=18'}
-    hasBin: true
-    requiresBuild: true
-    optionalDependencies:
-      '@esbuild/aix-ppc64': 0.25.0
-      '@esbuild/android-arm': 0.25.0
-      '@esbuild/android-arm64': 0.25.0
-      '@esbuild/android-x64': 0.25.0
-      '@esbuild/darwin-arm64': 0.25.0
-      '@esbuild/darwin-x64': 0.25.0
-      '@esbuild/freebsd-arm64': 0.25.0
-      '@esbuild/freebsd-x64': 0.25.0
-      '@esbuild/linux-arm': 0.25.0
-      '@esbuild/linux-arm64': 0.25.0
-      '@esbuild/linux-ia32': 0.25.0
-      '@esbuild/linux-loong64': 0.25.0
-      '@esbuild/linux-mips64el': 0.25.0
-      '@esbuild/linux-ppc64': 0.25.0
-      '@esbuild/linux-riscv64': 0.25.0
-      '@esbuild/linux-s390x': 0.25.0
-      '@esbuild/linux-x64': 0.25.0
-      '@esbuild/netbsd-arm64': 0.25.0
-      '@esbuild/netbsd-x64': 0.25.0
-      '@esbuild/openbsd-arm64': 0.25.0
-      '@esbuild/openbsd-x64': 0.25.0
-      '@esbuild/sunos-x64': 0.25.0
-      '@esbuild/win32-arm64': 0.25.0
-      '@esbuild/win32-ia32': 0.25.0
-      '@esbuild/win32-x64': 0.25.0
+      '@esbuild/aix-ppc64': 0.25.2
+      '@esbuild/android-arm': 0.25.2
+      '@esbuild/android-arm64': 0.25.2
+      '@esbuild/android-x64': 0.25.2
+      '@esbuild/darwin-arm64': 0.25.2
+      '@esbuild/darwin-x64': 0.25.2
+      '@esbuild/freebsd-arm64': 0.25.2
+      '@esbuild/freebsd-x64': 0.25.2
+      '@esbuild/linux-arm': 0.25.2
+      '@esbuild/linux-arm64': 0.25.2
+      '@esbuild/linux-ia32': 0.25.2
+      '@esbuild/linux-loong64': 0.25.2
+      '@esbuild/linux-mips64el': 0.25.2
+      '@esbuild/linux-ppc64': 0.25.2
+      '@esbuild/linux-riscv64': 0.25.2
+      '@esbuild/linux-s390x': 0.25.2
+      '@esbuild/linux-x64': 0.25.2
+      '@esbuild/netbsd-arm64': 0.25.2
+      '@esbuild/netbsd-x64': 0.25.2
+      '@esbuild/openbsd-arm64': 0.25.2
+      '@esbuild/openbsd-x64': 0.25.2
+      '@esbuild/sunos-x64': 0.25.2
+      '@esbuild/win32-arm64': 0.25.2
+      '@esbuild/win32-ia32': 0.25.2
+      '@esbuild/win32-x64': 0.25.2
     dev: true
 
   /escalade@3.2.0:
@@ -4309,38 +3572,133 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
-  /eslint-config-prettier@10.0.1(eslint@9.20.1):
-    resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==}
+  /escodegen@2.1.0:
+    resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
+    engines: {node: '>=6.0'}
+    hasBin: true
+    dependencies:
+      esprima: 4.0.1
+      estraverse: 5.3.0
+      esutils: 2.0.3
+    optionalDependencies:
+      source-map: 0.6.1
+    dev: true
+
+  /eslint-config-prettier@10.1.1(eslint@9.24.0):
+    resolution: {integrity: sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==}
     hasBin: true
     peerDependencies:
       eslint: '>=7.0.0'
     dependencies:
-      eslint: 9.20.1
+      eslint: 9.24.0
     dev: true
 
-  /eslint-plugin-cypress@4.1.0(eslint@9.20.1):
-    resolution: {integrity: sha512-JhqkMY02mw74USwK9OFhectx3YSj6Co1NgWBxlGdKvlqiAp9vdEuQqt33DKGQFvvGS/NWtduuhWXWNnU29xDSg==}
+  /eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0):
+    resolution: {integrity: sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==}
+    engines: {node: '>= 4'}
+    peerDependencies:
+      eslint-plugin-import: '>=1.4.0'
+    dependencies:
+      eslint-plugin-import: 2.31.0(eslint@9.24.0)
+    dev: true
+
+  /eslint-import-resolver-node@0.3.9:
+    resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+    dependencies:
+      debug: 3.2.7(supports-color@8.1.1)
+      is-core-module: 2.16.1
+      resolve: 1.22.10
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /eslint-module-utils@2.12.0(eslint-import-resolver-node@0.3.9)(eslint@9.24.0):
+    resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint:
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
+    dependencies:
+      debug: 3.2.7(supports-color@8.1.1)
+      eslint: 9.24.0
+      eslint-import-resolver-node: 0.3.9
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /eslint-plugin-cypress@4.2.0(eslint@9.24.0):
+    resolution: {integrity: sha512-v5cyt0VYb1tEEODBJSE44PocYOwQsckyexJhCs7LtdD3FGO6D2GjnZB2s2Sts4RcxdxECTWX01nObOZRs26bQw==}
     peerDependencies:
       eslint: '>=9'
     dependencies:
-      eslint: 9.20.1
+      eslint: 9.24.0
       globals: 15.15.0
     dev: true
 
-  /eslint-plugin-vue@9.32.0(eslint@9.20.1):
-    resolution: {integrity: sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==}
+  /eslint-plugin-import@2.31.0(eslint@9.24.0):
+    resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+    dependencies:
+      '@rtsao/scc': 1.1.0
+      array-includes: 3.1.8
+      array.prototype.findlastindex: 1.2.6
+      array.prototype.flat: 1.3.3
+      array.prototype.flatmap: 1.3.3
+      debug: 3.2.7(supports-color@8.1.1)
+      doctrine: 2.1.0
+      eslint: 9.24.0
+      eslint-import-resolver-node: 0.3.9
+      eslint-module-utils: 2.12.0(eslint-import-resolver-node@0.3.9)(eslint@9.24.0)
+      hasown: 2.0.2
+      is-core-module: 2.16.1
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.fromentries: 2.0.8
+      object.groupby: 1.0.3
+      object.values: 1.2.1
+      semver: 6.3.1
+      string.prototype.trimend: 1.0.9
+      tsconfig-paths: 3.15.0
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+    dev: true
+
+  /eslint-plugin-vue@9.33.0(eslint@9.24.0):
+    resolution: {integrity: sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==}
     engines: {node: ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1)
-      eslint: 9.20.1
+      '@eslint-community/eslint-utils': 4.5.1(eslint@9.24.0)
+      eslint: 9.24.0
       globals: 13.24.0
       natural-compare: 1.4.0
       nth-check: 2.1.1
       postcss-selector-parser: 6.1.2
       semver: 7.7.1
-      vue-eslint-parser: 9.4.3(eslint@9.20.1)
+      vue-eslint-parser: 9.4.3(eslint@9.24.0)
       xml-name-validator: 4.0.0
     transitivePeerDependencies:
       - supports-color
@@ -4354,26 +3712,14 @@ packages:
       estraverse: 5.3.0
     dev: true
 
-  /eslint-scope@8.2.0:
-    resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==}
+  /eslint-scope@8.3.0:
+    resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     dependencies:
       esrecurse: 4.3.0
       estraverse: 5.3.0
     dev: true
 
-  /eslint-utils@2.1.0:
-    resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==}
-    engines: {node: '>=6'}
-    dependencies:
-      eslint-visitor-keys: 1.3.0
-    dev: true
-
-  /eslint-visitor-keys@1.3.0:
-    resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==}
-    engines: {node: '>=4'}
-    dev: true
-
   /eslint-visitor-keys@3.4.3:
     resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4382,10 +3728,9 @@ packages:
   /eslint-visitor-keys@4.2.0:
     resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-    dev: true
 
-  /eslint@9.20.1:
-    resolution: {integrity: sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==}
+  /eslint@9.24.0:
+    resolution: {integrity: sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     hasBin: true
     peerDependencies:
@@ -4394,24 +3739,25 @@ packages:
       jiti:
         optional: true
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1)
+      '@eslint-community/eslint-utils': 4.5.1(eslint@9.24.0)
       '@eslint-community/regexpp': 4.12.1
-      '@eslint/config-array': 0.19.2
-      '@eslint/core': 0.11.0
-      '@eslint/eslintrc': 3.2.0
-      '@eslint/js': 9.20.0
-      '@eslint/plugin-kit': 0.2.6
+      '@eslint/config-array': 0.20.0
+      '@eslint/config-helpers': 0.2.1
+      '@eslint/core': 0.12.0
+      '@eslint/eslintrc': 3.3.1
+      '@eslint/js': 9.24.0
+      '@eslint/plugin-kit': 0.2.8
       '@humanfs/node': 0.16.6
       '@humanwhocodes/module-importer': 1.0.1
       '@humanwhocodes/retry': 0.4.2
-      '@types/estree': 1.0.6
+      '@types/estree': 1.0.7
       '@types/json-schema': 7.0.15
       ajv: 6.12.6
       chalk: 4.1.2
       cross-spawn: 7.0.6
       debug: 4.4.0(supports-color@8.1.1)
       escape-string-regexp: 4.0.0
-      eslint-scope: 8.2.0
+      eslint-scope: 8.3.0
       eslint-visitor-keys: 4.2.0
       espree: 10.3.0
       esquery: 1.6.0
@@ -4436,29 +3782,25 @@ packages:
     resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     dependencies:
-      acorn: 8.14.0
-      acorn-jsx: 5.3.2(acorn@8.14.0)
+      acorn: 8.14.1
+      acorn-jsx: 5.3.2(acorn@8.14.1)
       eslint-visitor-keys: 4.2.0
-    dev: true
-
-  /espree@6.2.1:
-    resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==}
-    engines: {node: '>=6.0.0'}
-    dependencies:
-      acorn: 7.4.1
-      acorn-jsx: 5.3.2(acorn@7.4.1)
-      eslint-visitor-keys: 1.3.0
-    dev: true
 
   /espree@9.6.1:
     resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dependencies:
-      acorn: 8.14.0
-      acorn-jsx: 5.3.2(acorn@8.14.0)
+      acorn: 8.14.1
+      acorn-jsx: 5.3.2(acorn@8.14.1)
       eslint-visitor-keys: 3.4.3
     dev: true
 
+  /esprima@4.0.1:
+    resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+    engines: {node: '>=4'}
+    hasBin: true
+    dev: true
+
   /esquery@1.6.0:
     resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
     engines: {node: '>=0.10'}
@@ -4481,6 +3823,12 @@ packages:
   /estree-walker@2.0.2:
     resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
 
+  /estree-walker@3.0.3:
+    resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+    dependencies:
+      '@types/estree': 1.0.7
+    dev: true
+
   /esutils@2.0.3:
     resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
     engines: {node: '>=0.10.0'}
@@ -4560,6 +3908,11 @@ packages:
       pify: 2.3.0
     dev: true
 
+  /expect-type@1.2.1:
+    resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==}
+    engines: {node: '>=12.0.0'}
+    dev: true
+
   /express@4.21.2:
     resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
     engines: {node: '>= 0.10.0'}
@@ -4644,7 +3997,6 @@ packages:
 
   /fast-deep-equal@3.1.3:
     resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
-    dev: true
 
   /fast-fifo@1.3.2:
     resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
@@ -4659,11 +4011,9 @@ packages:
       glob-parent: 5.1.2
       merge2: 1.4.1
       micromatch: 4.0.8
-    dev: true
 
   /fast-json-stable-stringify@2.1.0:
     resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
-    dev: true
 
   /fast-levenshtein@2.0.6:
     resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
@@ -4673,11 +4023,10 @@ packages:
     resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
     dev: true
 
-  /fastq@1.19.0:
-    resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==}
+  /fastq@1.19.1:
+    resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
     dependencies:
-      reusify: 1.0.4
-    dev: true
+      reusify: 1.1.0
 
   /fd-slicer@1.1.0:
     resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
@@ -4695,6 +4044,10 @@ packages:
       picomatch: 4.0.2
     dev: true
 
+  /fflate@0.8.2:
+    resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
+    dev: true
+
   /figures@3.2.0:
     resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
     engines: {node: '>=8'}
@@ -4771,12 +4124,6 @@ packages:
     resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
     dev: true
 
-  /focus-trap@7.6.4:
-    resolution: {integrity: sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==}
-    dependencies:
-      tabbable: 6.2.0
-    dev: true
-
   /follow-redirects@1.15.9:
     resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
     engines: {node: '>=4.0'}
@@ -4785,9 +4132,17 @@ packages:
     peerDependenciesMeta:
       debug:
         optional: true
+    dev: false
 
-  /foreground-child@3.3.0:
-    resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
+  /for-each@0.3.5:
+    resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      is-callable: 1.2.7
+    dev: true
+
+  /foreground-child@3.3.1:
+    resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
     engines: {node: '>=14'}
     dependencies:
       cross-spawn: 7.0.6
@@ -4860,6 +4215,10 @@ packages:
       universalify: 2.0.1
     dev: true
 
+  /fs-readdir-recursive@1.1.0:
+    resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==}
+    dev: true
+
   /fs.realpath@1.0.0:
     resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
 
@@ -4878,17 +4237,29 @@ packages:
   /function-bind@1.1.2:
     resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
 
+  /function.prototype.name@1.1.8:
+    resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      define-properties: 1.2.1
+      functions-have-names: 1.2.3
+      hasown: 2.0.2
+      is-callable: 1.2.7
+    dev: true
+
+  /functions-have-names@1.2.3:
+    resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+    dev: true
+
   /get-caller-file@2.0.5:
     resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
     engines: {node: 6.* || 8.* || >= 10.*}
     dev: true
 
-  /get-func-name@2.0.2:
-    resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
-    dev: true
-
-  /get-intrinsic@1.2.7:
-    resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==}
+  /get-intrinsic@1.3.0:
+    resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
     engines: {node: '>= 0.4'}
     dependencies:
       call-bind-apply-helpers: 1.0.2
@@ -4925,6 +4296,15 @@ packages:
     engines: {node: '>=10'}
     dev: false
 
+  /get-symbol-description@1.1.0:
+    resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+    dev: true
+
   /getos@3.2.1:
     resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==}
     dependencies:
@@ -4952,7 +4332,6 @@ packages:
     engines: {node: '>= 6'}
     dependencies:
       is-glob: 4.0.3
-    dev: true
 
   /glob-parent@6.0.2:
     resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
@@ -4969,7 +4348,7 @@ packages:
     resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
     hasBin: true
     dependencies:
-      foreground-child: 3.3.0
+      foreground-child: 3.3.1
       jackspeak: 3.4.3
       minimatch: 9.0.5
       minipass: 7.1.2
@@ -5011,13 +4390,25 @@ packages:
   /globals@14.0.0:
     resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
     engines: {node: '>=18'}
-    dev: true
 
   /globals@15.15.0:
     resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
     engines: {node: '>=18'}
     dev: true
 
+  /globals@16.0.0:
+    resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==}
+    engines: {node: '>=18'}
+    dev: true
+
+  /globalthis@1.0.4:
+    resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-properties: 1.2.1
+      gopd: 1.2.0
+    dev: true
+
   /globrex@0.1.2:
     resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
     dev: true
@@ -5091,10 +4482,28 @@ packages:
       whatwg-mimetype: 3.0.0
     dev: true
 
+  /has-bigints@1.1.0:
+    resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
   /has-flag@4.0.0:
     resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
     engines: {node: '>=8'}
 
+  /has-property-descriptors@1.0.2:
+    resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+    dependencies:
+      es-define-property: 1.0.1
+    dev: true
+
+  /has-proto@1.2.0:
+    resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      dunder-proto: 1.0.1
+    dev: true
+
   /has-symbols@1.1.0:
     resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
     engines: {node: '>= 0.4'}
@@ -5116,37 +4525,11 @@ packages:
     dependencies:
       function-bind: 1.1.2
 
-  /hast-util-to-html@9.0.5:
-    resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
-    dependencies:
-      '@types/hast': 3.0.4
-      '@types/unist': 3.0.3
-      ccount: 2.0.1
-      comma-separated-tokens: 2.0.3
-      hast-util-whitespace: 3.0.0
-      html-void-elements: 3.0.0
-      mdast-util-to-hast: 13.2.0
-      property-information: 7.0.0
-      space-separated-tokens: 2.0.2
-      stringify-entities: 4.0.4
-      zwitch: 2.0.4
-    dev: true
-
-  /hast-util-whitespace@3.0.0:
-    resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
-    dependencies:
-      '@types/hast': 3.0.4
-    dev: true
-
   /he@1.2.0:
     resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
     hasBin: true
     dev: true
 
-  /hookable@5.5.3:
-    resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
-    dev: true
-
   /html-minifier-terser@7.2.0:
     resolution: {integrity: sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==}
     engines: {node: ^14.13.1 || >=16.0.0}
@@ -5161,10 +4544,6 @@ packages:
       terser: 5.39.0
     dev: true
 
-  /html-void-elements@3.0.0:
-    resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
-    dev: true
-
   /http-cache-semantics@4.1.1:
     resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
     dev: false
@@ -5274,10 +4653,9 @@ packages:
   /ignore@5.3.2:
     resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
     engines: {node: '>= 4'}
-    dev: true
 
-  /immutable@5.0.3:
-    resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
+  /immutable@5.1.1:
+    resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==}
     dev: true
 
   /import-fresh@3.3.1:
@@ -5286,7 +4664,6 @@ packages:
     dependencies:
       parent-module: 1.0.1
       resolve-from: 4.0.0
-    dev: true
 
   /import-lazy@4.0.0:
     resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
@@ -5332,20 +4709,29 @@ packages:
     resolution: {integrity: sha512-LJKFHCSeIRq9hanN14IlOtPSTe3lNES7TYDTE2xxdAy1LS5rYphajK1qtwvj3YmQXvvk0U2Vbmcni8P9EIQW9w==}
     engines: {node: '>=18'}
     dependencies:
-      '@inquirer/figures': 1.0.10
+      '@inquirer/figures': 1.0.11
       ansi-escapes: 4.3.2
       cli-width: 4.1.0
       external-editor: 3.1.0
       mute-stream: 1.0.0
       ora: 5.4.1
       run-async: 3.0.0
-      rxjs: 7.8.1
+      rxjs: 7.8.2
       string-width: 4.2.3
       strip-ansi: 6.0.1
       wrap-ansi: 6.2.0
       yoctocolors-cjs: 2.1.2
     dev: true
 
+  /internal-slot@1.1.0:
+    resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-errors: 1.3.0
+      hasown: 2.0.2
+      side-channel: 1.1.0
+    dev: true
+
   /ip@1.1.9:
     resolution: {integrity: sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==}
     dev: true
@@ -5354,10 +4740,37 @@ packages:
     resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
     engines: {node: '>= 0.10'}
 
+  /is-array-buffer@3.0.5:
+    resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      get-intrinsic: 1.3.0
+    dev: true
+
   /is-arrayish@0.2.1:
     resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
     dev: true
 
+  /is-async-function@2.1.1:
+    resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      async-function: 1.0.0
+      call-bound: 1.0.4
+      get-proto: 1.0.1
+      has-tostringtag: 1.0.2
+      safe-regex-test: 1.1.0
+    dev: true
+
+  /is-bigint@1.1.0:
+    resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-bigints: 1.1.0
+    dev: true
+
   /is-binary-path@2.1.0:
     resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
     engines: {node: '>=8'}
@@ -5365,6 +4778,19 @@ packages:
       binary-extensions: 2.3.0
     dev: true
 
+  /is-boolean-object@1.2.2:
+    resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      has-tostringtag: 1.0.2
+    dev: true
+
+  /is-callable@1.2.7:
+    resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
   /is-ci@3.0.1:
     resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
     hasBin: true
@@ -5372,6 +4798,30 @@ packages:
       ci-info: 3.9.0
     dev: false
 
+  /is-core-module@2.16.1:
+    resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      hasown: 2.0.2
+    dev: true
+
+  /is-data-view@1.0.2:
+    resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      get-intrinsic: 1.3.0
+      is-typed-array: 1.1.15
+    dev: true
+
+  /is-date-object@1.1.0:
+    resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      has-tostringtag: 1.0.2
+    dev: true
+
   /is-docker@2.2.1:
     resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
     engines: {node: '>=8'}
@@ -5386,10 +4836,27 @@ packages:
     resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
     engines: {node: '>=0.10.0'}
 
+  /is-finalizationregistry@1.1.1:
+    resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+    dev: true
+
   /is-fullwidth-code-point@3.0.0:
     resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
     engines: {node: '>=8'}
 
+  /is-generator-function@1.1.0:
+    resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      get-proto: 1.0.1
+      has-tostringtag: 1.0.2
+      safe-regex-test: 1.1.0
+    dev: true
+
   /is-glob@4.0.3:
     resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
     engines: {node: '>=0.10.0'}
@@ -5415,11 +4882,24 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /is-map@2.0.3:
+    resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
   /is-npm@6.0.0:
     resolution: {integrity: sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
     dev: false
 
+  /is-number-object@1.1.1:
+    resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      has-tostringtag: 1.0.2
+    dev: true
+
   /is-number@7.0.0:
     resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
     engines: {node: '>=0.12.0'}
@@ -5449,6 +4929,28 @@ packages:
       isobject: 3.0.1
     dev: true
 
+  /is-regex@1.2.1:
+    resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      gopd: 1.2.0
+      has-tostringtag: 1.0.2
+      hasown: 2.0.2
+    dev: true
+
+  /is-set@2.0.3:
+    resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
+  /is-shared-array-buffer@1.0.4:
+    resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+    dev: true
+
   /is-stream@2.0.1:
     resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
     engines: {node: '>=8'}
@@ -5458,6 +4960,23 @@ packages:
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
     dev: false
 
+  /is-string@1.1.1:
+    resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      has-tostringtag: 1.0.2
+    dev: true
+
+  /is-symbol@1.1.1:
+    resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      has-symbols: 1.1.0
+      safe-regex-test: 1.1.0
+    dev: true
+
   /is-text-path@2.0.0:
     resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==}
     engines: {node: '>=8'}
@@ -5465,6 +4984,13 @@ packages:
       text-extensions: 2.4.0
     dev: true
 
+  /is-typed-array@1.1.15:
+    resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      which-typed-array: 1.1.19
+    dev: true
+
   /is-typedarray@1.0.0:
     resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
 
@@ -5473,9 +4999,24 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
-  /is-what@4.1.16:
-    resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
-    engines: {node: '>=12.13'}
+  /is-weakmap@2.0.2:
+    resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
+  /is-weakref@1.1.1:
+    resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+    dev: true
+
+  /is-weakset@2.0.4:
+    resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      get-intrinsic: 1.3.0
     dev: true
 
   /is-wsl@2.2.0:
@@ -5499,6 +5040,10 @@ packages:
   /isarray@1.0.0:
     resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
 
+  /isarray@2.0.5:
+    resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+    dev: true
+
   /isbinaryfile@5.0.4:
     resolution: {integrity: sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==}
     engines: {node: '>= 18.0.0'}
@@ -5529,8 +5074,8 @@ packages:
     hasBin: true
     dev: true
 
-  /js-beautify@1.15.3:
-    resolution: {integrity: sha512-rKKGuyTxGNlyN4EQKWzNndzXpi0bOl8Gl8YQAW1as/oMz0XhD6sHJO1hTvoBDOSzKuJb9WkwoAb34FfdkKMv2A==}
+  /js-beautify@1.15.4:
+    resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
     engines: {node: '>=14'}
     hasBin: true
     dependencies:
@@ -5538,7 +5083,7 @@ packages:
       editorconfig: 1.0.4
       glob: 10.4.5
       js-cookie: 3.0.5
-      nopt: 8.1.0
+      nopt: 7.2.1
     dev: true
 
   /js-cookie@3.0.5:
@@ -5555,7 +5100,6 @@ packages:
     hasBin: true
     dependencies:
       argparse: 2.0.1
-    dev: true
 
   /jsbn@0.1.1:
     resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
@@ -5570,7 +5114,6 @@ packages:
 
   /json-schema-traverse@0.4.1:
     resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
-    dev: true
 
   /json-schema-traverse@1.0.0:
     resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
@@ -5601,15 +5144,14 @@ packages:
     hasBin: true
     dev: true
 
-  /jsonc-eslint-parser@1.4.1:
-    resolution: {integrity: sha512-hXBrvsR1rdjmB2kQmUjf1rEIa+TqHBGMge8pwi++C+Si1ad7EjZrJcpgwym+QGK/pqTx+K7keFAtLlVNdLRJOg==}
-    engines: {node: '>=8.10.0'}
+  /jsonc-eslint-parser@2.4.0:
+    resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dependencies:
-      acorn: 7.4.1
-      eslint-utils: 2.1.0
-      eslint-visitor-keys: 1.3.0
-      espree: 6.2.1
-      semver: 6.3.1
+      acorn: 8.14.1
+      eslint-visitor-keys: 3.4.3
+      espree: 9.6.1
+      semver: 7.7.1
     dev: true
 
   /jsonfile@4.0.0:
@@ -5640,6 +5182,16 @@ packages:
       verror: 1.10.0
     dev: true
 
+  /junit-merge@2.0.0:
+    resolution: {integrity: sha512-qwENzBWcdHPazNqPO0fKyFIqEyaSKyO0iyBeIU4Y/scjkXYpwTi88P2S/PWecqgMhzG2MOCwXk8QB9ucvXeIPw==}
+    hasBin: true
+    dependencies:
+      commander: 2.20.3
+      fs-readdir-recursive: 1.1.0
+      mkdirp: 0.5.6
+      xmldoc: 1.3.0
+    dev: true
+
   /keyv@4.5.4:
     resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
     dependencies:
@@ -5699,16 +5251,11 @@ packages:
       log-update: 4.0.0
       p-map: 4.0.0
       rfdc: 1.4.1
-      rxjs: 7.8.1
+      rxjs: 7.8.2
       through: 2.3.8
       wrap-ansi: 7.0.0
     dev: true
 
-  /local-pkg@0.4.3:
-    resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
-    engines: {node: '>=14'}
-    dev: true
-
   /locate-path@5.0.0:
     resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
     engines: {node: '>=8'}
@@ -5819,10 +5366,8 @@ packages:
       js-tokens: 4.0.0
     dev: true
 
-  /loupe@2.3.7:
-    resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
-    dependencies:
-      get-func-name: 2.0.2
+  /loupe@3.1.3:
+    resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
     dev: true
 
   /lower-case@2.0.2:
@@ -5863,28 +5408,10 @@ packages:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.5.0
 
-  /mark.js@8.11.1:
-    resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==}
-    dev: true
-
   /math-intrinsics@1.1.0:
     resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
     engines: {node: '>= 0.4'}
 
-  /mdast-util-to-hast@13.2.0:
-    resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
-    dependencies:
-      '@types/hast': 3.0.4
-      '@types/mdast': 4.0.4
-      '@ungap/structured-clone': 1.3.0
-      devlop: 1.1.0
-      micromark-util-sanitize-uri: 2.0.1
-      trim-lines: 3.0.1
-      unist-util-position: 5.0.0
-      unist-util-visit: 5.0.0
-      vfile: 6.0.3
-    dev: true
-
   /media-typer@0.3.0:
     resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
     engines: {node: '>= 0.6'}
@@ -5903,7 +5430,6 @@ packages:
   /merge2@1.4.1:
     resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
     engines: {node: '>= 8'}
-    dev: true
 
   /merge@2.1.1:
     resolution: {integrity: sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==}
@@ -5913,33 +5439,6 @@ packages:
     resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
     engines: {node: '>= 0.6'}
 
-  /micromark-util-character@2.1.1:
-    resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
-    dependencies:
-      micromark-util-symbol: 2.0.1
-      micromark-util-types: 2.0.1
-    dev: true
-
-  /micromark-util-encode@2.0.1:
-    resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
-    dev: true
-
-  /micromark-util-sanitize-uri@2.0.1:
-    resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
-    dependencies:
-      micromark-util-character: 2.1.1
-      micromark-util-encode: 2.0.1
-      micromark-util-symbol: 2.0.1
-    dev: true
-
-  /micromark-util-symbol@2.0.1:
-    resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
-    dev: true
-
-  /micromark-util-types@2.0.1:
-    resolution: {integrity: sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==}
-    dev: true
-
   /micromatch@4.0.8:
     resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
     engines: {node: '>=8.6'}
@@ -5951,8 +5450,8 @@ packages:
     resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
     engines: {node: '>= 0.6'}
 
-  /mime-db@1.53.0:
-    resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==}
+  /mime-db@1.54.0:
+    resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
     engines: {node: '>= 0.6'}
 
   /mime-types@2.1.35:
@@ -6024,28 +5523,19 @@ packages:
     engines: {node: '>=16 || 14 >=14.17'}
     dev: true
 
-  /minisearch@7.1.2:
-    resolution: {integrity: sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==}
-    dev: true
-
-  /mitt@3.0.1:
-    resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
-    dev: true
-
   /mkdirp@0.5.6:
     resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
     hasBin: true
     dependencies:
       minimist: 1.2.8
-    dev: false
 
   /mlly@1.7.4:
     resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
     dependencies:
-      acorn: 8.14.0
+      acorn: 8.14.1
       pathe: 2.0.3
       pkg-types: 1.3.1
-      ufo: 1.5.4
+      ufo: 1.6.0
     dev: true
 
   /mocha@11.1.0:
@@ -6099,7 +5589,7 @@ packages:
       prop-types: 15.8.1
       tcomb: 3.2.29
       tcomb-validation: 3.4.1
-      validator: 13.12.0
+      validator: 13.15.0
       yargs: 17.7.2
     dev: true
 
@@ -6125,6 +5615,11 @@ packages:
     resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
     dev: false
 
+  /mrmime@2.0.1:
+    resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+    engines: {node: '>=10'}
+    dev: true
+
   /ms@2.0.0:
     resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
 
@@ -6144,8 +5639,8 @@ packages:
       thenify-all: 1.6.0
     dev: true
 
-  /nanoid@3.3.8:
-    resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
+  /nanoid@3.3.11:
+    resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     hasBin: true
 
@@ -6186,12 +5681,12 @@ packages:
     resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
     dev: true
 
-  /nopt@8.1.0:
-    resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==}
-    engines: {node: ^18.17.0 || >=20.5.0}
+  /nopt@7.2.1:
+    resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     hasBin: true
     dependencies:
-      abbrev: 3.0.0
+      abbrev: 2.0.0
     dev: true
 
   /normalize-path@3.0.0:
@@ -6241,6 +5736,52 @@ packages:
     resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
     engines: {node: '>= 0.4'}
 
+  /object-keys@1.1.1:
+    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
+  /object.assign@4.1.7:
+    resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
+    engines: {node: '>= 0.4'}
+    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
+    dev: true
+
+  /object.fromentries@2.0.8:
+    resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-object-atoms: 1.1.1
+    dev: true
+
+  /object.groupby@1.0.3:
+    resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+    dev: true
+
+  /object.values@1.2.1:
+    resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      define-properties: 1.2.1
+      es-object-atoms: 1.1.1
+    dev: true
+
   /on-finished@2.4.1:
     resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
     engines: {node: '>= 0.8'}
@@ -6269,14 +5810,6 @@ packages:
       mimic-fn: 4.0.0
     dev: false
 
-  /oniguruma-to-es@3.1.1:
-    resolution: {integrity: sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==}
-    dependencies:
-      emoji-regex-xs: 1.0.0
-      regex: 6.0.1
-      regex-recursion: 6.0.2
-    dev: true
-
   /open@10.1.0:
     resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
     engines: {node: '>=18'}
@@ -6346,6 +5879,15 @@ packages:
     resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==}
     dev: true
 
+  /own-keys@1.0.1:
+    resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      get-intrinsic: 1.3.0
+      object-keys: 1.1.1
+      safe-push-apply: 1.0.0
+    dev: true
+
   /p-cancelable@2.1.1:
     resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
     engines: {node: '>=8'}
@@ -6374,7 +5916,7 @@ packages:
     resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
     dependencies:
-      yocto-queue: 1.1.1
+      yocto-queue: 1.2.1
     dev: true
 
   /p-locate@4.1.0:
@@ -6436,7 +5978,6 @@ packages:
     engines: {node: '>=6'}
     dependencies:
       callsites: 3.1.0
-    dev: true
 
   /parse-json@5.2.0:
     resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
@@ -6482,6 +6023,10 @@ packages:
     engines: {node: '>=12'}
     dev: false
 
+  /path-parse@1.0.7:
+    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+    dev: true
+
   /path-scurry@1.11.1:
     resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
     engines: {node: '>=16 || 14 >=14.18'}
@@ -6501,17 +6046,14 @@ packages:
     resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
     dev: true
 
-  /pathval@1.1.1:
-    resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+  /pathval@2.0.0:
+    resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
+    engines: {node: '>= 14.16'}
     dev: true
 
   /pend@1.2.0:
     resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
 
-  /perfect-debounce@1.0.0:
-    resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
-    dev: true
-
   /performance-now@2.1.0:
     resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
     dev: true
@@ -6533,7 +6075,7 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /pinia@2.3.1(typescript@5.7.3)(vue@3.5.13):
+  /pinia@2.3.1(typescript@5.8.3)(vue@3.5.13):
     resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==}
     peerDependencies:
       typescript: '>=4.4.4'
@@ -6543,14 +6085,14 @@ packages:
         optional: true
     dependencies:
       '@vue/devtools-api': 6.6.4
-      typescript: 5.7.3
-      vue: 3.5.13(typescript@5.7.3)
+      typescript: 5.8.3
+      vue: 3.5.13(typescript@5.8.3)
       vue-demi: 0.14.10(vue@3.5.13)
     transitivePeerDependencies:
       - '@vue/composition-api'
 
-  /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'}
     dev: true
 
@@ -6562,6 +6104,11 @@ packages:
       pathe: 2.0.3
     dev: true
 
+  /possible-typed-array-names@1.1.0:
+    resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
   /postcss-selector-parser@6.1.2:
     resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
     engines: {node: '>=4'}
@@ -6578,21 +6125,17 @@ packages:
     resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
-      nanoid: 3.3.8
+      nanoid: 3.3.11
       picocolors: 1.1.1
       source-map-js: 1.2.1
 
-  /preact@10.26.2:
-    resolution: {integrity: sha512-0gNmv4qpS9HaN3+40CLBAnKe0ZfyE4ZWo5xKlC1rVrr0ckkEvJvAQqKaHANdFKsGstoxrY4AItZ7kZSGVoVjgg==}
-    dev: true
-
   /prelude-ls@1.2.1:
     resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
     engines: {node: '>= 0.8.0'}
     dev: true
 
-  /prettier@3.5.1:
-    resolution: {integrity: sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==}
+  /prettier@3.5.3:
+    resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
     engines: {node: '>=14'}
     hasBin: true
     dev: true
@@ -6602,15 +6145,6 @@ packages:
     engines: {node: '>=6'}
     dev: true
 
-  /pretty-format@29.7.0:
-    resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
-    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-    dependencies:
-      '@jest/schemas': 29.6.3
-      ansi-styles: 5.2.0
-      react-is: 18.3.1
-    dev: true
-
   /process-nextick-args@2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
 
@@ -6632,10 +6166,6 @@ packages:
       react-is: 16.13.1
     dev: true
 
-  /property-information@7.0.0:
-    resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==}
-    dev: true
-
   /proto-list@1.2.4:
     resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
 
@@ -6652,6 +6182,7 @@ packages:
 
   /proxy-from-env@1.1.0:
     resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+    dev: false
 
   /pseudomap@1.0.2:
     resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
@@ -6666,7 +6197,6 @@ packages:
   /punycode@2.3.1:
     resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
     engines: {node: '>=6'}
-    dev: true
 
   /pupa@3.1.0:
     resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==}
@@ -6681,20 +6211,19 @@ packages:
     dependencies:
       side-channel: 1.1.0
 
-  /qs@6.13.1:
-    resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==}
+  /qs@6.14.0:
+    resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
     engines: {node: '>=0.6'}
     dependencies:
       side-channel: 1.1.0
     dev: true
 
-  /quasar@2.17.7:
-    resolution: {integrity: sha512-nPJdHoONlcW7WEU2Ody907Wx945Zfyuea/KP4LBaEn5AcL95PUWp8Gz/0zDYNnFw0aCWRtye3SUAdQl5tmrn5w==}
+  /quasar@2.18.1:
+    resolution: {integrity: sha512-db/P64Mzpt1uXJ0MapaG+IYJQ9hHDb5KtTCoszwC78DR7sA+Uoj7nBW2EytwYykIExEmqavOvKrdasTvqhkgEg==}
     engines: {node: '>= 10.18.1', npm: '>= 6.13.4', yarn: '>= 1.21.1'}
 
   /queue-microtask@1.2.3:
     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
-    dev: true
 
   /quick-lru@5.1.1:
     resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
@@ -6730,25 +6259,21 @@ packages:
       strip-json-comments: 2.0.1
     dev: false
 
-  /react-dom@19.0.0(react@19.0.0):
-    resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==}
+  /react-dom@19.1.0(react@19.1.0):
+    resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
     peerDependencies:
-      react: ^19.0.0
+      react: ^19.1.0
     dependencies:
-      react: 19.0.0
-      scheduler: 0.25.0
+      react: 19.1.0
+      scheduler: 0.26.0
     dev: true
 
   /react-is@16.13.1:
     resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
     dev: true
 
-  /react-is@18.3.1:
-    resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
-    dev: true
-
-  /react@19.0.0:
-    resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
+  /react@19.1.0:
+    resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
     engines: {node: '>=0.10.0'}
     dev: true
 
@@ -6811,24 +6336,34 @@ packages:
       tslib: 1.14.1
     dev: true
 
+  /reflect.getprototypeof@1.0.10:
+    resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-errors: 1.3.0
+      es-object-atoms: 1.1.1
+      get-intrinsic: 1.3.0
+      get-proto: 1.0.1
+      which-builtin-type: 1.2.1
+    dev: true
+
   /regenerator-runtime@0.14.1:
     resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
     dev: true
 
-  /regex-recursion@6.0.2:
-    resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
+  /regexp.prototype.flags@1.5.4:
+    resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
+    engines: {node: '>= 0.4'}
     dependencies:
-      regex-utilities: 2.3.0
-    dev: true
-
-  /regex-utilities@2.3.0:
-    resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==}
-    dev: true
-
-  /regex@6.0.1:
-    resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==}
-    dependencies:
-      regex-utilities: 2.3.0
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-errors: 1.3.0
+      get-proto: 1.0.1
+      gopd: 1.2.0
+      set-function-name: 2.0.2
     dev: true
 
   /registry-auth-token@5.1.0:
@@ -6881,13 +6416,22 @@ packages:
   /resolve-from@4.0.0:
     resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
     engines: {node: '>=4'}
-    dev: true
 
   /resolve-from@5.0.0:
     resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
     engines: {node: '>=8'}
     dev: true
 
+  /resolve@1.22.10:
+    resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+    engines: {node: '>= 0.4'}
+    hasBin: true
+    dependencies:
+      is-core-module: 2.16.1
+      path-parse: 1.0.7
+      supports-preserve-symlinks-flag: 1.0.0
+    dev: true
+
   /responselike@2.0.1:
     resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
     dependencies:
@@ -6909,10 +6453,9 @@ packages:
       signal-exit: 3.0.7
     dev: true
 
-  /reusify@1.0.4:
-    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+  /reusify@1.1.0:
+    resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
     engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
-    dev: true
 
   /rfdc@1.4.1:
     resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
@@ -6945,32 +6488,33 @@ packages:
       yargs: 17.7.2
     dev: true
 
-  /rollup@4.34.8:
-    resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==}
+  /rollup@4.39.0:
+    resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==}
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
     hasBin: true
     dependencies:
-      '@types/estree': 1.0.6
+      '@types/estree': 1.0.7
     optionalDependencies:
-      '@rollup/rollup-android-arm-eabi': 4.34.8
-      '@rollup/rollup-android-arm64': 4.34.8
-      '@rollup/rollup-darwin-arm64': 4.34.8
-      '@rollup/rollup-darwin-x64': 4.34.8
-      '@rollup/rollup-freebsd-arm64': 4.34.8
-      '@rollup/rollup-freebsd-x64': 4.34.8
-      '@rollup/rollup-linux-arm-gnueabihf': 4.34.8
-      '@rollup/rollup-linux-arm-musleabihf': 4.34.8
-      '@rollup/rollup-linux-arm64-gnu': 4.34.8
-      '@rollup/rollup-linux-arm64-musl': 4.34.8
-      '@rollup/rollup-linux-loongarch64-gnu': 4.34.8
-      '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8
-      '@rollup/rollup-linux-riscv64-gnu': 4.34.8
-      '@rollup/rollup-linux-s390x-gnu': 4.34.8
-      '@rollup/rollup-linux-x64-gnu': 4.34.8
-      '@rollup/rollup-linux-x64-musl': 4.34.8
-      '@rollup/rollup-win32-arm64-msvc': 4.34.8
-      '@rollup/rollup-win32-ia32-msvc': 4.34.8
-      '@rollup/rollup-win32-x64-msvc': 4.34.8
+      '@rollup/rollup-android-arm-eabi': 4.39.0
+      '@rollup/rollup-android-arm64': 4.39.0
+      '@rollup/rollup-darwin-arm64': 4.39.0
+      '@rollup/rollup-darwin-x64': 4.39.0
+      '@rollup/rollup-freebsd-arm64': 4.39.0
+      '@rollup/rollup-freebsd-x64': 4.39.0
+      '@rollup/rollup-linux-arm-gnueabihf': 4.39.0
+      '@rollup/rollup-linux-arm-musleabihf': 4.39.0
+      '@rollup/rollup-linux-arm64-gnu': 4.39.0
+      '@rollup/rollup-linux-arm64-musl': 4.39.0
+      '@rollup/rollup-linux-loongarch64-gnu': 4.39.0
+      '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0
+      '@rollup/rollup-linux-riscv64-gnu': 4.39.0
+      '@rollup/rollup-linux-riscv64-musl': 4.39.0
+      '@rollup/rollup-linux-s390x-gnu': 4.39.0
+      '@rollup/rollup-linux-x64-gnu': 4.39.0
+      '@rollup/rollup-linux-x64-musl': 4.39.0
+      '@rollup/rollup-win32-arm64-msvc': 4.39.0
+      '@rollup/rollup-win32-ia32-msvc': 4.39.0
+      '@rollup/rollup-win32-x64-msvc': 4.39.0
       fsevents: 2.3.3
     dev: true
 
@@ -7004,25 +6548,52 @@ packages:
     resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
     dependencies:
       queue-microtask: 1.2.3
-    dev: true
 
-  /rxjs@7.8.1:
-    resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
+  /rxjs@7.8.2:
+    resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
     dependencies:
       tslib: 2.8.1
     dev: true
 
+  /safe-array-concat@1.1.3:
+    resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
+    engines: {node: '>=0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      get-intrinsic: 1.3.0
+      has-symbols: 1.1.0
+      isarray: 2.0.5
+    dev: true
+
   /safe-buffer@5.1.2:
     resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
 
   /safe-buffer@5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
 
+  /safe-push-apply@1.0.0:
+    resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-errors: 1.3.0
+      isarray: 2.0.5
+    dev: true
+
+  /safe-regex-test@1.1.0:
+    resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      is-regex: 1.2.1
+    dev: true
+
   /safer-buffer@2.1.2:
     resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
 
-  /sass-embedded-android-arm64@1.85.0:
-    resolution: {integrity: sha512-4itDzRwezwrW8+YzMLIwHtMeH+qrBNdBsRn9lTVI15K+cNLC8z5JWJi6UCZ8TNNZr9LDBfsh5jUdjSub0yF7jg==}
+  /sass-embedded-android-arm64@1.86.3:
+    resolution: {integrity: sha512-q+XwFp6WgAv+UgnQhsB8KQ95kppvWAB7DSoJp+8Vino8b9ND+1ai3cUUZPE5u4SnLZrgo5NtrbPvN5KLc4Pfyg==}
     engines: {node: '>=14.0.0'}
     cpu: [arm64]
     os: [android]
@@ -7030,8 +6601,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-android-arm@1.85.0:
-    resolution: {integrity: sha512-pPBT7Ad6G8Mlao8ypVNXW2ya7I/Bhcny+RYZ/EmrunEXfhzCNp4PWV2VAweitPO9RnPIJwvUTkLc8Fu6K3nVmw==}
+  /sass-embedded-android-arm@1.86.3:
+    resolution: {integrity: sha512-UyeXrFzZSvrGbvrWUBcspbsbivGgAgebLGJdSqJulgSyGbA6no3DWQ5Qpdd6+OAUC39BlpPu74Wx9s4RrVuaFw==}
     engines: {node: '>=14.0.0'}
     cpu: [arm]
     os: [android]
@@ -7039,8 +6610,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-android-ia32@1.85.0:
-    resolution: {integrity: sha512-bwqKq95hzbGbMTeXCMQhH7yEdc2xJVwIXj7rGdD3McvyFWbED6362XRFFPI5YyjfD2wRJd9yWLh/hn+6VyjcYA==}
+  /sass-embedded-android-ia32@1.86.3:
+    resolution: {integrity: sha512-gTJjVh2cRzvGujXj5ApPk/owUTL5SiO7rDtNLrzYAzi1N5HRuLYXqk3h1IQY3+eCOBjGl7mQ9XyySbJs/3hDvg==}
     engines: {node: '>=14.0.0'}
     cpu: [ia32]
     os: [android]
@@ -7048,8 +6619,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-android-riscv64@1.85.0:
-    resolution: {integrity: sha512-Fgkgay+5EePJXZFHR5Vlkutnsmox2V6nX4U3mfGbSN1xjLRm8F5ST72V2s5Z0mnIFpGvEu/v7hfptgViqMvaxg==}
+  /sass-embedded-android-riscv64@1.86.3:
+    resolution: {integrity: sha512-Po3JnyiCS16kd6REo1IMUbFGYtvL9O0rmKaXx5vOuBaJD1LPy2LiSSp7TU7wkJ9IxsTDGzFaSeP1I9qb6D8VVg==}
     engines: {node: '>=14.0.0'}
     cpu: [riscv64]
     os: [android]
@@ -7057,8 +6628,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-android-x64@1.85.0:
-    resolution: {integrity: sha512-/bG3JgTn3eoIDHCiJNVkLeJgUesat4ghxqYmKMZUJx++4e6iKCDj8XwQTJAgm+QDrsPKXHBacHEANJ9LEAuTqg==}
+  /sass-embedded-android-x64@1.86.3:
+    resolution: {integrity: sha512-+7h3jdDv/0kUFx0BvxYlq2fa7CcHiDPlta6k5OxO5K6jyqJwo9hc0Z052BoYEauWTqZ+vK6bB5rv2BIzq4U9nA==}
     engines: {node: '>=14.0.0'}
     cpu: [x64]
     os: [android]
@@ -7066,8 +6637,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-darwin-arm64@1.85.0:
-    resolution: {integrity: sha512-plp8TyMz97YFBCB3ndftEvoW29vyfsSBJILM5U84cGzr06SvLh/Npjj8psfUeRw+upEk1zkFtw5u61sRCdgwIw==}
+  /sass-embedded-darwin-arm64@1.86.3:
+    resolution: {integrity: sha512-EgLwV4ORm5Hr0DmIXo0Xw/vlzwLnfAiqD2jDXIglkBsc5czJmo4/IBdGXOP65TRnsgJEqvbU3aQhuawX5++x9A==}
     engines: {node: '>=14.0.0'}
     cpu: [arm64]
     os: [darwin]
@@ -7075,8 +6646,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-darwin-x64@1.85.0:
-    resolution: {integrity: sha512-LP8Zv8DG57Gn6PmSwWzC0gEZUsGdg36Ps3m0i1fVTOelql7N3HZIrlPYRjJvidL8ZlB3ISxNANebTREUHn/wkQ==}
+  /sass-embedded-darwin-x64@1.86.3:
+    resolution: {integrity: sha512-dfKhfrGPRNLWLC82vy/vQGmNKmAiKWpdFuWiePRtg/E95pqw+sCu6080Y6oQLfFu37Iq3MpnXiSpDuSo7UnPWA==}
     engines: {node: '>=14.0.0'}
     cpu: [x64]
     os: [darwin]
@@ -7084,8 +6655,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-arm64@1.85.0:
-    resolution: {integrity: sha512-JRIRKVOY5Y8M1zlUOv9AQGju4P6lj8i5vLJZsVYVN/uY8Cd2dDJZPC8EOhjntp+IpF8AOGIHqCeCkHBceIyIjA==}
+  /sass-embedded-linux-arm64@1.86.3:
+    resolution: {integrity: sha512-tYq5rywR53Qtc+0KI6pPipOvW7a47ETY69VxfqI9BR2RKw2hBbaz0bIw6OaOgEBv2/XNwcWb7a4sr7TqgkqKAA==}
     engines: {node: '>=14.0.0'}
     cpu: [arm64]
     os: [linux]
@@ -7093,8 +6664,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-arm@1.85.0:
-    resolution: {integrity: sha512-18xOAEfazJt1MMVS2TRHV94n81VyMnywOoJ7/S7I79qno/zx26OoqqP4XvH107xu8+mZ9Gg54LrUH6ZcgHk08g==}
+  /sass-embedded-linux-arm@1.86.3:
+    resolution: {integrity: sha512-+fVCIH+OR0SMHn2NEhb/VfbpHuUxcPtqMS34OCV3Ka99LYZUJZqth4M3lT/ppGl52mwIVLNYzR4iLe6mdZ6mYA==}
     engines: {node: '>=14.0.0'}
     cpu: [arm]
     os: [linux]
@@ -7102,8 +6673,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-ia32@1.85.0:
-    resolution: {integrity: sha512-4JH+h+gLt9So22nNPQtsKojEsLzjld9ol3zWcOtMGclv+HojZGbCuhJUrLUcK72F8adXYsULmWhJPKROLIwYMA==}
+  /sass-embedded-linux-ia32@1.86.3:
+    resolution: {integrity: sha512-CmQ5OkqnaeLdaF+bMqlYGooBuenqm3LvEN9H8BLhjkpWiFW8hnYMetiqMcJjhrXLvDw601KGqA5sr/Rsg5s45g==}
     engines: {node: '>=14.0.0'}
     cpu: [ia32]
     os: [linux]
@@ -7111,8 +6682,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-musl-arm64@1.85.0:
-    resolution: {integrity: sha512-aoQjUjK28bvdw9XKTjQeayn8oWQ2QqvoTD11myklGd3IHH7Jj0nwXUstI4NxDueCKt3wghuZoIQkjOheReQxlg==}
+  /sass-embedded-linux-musl-arm64@1.86.3:
+    resolution: {integrity: sha512-4zOr2C/eW89rxb4ozTfn7lBzyyM5ZigA1ZSRTcAR26Qbg/t2UksLdGnVX9/yxga0d6aOi0IvO/7iM2DPPRRotg==}
     engines: {node: '>=14.0.0'}
     cpu: [arm64]
     os: [linux]
@@ -7120,8 +6691,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-musl-arm@1.85.0:
-    resolution: {integrity: sha512-Z1j4ageDVFihqNUBnm89fxY46pY0zD/Clp1D3ZdI7S+D280+AEpbm5vMoH8LLhBQfQLf2w7H++SZGpQwrisudQ==}
+  /sass-embedded-linux-musl-arm@1.86.3:
+    resolution: {integrity: sha512-SEm65SQknI4pl+mH5Xf231hOkHJyrlgh5nj4qDbiBG6gFeutaNkNIeRgKEg3cflXchCr8iV/q/SyPgjhhzQb7w==}
     engines: {node: '>=14.0.0'}
     cpu: [arm]
     os: [linux]
@@ -7129,8 +6700,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-musl-ia32@1.85.0:
-    resolution: {integrity: sha512-/cJCSXOfXmQFH8deE+3U9x+BSz8i0d1Tt9gKV/Gat1Xm43Oumw8pmZgno+cDuGjYQInr9ryW5121pTMlj/PBXQ==}
+  /sass-embedded-linux-musl-ia32@1.86.3:
+    resolution: {integrity: sha512-84Tcld32LB1loiqUvczWyVBQRCChm0wNLlkT59qF29nxh8njFIVf9yaPgXcSyyjpPoD9Tu0wnq3dvVzoMCh9AQ==}
     engines: {node: '>=14.0.0'}
     cpu: [ia32]
     os: [linux]
@@ -7138,8 +6709,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-musl-riscv64@1.85.0:
-    resolution: {integrity: sha512-l+FJxMXkmg42RZq5RFKXg4InX0IA7yEiPHe4kVSdrczP7z3NLxk+W9wVkPnoRKYIMe1qZPPQ25y0TgI4HNWouA==}
+  /sass-embedded-linux-musl-riscv64@1.86.3:
+    resolution: {integrity: sha512-IxEqoiD7vdNpiOwccybbV93NljBy64wSTkUOknGy21SyV43C8uqESOwTwW9ywa3KufImKm8L3uQAW/B0KhJMWg==}
     engines: {node: '>=14.0.0'}
     cpu: [riscv64]
     os: [linux]
@@ -7147,8 +6718,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-musl-x64@1.85.0:
-    resolution: {integrity: sha512-M9ffjcYfFcRvkFA6V3DpOS955AyvmpvPAhL/xNK45d/ma1n1ehTWpd24tVeKiNK5CZkNjjMEfyw2fHa6MpqmEA==}
+  /sass-embedded-linux-musl-x64@1.86.3:
+    resolution: {integrity: sha512-ePeTPXUxPK6JgHcUfnrkIyDtyt+zlAvF22mVZv6y1g/PZFm1lSfX+Za7TYHg9KaYqaaXDiw6zICX4i44HhR8rA==}
     engines: {node: '>=14.0.0'}
     cpu: [x64]
     os: [linux]
@@ -7156,8 +6727,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-riscv64@1.85.0:
-    resolution: {integrity: sha512-yqPXQWfM+qiIPkfn++48GOlbmSvUZIyL9nwFstBk0k4x40UhbhilfknqeTUpxoHfQzylTGVhrm5JE7MjM+LNZA==}
+  /sass-embedded-linux-riscv64@1.86.3:
+    resolution: {integrity: sha512-NuXQ72dwfNLe35E+RaXJ4Noq4EkFwM65eWwCwxEWyJO9qxOx1EXiCAJii6x8kkOh5daWuMU0VAI1B9RsJaqqQQ==}
     engines: {node: '>=14.0.0'}
     cpu: [riscv64]
     os: [linux]
@@ -7165,8 +6736,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-linux-x64@1.85.0:
-    resolution: {integrity: sha512-NTDeQFZcuVR7COoaRy8pZD6/+QznwBR8kVFsj7NpmvX9aJ7TX/q+OQZHX7Bfb3tsfKXhf1YZozegPuYxRnMKAQ==}
+  /sass-embedded-linux-x64@1.86.3:
+    resolution: {integrity: sha512-t8be9zJ5B82+og9bQmIQ83yMGYZMTMrlGA+uGWtYacmwg6w3093dk91Fx0YzNSZBp3Tk60qVYjCZnEIwy60x0g==}
     engines: {node: '>=14.0.0'}
     cpu: [x64]
     os: [linux]
@@ -7174,8 +6745,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-win32-arm64@1.85.0:
-    resolution: {integrity: sha512-gO0VAuxC4AdV+uZYJESRWVVHQWCGzNs0C3OKCAdH4r1vGRugooMi7J/5wbwUdXDA1MV9ICfhlKsph2n3GiPdqA==}
+  /sass-embedded-win32-arm64@1.86.3:
+    resolution: {integrity: sha512-4ghuAzjX4q8Nksm0aifRz8hgXMMxS0SuymrFfkfJlrSx68pIgvAge6AOw0edoZoe0Tf5ZbsWUWamhkNyNxkTvw==}
     engines: {node: '>=14.0.0'}
     cpu: [arm64]
     os: [win32]
@@ -7183,8 +6754,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-win32-ia32@1.85.0:
-    resolution: {integrity: sha512-PCyn6xeFIBUgBceNypuf73/5DWF2VWPlPqPuBprPsTvpZOMUJeBtP+Lf4mnu3dNy1z76mYVnpaCnQmzZ0zHZaA==}
+  /sass-embedded-win32-ia32@1.86.3:
+    resolution: {integrity: sha512-tCaK4zIRq9mLRPxLzBAdYlfCuS/xLNpmjunYxeWkIwlJo+k53h1udyXH/FInnQ2GgEz0xMXyvH3buuPgzwWYsw==}
     engines: {node: '>=14.0.0'}
     cpu: [ia32]
     os: [win32]
@@ -7192,8 +6763,8 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded-win32-x64@1.85.0:
-    resolution: {integrity: sha512-AknE2jLp6OBwrR5hQ8pDsG94KhJCeSheFJ2xgbnk8RUjZX909JiNbgh2sNt9LG+RXf4xZa55dDL537gZoCx/iw==}
+  /sass-embedded-win32-x64@1.86.3:
+    resolution: {integrity: sha512-zS+YNKfTF4SnOfpC77VTb0qNZyTXrxnAezSoRV0xnw6HlY+1WawMSSB6PbWtmbvyfXNgpmJUttoTtsvJjRCucg==}
     engines: {node: '>=14.0.0'}
     cpu: [x64]
     os: [win32]
@@ -7201,49 +6772,49 @@ packages:
     dev: true
     optional: true
 
-  /sass-embedded@1.85.0:
-    resolution: {integrity: sha512-x3Vv54g0jv1aPSW8OTA/0GzQCs/HMQOjIkLtZJ3Xsn/I4vnyjKbVTQmFTax9bQjldqLEEkdbvy6ES/cOOnYNwA==}
+  /sass-embedded@1.86.3:
+    resolution: {integrity: sha512-3pZSp24ibO1hdopj+W9DuiWsZOb2YY6AFRo/jjutKLBkqJGM1nJjXzhAYfzRV+Xn5BX1eTI4bBTE09P0XNHOZg==}
     engines: {node: '>=16.0.0'}
     hasBin: true
     dependencies:
-      '@bufbuild/protobuf': 2.2.3
+      '@bufbuild/protobuf': 2.2.5
       buffer-builder: 0.2.0
       colorjs.io: 0.5.2
-      immutable: 5.0.3
-      rxjs: 7.8.1
+      immutable: 5.1.1
+      rxjs: 7.8.2
       supports-color: 8.1.1
       sync-child-process: 1.0.2
       varint: 6.0.0
     optionalDependencies:
-      sass-embedded-android-arm: 1.85.0
-      sass-embedded-android-arm64: 1.85.0
-      sass-embedded-android-ia32: 1.85.0
-      sass-embedded-android-riscv64: 1.85.0
-      sass-embedded-android-x64: 1.85.0
-      sass-embedded-darwin-arm64: 1.85.0
-      sass-embedded-darwin-x64: 1.85.0
-      sass-embedded-linux-arm: 1.85.0
-      sass-embedded-linux-arm64: 1.85.0
-      sass-embedded-linux-ia32: 1.85.0
-      sass-embedded-linux-musl-arm: 1.85.0
-      sass-embedded-linux-musl-arm64: 1.85.0
-      sass-embedded-linux-musl-ia32: 1.85.0
-      sass-embedded-linux-musl-riscv64: 1.85.0
-      sass-embedded-linux-musl-x64: 1.85.0
-      sass-embedded-linux-riscv64: 1.85.0
-      sass-embedded-linux-x64: 1.85.0
-      sass-embedded-win32-arm64: 1.85.0
-      sass-embedded-win32-ia32: 1.85.0
-      sass-embedded-win32-x64: 1.85.0
+      sass-embedded-android-arm: 1.86.3
+      sass-embedded-android-arm64: 1.86.3
+      sass-embedded-android-ia32: 1.86.3
+      sass-embedded-android-riscv64: 1.86.3
+      sass-embedded-android-x64: 1.86.3
+      sass-embedded-darwin-arm64: 1.86.3
+      sass-embedded-darwin-x64: 1.86.3
+      sass-embedded-linux-arm: 1.86.3
+      sass-embedded-linux-arm64: 1.86.3
+      sass-embedded-linux-ia32: 1.86.3
+      sass-embedded-linux-musl-arm: 1.86.3
+      sass-embedded-linux-musl-arm64: 1.86.3
+      sass-embedded-linux-musl-ia32: 1.86.3
+      sass-embedded-linux-musl-riscv64: 1.86.3
+      sass-embedded-linux-musl-x64: 1.86.3
+      sass-embedded-linux-riscv64: 1.86.3
+      sass-embedded-linux-x64: 1.86.3
+      sass-embedded-win32-arm64: 1.86.3
+      sass-embedded-win32-ia32: 1.86.3
+      sass-embedded-win32-x64: 1.86.3
     dev: true
 
-  /sass@1.85.0:
-    resolution: {integrity: sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==}
+  /sass@1.86.3:
+    resolution: {integrity: sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==}
     engines: {node: '>=14.0.0'}
     hasBin: true
     dependencies:
       chokidar: 4.0.3
-      immutable: 5.0.3
+      immutable: 5.1.1
       source-map-js: 1.2.1
     optionalDependencies:
       '@parcel/watcher': 2.5.1
@@ -7253,12 +6824,12 @@ packages:
     resolution: {integrity: sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==}
     dev: true
 
-  /scheduler@0.25.0:
-    resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
+  /sax@1.4.1:
+    resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
     dev: true
 
-  /search-insights@2.17.3:
-    resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==}
+  /scheduler@0.26.0:
+    resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
     dev: true
 
   /selfsigned@2.4.1:
@@ -7326,6 +6897,37 @@ packages:
     resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
     dev: true
 
+  /set-function-length@1.2.2:
+    resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+    engines: {node: '>= 0.4'}
+    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
+    dev: true
+
+  /set-function-name@2.0.2:
+    resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-data-property: 1.1.4
+      es-errors: 1.3.0
+      functions-have-names: 1.2.3
+      has-property-descriptors: 1.0.2
+    dev: true
+
+  /set-proto@1.0.0:
+    resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      dunder-proto: 1.0.1
+      es-errors: 1.3.0
+      es-object-atoms: 1.1.1
+    dev: true
+
   /setprototypeof@1.2.0:
     resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
 
@@ -7346,19 +6948,6 @@ packages:
     resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
     engines: {node: '>=8'}
 
-  /shiki@2.5.0:
-    resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==}
-    dependencies:
-      '@shikijs/core': 2.5.0
-      '@shikijs/engine-javascript': 2.5.0
-      '@shikijs/engine-oniguruma': 2.5.0
-      '@shikijs/langs': 2.5.0
-      '@shikijs/themes': 2.5.0
-      '@shikijs/types': 2.5.0
-      '@shikijs/vscode-textmate': 10.0.2
-      '@types/hast': 3.0.4
-    dev: true
-
   /side-channel-list@1.0.0:
     resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
     engines: {node: '>= 0.4'}
@@ -7370,18 +6959,18 @@ packages:
     resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
     engines: {node: '>= 0.4'}
     dependencies:
-      call-bound: 1.0.3
+      call-bound: 1.0.4
       es-errors: 1.3.0
-      get-intrinsic: 1.2.7
+      get-intrinsic: 1.3.0
       object-inspect: 1.13.4
 
   /side-channel-weakmap@1.0.2:
     resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
     engines: {node: '>= 0.4'}
     dependencies:
-      call-bound: 1.0.3
+      call-bound: 1.0.4
       es-errors: 1.3.0
-      get-intrinsic: 1.2.7
+      get-intrinsic: 1.3.0
       object-inspect: 1.13.4
       side-channel-map: 1.0.1
 
@@ -7407,6 +6996,15 @@ packages:
     engines: {node: '>=14'}
     dev: true
 
+  /sirv@3.0.1:
+    resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
+    engines: {node: '>=18'}
+    dependencies:
+      '@polka/url': 1.0.0-next.28
+      mrmime: 2.0.1
+      totalist: 3.0.1
+    dev: true
+
   /slash@3.0.0:
     resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
     engines: {node: '>=8'}
@@ -7489,15 +7087,6 @@ packages:
     engines: {node: '>= 8'}
     dev: true
 
-  /space-separated-tokens@2.0.2:
-    resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
-    dev: true
-
-  /speakingurl@14.0.1:
-    resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
   /split2@4.2.0:
     resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
     engines: {node: '>= 10.x'}
@@ -7532,8 +7121,8 @@ packages:
     resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
     engines: {node: '>= 0.8'}
 
-  /std-env@3.8.0:
-    resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
+  /std-env@3.9.0:
+    resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
     dev: true
 
   /streamx@2.22.0:
@@ -7561,6 +7150,38 @@ packages:
       emoji-regex: 9.2.2
       strip-ansi: 7.1.0
 
+  /string.prototype.trim@1.2.10:
+    resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      define-data-property: 1.1.4
+      define-properties: 1.2.1
+      es-abstract: 1.23.9
+      es-object-atoms: 1.1.1
+      has-property-descriptors: 1.0.2
+    dev: true
+
+  /string.prototype.trimend@1.0.9:
+    resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      call-bound: 1.0.4
+      define-properties: 1.2.1
+      es-object-atoms: 1.1.1
+    dev: true
+
+  /string.prototype.trimstart@1.0.8:
+    resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      define-properties: 1.2.1
+      es-object-atoms: 1.1.1
+    dev: true
+
   /string_decoder@1.1.1:
     resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
     dependencies:
@@ -7572,13 +7193,6 @@ packages:
       safe-buffer: 5.2.1
     dev: true
 
-  /stringify-entities@4.0.4:
-    resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
-    dependencies:
-      character-entities-html4: 2.1.0
-      character-entities-legacy: 3.0.0
-    dev: true
-
   /strip-ansi@6.0.1:
     resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
     engines: {node: '>=8'}
@@ -7613,13 +7227,6 @@ packages:
   /strip-json-comments@3.1.1:
     resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
     engines: {node: '>=8'}
-    dev: true
-
-  /strip-literal@1.3.0:
-    resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==}
-    dependencies:
-      acorn: 8.14.0
-    dev: true
 
   /style-mod@4.1.2:
     resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
@@ -7635,17 +7242,10 @@ packages:
       glob: 10.4.5
       lines-and-columns: 1.2.4
       mz: 2.7.0
-      pirates: 4.0.6
+      pirates: 4.0.7
       ts-interface-checker: 0.1.13
     dev: true
 
-  /superjson@2.2.2:
-    resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==}
-    engines: {node: '>=16'}
-    dependencies:
-      copy-anything: 3.0.5
-    dev: true
-
   /supports-color@7.2.0:
     resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
     engines: {node: '>=8'}
@@ -7659,6 +7259,11 @@ packages:
     dependencies:
       has-flag: 4.0.0
 
+  /supports-preserve-symlinks-flag@1.0.0:
+    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
   /sync-child-process@1.0.2:
     resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==}
     engines: {node: '>=16.0.0'}
@@ -7671,10 +7276,6 @@ packages:
     engines: {node: '>=16.0.0'}
     dev: true
 
-  /tabbable@6.2.0:
-    resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
-    dev: true
-
   /tar-stream@3.1.7:
     resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
     dependencies:
@@ -7699,7 +7300,7 @@ packages:
     hasBin: true
     dependencies:
       '@jridgewell/source-map': 0.3.6
-      acorn: 8.14.0
+      acorn: 8.14.1
       commander: 2.20.3
       source-map-support: 0.5.21
     dev: true
@@ -7752,13 +7353,18 @@ packages:
       picomatch: 4.0.2
     dev: true
 
-  /tinypool@0.7.0:
-    resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==}
+  /tinypool@1.0.2:
+    resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    dev: true
+
+  /tinyrainbow@2.0.0:
+    resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
     engines: {node: '>=14.0.0'}
     dev: true
 
-  /tinyspy@2.2.1:
-    resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
+  /tinyspy@3.0.2:
+    resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
     engines: {node: '>=14.0.0'}
     dev: true
 
@@ -7767,15 +7373,15 @@ packages:
     engines: {node: '>=12'}
     dev: false
 
-  /tldts-core@6.1.78:
-    resolution: {integrity: sha512-jS0svNsB99jR6AJBmfmEWuKIgz91Haya91Z43PATaeHJ24BkMoNRb/jlaD37VYjb0mYf6gRL/HOnvS1zEnYBiw==}
+  /tldts-core@6.1.85:
+    resolution: {integrity: sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA==}
     dev: true
 
-  /tldts@6.1.78:
-    resolution: {integrity: sha512-fSgYrW0ITH0SR/CqKMXIruYIPpNu5aDgUp22UhYoSrnUQwc7SBqifEBFNce7AAcygUPBo6a/gbtcguWdmko4RQ==}
+  /tldts@6.1.85:
+    resolution: {integrity: sha512-gBdZ1RjCSevRPFix/hpaUWeak2/RNUZB4/8frF1r5uYMHjFptkiT0JXIebWvgI/0ZHXvxaUDDJshiA0j6GdL3w==}
     hasBin: true
     dependencies:
-      tldts-core: 6.1.78
+      tldts-core: 6.1.85
     dev: true
 
   /tmp@0.0.33:
@@ -7799,11 +7405,16 @@ packages:
     resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
     engines: {node: '>=0.6'}
 
-  /tough-cookie@5.1.1:
-    resolution: {integrity: sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==}
+  /totalist@3.0.1:
+    resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /tough-cookie@5.1.2:
+    resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
     engines: {node: '>=16'}
     dependencies:
-      tldts: 6.1.78
+      tldts: 6.1.85
     dev: true
 
   /tree-kill@1.2.2:
@@ -7811,11 +7422,7 @@ packages:
     hasBin: true
     dev: true
 
-  /trim-lines@3.0.1:
-    resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
-    dev: true
-
-  /ts-essentials@9.4.2(typescript@5.7.3):
+  /ts-essentials@9.4.2(typescript@5.8.3):
     resolution: {integrity: sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ==}
     peerDependencies:
       typescript: '>=4.1.0'
@@ -7823,14 +7430,14 @@ packages:
       typescript:
         optional: true
     dependencies:
-      typescript: 5.7.3
+      typescript: 5.8.3
     dev: true
 
   /ts-interface-checker@0.1.13:
     resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
     dev: true
 
-  /tsconfck@3.1.5(typescript@5.7.3):
+  /tsconfck@3.1.5(typescript@5.8.3):
     resolution: {integrity: sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==}
     engines: {node: ^18 || >=20}
     hasBin: true
@@ -7840,7 +7447,7 @@ packages:
       typescript:
         optional: true
     dependencies:
-      typescript: 5.7.3
+      typescript: 5.8.3
     dev: true
 
   /tsconfig-paths@3.15.0:
@@ -7882,11 +7489,6 @@ packages:
       prelude-ls: 1.2.1
     dev: true
 
-  /type-detect@4.1.0:
-    resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==}
-    engines: {node: '>=4'}
-    dev: true
-
   /type-fest@0.20.2:
     resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
     engines: {node: '>=10'}
@@ -7907,8 +7509,8 @@ packages:
     engines: {node: '>=12.20'}
     dev: false
 
-  /type-fest@4.35.0:
-    resolution: {integrity: sha512-2/AwEFQDFEy30iOLjrvHDIH7e4HEWH+f1Yl1bI5XMqzuoCUqwYCdxachgsgv0og/JdVZUhbfjcJAoHj5L1753A==}
+  /type-fest@4.39.1:
+    resolution: {integrity: sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w==}
     engines: {node: '>=16'}
     dev: true
 
@@ -7919,6 +7521,51 @@ packages:
       media-typer: 0.3.0
       mime-types: 2.1.35
 
+  /typed-array-buffer@1.0.3:
+    resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      is-typed-array: 1.1.15
+    dev: true
+
+  /typed-array-byte-length@1.0.3:
+    resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      for-each: 0.3.5
+      gopd: 1.2.0
+      has-proto: 1.2.0
+      is-typed-array: 1.1.15
+    dev: true
+
+  /typed-array-byte-offset@1.0.4:
+    resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.8
+      for-each: 0.3.5
+      gopd: 1.2.0
+      has-proto: 1.2.0
+      is-typed-array: 1.1.15
+      reflect.getprototypeof: 1.0.10
+    dev: true
+
+  /typed-array-length@1.0.7:
+    resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.8
+      for-each: 0.3.5
+      gopd: 1.2.0
+      is-typed-array: 1.1.15
+      possible-typed-array-names: 1.1.0
+      reflect.getprototypeof: 1.0.10
+    dev: true
+
   /typedarray-to-buffer@3.1.5:
     resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
     dependencies:
@@ -7929,13 +7576,13 @@ packages:
     resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
     dev: false
 
-  /typescript@5.7.3:
-    resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
+  /typescript@5.8.3:
+    resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
     engines: {node: '>=14.17'}
     hasBin: true
 
-  /ufo@1.5.4:
-    resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
+  /ufo@1.6.0:
+    resolution: {integrity: sha512-AkgU2cV/+Xb4Uz6cic0kMZbtM42nbltnGvTVOt/8gMCbO2/z64nE47TOygh7HjgFPkUkVRBEyNFqpqi3zo+BJA==}
     dev: true
 
   /uglify-js@3.19.3:
@@ -7946,8 +7593,18 @@ packages:
     dev: true
     optional: true
 
-  /undici-types@6.20.0:
-    resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
+  /unbox-primitive@1.1.0:
+    resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      has-bigints: 1.1.0
+      has-symbols: 1.1.0
+      which-boxed-primitive: 1.1.1
+    dev: true
+
+  /undici-types@6.21.0:
+    resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
 
   /unicorn-magic@0.1.0:
     resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
@@ -7961,39 +7618,6 @@ packages:
       crypto-random-string: 4.0.0
     dev: false
 
-  /unist-util-is@6.0.0:
-    resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
-    dependencies:
-      '@types/unist': 3.0.3
-    dev: true
-
-  /unist-util-position@5.0.0:
-    resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
-    dependencies:
-      '@types/unist': 3.0.3
-    dev: true
-
-  /unist-util-stringify-position@4.0.0:
-    resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
-    dependencies:
-      '@types/unist': 3.0.3
-    dev: true
-
-  /unist-util-visit-parents@6.0.1:
-    resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
-    dependencies:
-      '@types/unist': 3.0.3
-      unist-util-is: 6.0.0
-    dev: true
-
-  /unist-util-visit@5.0.0:
-    resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
-    dependencies:
-      '@types/unist': 3.0.3
-      unist-util-is: 6.0.0
-      unist-util-visit-parents: 6.0.1
-    dev: true
-
   /universalify@0.1.2:
     resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
     engines: {node: '>= 4.0.0'}
@@ -8011,7 +7635,7 @@ packages:
     resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==}
     engines: {node: '>=14.0.0'}
     dependencies:
-      acorn: 8.14.0
+      acorn: 8.14.1
       webpack-virtual-modules: 0.6.2
     dev: true
 
@@ -8019,8 +7643,8 @@ packages:
     resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
     engines: {node: '>=8'}
 
-  /update-browserslist-db@1.1.2(browserslist@4.24.4):
-    resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
+  /update-browserslist-db@1.1.3(browserslist@4.24.4):
+    resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
     hasBin: true
     peerDependencies:
       browserslist: '>= 4.21.0'
@@ -8054,7 +7678,6 @@ packages:
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
     dependencies:
       punycode: 2.3.1
-    dev: true
 
   /util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -8068,8 +7691,8 @@ packages:
     hasBin: true
     dev: true
 
-  /validator@13.12.0:
-    resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==}
+  /validator@13.15.0:
+    resolution: {integrity: sha512-36B2ryl4+oL5QxZ3AzD0t5SsMNGvTtQHpjgFO5tbNxfXbMFkY822ktCDe1MnlqV3301QQI9SLHDNJokDI+Z9pA==}
     engines: {node: '>= 0.10'}
 
   /varint@6.0.0:
@@ -8089,21 +7712,7 @@ packages:
       extsprintf: 1.3.0
     dev: true
 
-  /vfile-message@4.0.2:
-    resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
-    dependencies:
-      '@types/unist': 3.0.3
-      unist-util-stringify-position: 4.0.0
-    dev: true
-
-  /vfile@6.0.3:
-    resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
-    dependencies:
-      '@types/unist': 3.0.3
-      vfile-message: 4.0.2
-    dev: true
-
-  /vite-jsconfig-paths@2.0.1(vite@6.2.0):
+  /vite-jsconfig-paths@2.0.1(vite@6.2.5):
     resolution: {integrity: sha512-rabcTTfKs0MdAsQWcZjbIMo5fcp6jthZce7uFEPgVPgpSY+RNOwjzIJOPES6cB/GJZLSoLGfHM9kt5HNmJvp7A==}
     peerDependencies:
       vite: '>2.0.0-0'
@@ -8112,24 +7721,24 @@ packages:
       globrex: 0.1.2
       recrawl-sync: 2.2.3
       tsconfig-paths: 3.15.0
-      vite: 6.2.0(@types/node@22.13.5)(sass@1.85.0)
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /vite-node@0.34.6(@types/node@22.13.4)(sass@1.85.0):
-    resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
-    engines: {node: '>=v14.18.0'}
+  /vite-node@3.1.1(@types/node@22.14.0)(sass@1.86.3):
+    resolution: {integrity: sha512-V+IxPAE2FvXpTCHXyNem0M+gWm6J7eRyWPR6vYoG/Gl+IscNOjXzztUhimQgTxaAoUoj40Qqimaa0NLIOOAH4w==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
     hasBin: true
     dependencies:
       cac: 6.7.14
       debug: 4.4.0(supports-color@8.1.1)
-      mlly: 1.7.4
-      pathe: 1.1.2
-      picocolors: 1.1.1
-      vite: 5.4.14(@types/node@22.13.4)(sass@1.85.0)
+      es-module-lexer: 1.6.0
+      pathe: 2.0.3
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
     transitivePeerDependencies:
       - '@types/node'
+      - jiti
       - less
       - lightningcss
       - sass
@@ -8138,9 +7747,11 @@ packages:
       - sugarss
       - supports-color
       - terser
+      - tsx
+      - yaml
     dev: true
 
-  /vite-tsconfig-paths@4.3.2(typescript@5.7.3)(vite@6.2.0):
+  /vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@6.2.5):
     resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==}
     peerDependencies:
       vite: '*'
@@ -8150,95 +7761,15 @@ packages:
     dependencies:
       debug: 4.4.0(supports-color@8.1.1)
       globrex: 0.1.2
-      tsconfck: 3.1.5(typescript@5.7.3)
-      vite: 6.2.0(@types/node@22.13.5)(sass@1.85.0)
+      tsconfck: 3.1.5(typescript@5.8.3)
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
     transitivePeerDependencies:
       - supports-color
       - typescript
     dev: true
 
-  /vite@5.4.14(@types/node@22.13.4)(sass@1.85.0):
-    resolution: {integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==}
-    engines: {node: ^18.0.0 || >=20.0.0}
-    hasBin: true
-    peerDependencies:
-      '@types/node': ^18.0.0 || >=20.0.0
-      less: '*'
-      lightningcss: ^1.21.0
-      sass: '*'
-      sass-embedded: '*'
-      stylus: '*'
-      sugarss: '*'
-      terser: ^5.4.0
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-      less:
-        optional: true
-      lightningcss:
-        optional: true
-      sass:
-        optional: true
-      sass-embedded:
-        optional: true
-      stylus:
-        optional: true
-      sugarss:
-        optional: true
-      terser:
-        optional: true
-    dependencies:
-      '@types/node': 22.13.4
-      esbuild: 0.21.5
-      postcss: 8.5.3
-      rollup: 4.34.8
-      sass: 1.85.0
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
-  /vite@5.4.14(@types/node@22.13.5)(sass@1.85.0):
-    resolution: {integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==}
-    engines: {node: ^18.0.0 || >=20.0.0}
-    hasBin: true
-    peerDependencies:
-      '@types/node': ^18.0.0 || >=20.0.0
-      less: '*'
-      lightningcss: ^1.21.0
-      sass: '*'
-      sass-embedded: '*'
-      stylus: '*'
-      sugarss: '*'
-      terser: ^5.4.0
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-      less:
-        optional: true
-      lightningcss:
-        optional: true
-      sass:
-        optional: true
-      sass-embedded:
-        optional: true
-      stylus:
-        optional: true
-      sugarss:
-        optional: true
-      terser:
-        optional: true
-    dependencies:
-      '@types/node': 22.13.5
-      esbuild: 0.21.5
-      postcss: 8.5.3
-      rollup: 4.34.8
-      sass: 1.85.0
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
-  /vite@6.1.1(@types/node@22.13.5)(sass-embedded@1.85.0)(sass@1.85.0):
-    resolution: {integrity: sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==}
+  /vite@6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3):
+    resolution: {integrity: sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==}
     engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
     hasBin: true
     peerDependencies:
@@ -8277,140 +7808,35 @@ packages:
       yaml:
         optional: true
     dependencies:
-      '@types/node': 22.13.5
-      esbuild: 0.24.2
+      '@types/node': 22.14.0
+      esbuild: 0.25.2
       postcss: 8.5.3
-      rollup: 4.34.8
-      sass: 1.85.0
-      sass-embedded: 1.85.0
+      rollup: 4.39.0
+      sass: 1.86.3
+      sass-embedded: 1.86.3
     optionalDependencies:
       fsevents: 2.3.3
     dev: true
 
-  /vite@6.2.0(@types/node@22.13.5)(sass@1.85.0):
-    resolution: {integrity: sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==}
+  /vitest@3.1.1(@types/node@22.14.0)(@vitest/ui@3.1.1)(sass@1.86.3):
+    resolution: {integrity: sha512-kiZc/IYmKICeBAZr9DQ5rT7/6bD9G7uqQEki4fxazi1jdVl2mWGzedtBs5s6llz59yQhVb7FFY2MbHzHCnT79Q==}
     engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
     hasBin: true
-    peerDependencies:
-      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
-      jiti: '>=1.21.0'
-      less: '*'
-      lightningcss: ^1.21.0
-      sass: '*'
-      sass-embedded: '*'
-      stylus: '*'
-      sugarss: '*'
-      terser: ^5.16.0
-      tsx: ^4.8.1
-      yaml: ^2.4.2
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-      jiti:
-        optional: true
-      less:
-        optional: true
-      lightningcss:
-        optional: true
-      sass:
-        optional: true
-      sass-embedded:
-        optional: true
-      stylus:
-        optional: true
-      sugarss:
-        optional: true
-      terser:
-        optional: true
-      tsx:
-        optional: true
-      yaml:
-        optional: true
-    dependencies:
-      '@types/node': 22.13.5
-      esbuild: 0.25.0
-      postcss: 8.5.3
-      rollup: 4.34.8
-      sass: 1.85.0
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
-  /vitepress@1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(react-dom@19.0.0)(react@19.0.0)(sass@1.85.0)(search-insights@2.17.3)(typescript@5.7.3):
-    resolution: {integrity: sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw==}
-    hasBin: true
-    peerDependencies:
-      markdown-it-mathjax3: ^4
-      postcss: ^8
-    peerDependenciesMeta:
-      markdown-it-mathjax3:
-        optional: true
-      postcss:
-        optional: true
-    dependencies:
-      '@docsearch/css': 3.8.2
-      '@docsearch/js': 3.8.2(@algolia/client-search@5.20.3)(react-dom@19.0.0)(react@19.0.0)(search-insights@2.17.3)
-      '@iconify-json/simple-icons': 1.2.25
-      '@shikijs/core': 2.5.0
-      '@shikijs/transformers': 2.5.0
-      '@shikijs/types': 2.5.0
-      '@types/markdown-it': 14.1.2
-      '@vitejs/plugin-vue': 5.2.1(vite@5.4.14)(vue@3.5.13)
-      '@vue/devtools-api': 7.7.2
-      '@vue/shared': 3.5.13
-      '@vueuse/core': 12.7.0(typescript@5.7.3)
-      '@vueuse/integrations': 12.7.0(axios@1.7.9)(focus-trap@7.6.4)(typescript@5.7.3)
-      focus-trap: 7.6.4
-      mark.js: 8.11.1
-      minisearch: 7.1.2
-      postcss: 8.5.3
-      shiki: 2.5.0
-      vite: 5.4.14(@types/node@22.13.5)(sass@1.85.0)
-      vue: 3.5.13(typescript@5.7.3)
-    transitivePeerDependencies:
-      - '@algolia/client-search'
-      - '@types/node'
-      - '@types/react'
-      - async-validator
-      - axios
-      - change-case
-      - drauu
-      - fuse.js
-      - idb-keyval
-      - jwt-decode
-      - less
-      - lightningcss
-      - nprogress
-      - qrcode
-      - react
-      - react-dom
-      - sass
-      - sass-embedded
-      - search-insights
-      - sortablejs
-      - stylus
-      - sugarss
-      - terser
-      - typescript
-      - universal-cookie
-    dev: true
-
-  /vitest@0.34.6(sass@1.85.0):
-    resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==}
-    engines: {node: '>=v14.18.0'}
-    hasBin: true
     peerDependencies:
       '@edge-runtime/vm': '*'
-      '@vitest/browser': '*'
-      '@vitest/ui': '*'
+      '@types/debug': ^4.1.12
+      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+      '@vitest/browser': 3.1.1
+      '@vitest/ui': 3.1.1
       happy-dom: '*'
       jsdom: '*'
-      playwright: '*'
-      safaridriver: '*'
-      webdriverio: '*'
     peerDependenciesMeta:
       '@edge-runtime/vm':
         optional: true
+      '@types/debug':
+        optional: true
+      '@types/node':
+        optional: true
       '@vitest/browser':
         optional: true
       '@vitest/ui':
@@ -8419,50 +7845,46 @@ packages:
         optional: true
       jsdom:
         optional: true
-      playwright:
-        optional: true
-      safaridriver:
-        optional: true
-      webdriverio:
-        optional: true
     dependencies:
-      '@types/chai': 4.3.20
-      '@types/chai-subset': 1.3.5
-      '@types/node': 22.13.4
-      '@vitest/expect': 0.34.6
-      '@vitest/runner': 0.34.6
-      '@vitest/snapshot': 0.34.6
-      '@vitest/spy': 0.34.6
-      '@vitest/utils': 0.34.6
-      acorn: 8.14.0
-      acorn-walk: 8.3.4
-      cac: 6.7.14
-      chai: 4.5.0
+      '@types/node': 22.14.0
+      '@vitest/expect': 3.1.1
+      '@vitest/mocker': 3.1.1(vite@6.2.5)
+      '@vitest/pretty-format': 3.1.1
+      '@vitest/runner': 3.1.1
+      '@vitest/snapshot': 3.1.1
+      '@vitest/spy': 3.1.1
+      '@vitest/ui': 3.1.1(vitest@3.1.1)
+      '@vitest/utils': 3.1.1
+      chai: 5.2.0
       debug: 4.4.0(supports-color@8.1.1)
-      local-pkg: 0.4.3
+      expect-type: 1.2.1
       magic-string: 0.30.17
-      pathe: 1.1.2
-      picocolors: 1.1.1
-      std-env: 3.8.0
-      strip-literal: 1.3.0
+      pathe: 2.0.3
+      std-env: 3.9.0
       tinybench: 2.9.0
-      tinypool: 0.7.0
-      vite: 5.4.14(@types/node@22.13.4)(sass@1.85.0)
-      vite-node: 0.34.6(@types/node@22.13.4)(sass@1.85.0)
+      tinyexec: 0.3.2
+      tinypool: 1.0.2
+      tinyrainbow: 2.0.0
+      vite: 6.2.5(@types/node@22.14.0)(sass-embedded@1.86.3)(sass@1.86.3)
+      vite-node: 3.1.1(@types/node@22.14.0)(sass@1.86.3)
       why-is-node-running: 2.3.0
     transitivePeerDependencies:
+      - jiti
       - less
       - lightningcss
+      - msw
       - sass
       - sass-embedded
       - stylus
       - sugarss
       - supports-color
       - terser
+      - tsx
+      - yaml
     dev: true
 
-  /vue-component-type-helpers@2.2.2:
-    resolution: {integrity: sha512-6lLY+n2xz2kCYshl59mL6gy8OUUTmkscmDFMO8i7Lj+QKwgnIFUZmM1i/iTYObtrczZVdw7UakPqDTGwVSGaRg==}
+  /vue-component-type-helpers@2.2.8:
+    resolution: {integrity: sha512-4bjIsC284coDO9om4HPA62M7wfsTvcmZyzdfR0aUlFXqq4tXxM1APyXpNVxPC8QazKw9OhmZNHBVDA6ODaZsrA==}
     dev: true
 
   /vue-demi@0.14.10(vue@3.5.13):
@@ -8477,16 +7899,16 @@ packages:
       '@vue/composition-api':
         optional: true
     dependencies:
-      vue: 3.5.13(typescript@5.7.3)
+      vue: 3.5.13(typescript@5.8.3)
 
-  /vue-eslint-parser@9.4.3(eslint@9.20.1):
+  /vue-eslint-parser@9.4.3(eslint@9.24.0):
     resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
     engines: {node: ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: '>=6.0.0'
     dependencies:
       debug: 4.4.0(supports-color@8.1.1)
-      eslint: 9.20.1
+      eslint: 9.24.0
       eslint-scope: 7.2.2
       eslint-visitor-keys: 3.4.3
       espree: 9.6.1
@@ -8497,16 +7919,16 @@ packages:
       - supports-color
     dev: true
 
-  /vue-i18n@9.14.2(vue@3.5.13):
-    resolution: {integrity: sha512-JK9Pm80OqssGJU2Y6F7DcM8RFHqVG4WkuCqOZTVsXkEzZME7ABejAUqUdA931zEBedc4thBgSUWxeQh4uocJAQ==}
+  /vue-i18n@9.14.4(vue@3.5.13):
+    resolution: {integrity: sha512-B934C8yUyWLT0EMud3DySrwSUJI7ZNiWYsEEz2gknTthqKiG4dzWE/WSa8AzCuSQzwBEv4HtG1jZDhgzPfWSKQ==}
     engines: {node: '>= 16'}
     peerDependencies:
       vue: ^3.0.0
     dependencies:
-      '@intlify/core-base': 9.14.2
-      '@intlify/shared': 9.14.2
+      '@intlify/core-base': 9.14.4
+      '@intlify/shared': 9.14.4
       '@vue/devtools-api': 6.6.4
-      vue: 3.5.13(typescript@5.7.3)
+      vue: 3.5.13(typescript@5.8.3)
 
   /vue-router@4.5.0(vue@3.5.13):
     resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==}
@@ -8514,9 +7936,9 @@ packages:
       vue: ^3.2.0
     dependencies:
       '@vue/devtools-api': 6.6.4
-      vue: 3.5.13(typescript@5.7.3)
+      vue: 3.5.13(typescript@5.8.3)
 
-  /vue@3.5.13(typescript@5.7.3):
+  /vue@3.5.13(typescript@5.8.3):
     resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
     peerDependencies:
       typescript: '*'
@@ -8529,7 +7951,7 @@ packages:
       '@vue/runtime-dom': 3.5.13
       '@vue/server-renderer': 3.5.13(vue@3.5.13)
       '@vue/shared': 3.5.13
-      typescript: 5.7.3
+      typescript: 5.8.3
 
   /w3c-keyname@2.2.8:
     resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
@@ -8571,10 +7993,63 @@ packages:
     engines: {node: '>=12'}
     dev: true
 
+  /which-boxed-primitive@1.1.1:
+    resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      is-bigint: 1.1.0
+      is-boolean-object: 1.2.2
+      is-number-object: 1.1.1
+      is-string: 1.1.1
+      is-symbol: 1.1.1
+    dev: true
+
+  /which-builtin-type@1.2.1:
+    resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bound: 1.0.4
+      function.prototype.name: 1.1.8
+      has-tostringtag: 1.0.2
+      is-async-function: 2.1.1
+      is-date-object: 1.1.0
+      is-finalizationregistry: 1.1.1
+      is-generator-function: 1.1.0
+      is-regex: 1.2.1
+      is-weakref: 1.1.1
+      isarray: 2.0.5
+      which-boxed-primitive: 1.1.1
+      which-collection: 1.0.2
+      which-typed-array: 1.1.19
+    dev: true
+
+  /which-collection@1.0.2:
+    resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      is-map: 2.0.3
+      is-set: 2.0.3
+      is-weakmap: 2.0.2
+      is-weakset: 2.0.4
+    dev: true
+
   /which-module@2.0.1:
     resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
     dev: true
 
+  /which-typed-array@1.1.19:
+    resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
+    engines: {node: '>= 0.4'}
+    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
+    dev: true
+
   /which@2.0.2:
     resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
     engines: {node: '>= 8'}
@@ -8680,7 +8155,7 @@ packages:
     resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==}
     engines: {node: '>=4.0.0'}
     dependencies:
-      sax: 1.1.4
+      sax: 1.4.1
       xmlbuilder: 11.0.1
     dev: true
 
@@ -8689,11 +8164,17 @@ packages:
     engines: {node: '>=4.0'}
     dev: true
 
-  /xunit-viewer@10.6.1(@babel/runtime@7.26.9)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.3)(codemirror@6.0.1)(react-dom@19.0.0)(react@19.0.0):
+  /xmldoc@1.3.0:
+    resolution: {integrity: sha512-y7IRWW6PvEnYQZNZFMRLNJw+p3pezM4nKYPfr15g4OOW9i8VpeydycFuipE2297OvZnh3jSb2pxOt9QpkZUVng==}
+    dependencies:
+      sax: 1.4.1
+    dev: true
+
+  /xunit-viewer@10.6.1(@babel/runtime@7.27.0)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.5)(codemirror@6.0.1)(react-dom@19.1.0)(react@19.1.0):
     resolution: {integrity: sha512-ZMprLPVhCQJf2KD56tv2hlOjc4T+KnUe1E9DkEBHnuliOq7IOXWJf61pxyBMo/7H83B7Ln0DIeWNMMbx/3I7Jg==}
     hasBin: true
     dependencies:
-      '@uiw/react-codemirror': 4.23.8(@babel/runtime@7.26.9)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.4)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.3)(codemirror@6.0.1)(react-dom@19.0.0)(react@19.0.0)
+      '@uiw/react-codemirror': 4.23.10(@babel/runtime@7.27.0)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.10)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.5)(codemirror@6.0.1)(react-dom@19.1.0)(react@19.1.0)
       chalk: 5.4.1
       chokidar: 3.6.0
       console-clear: 1.1.1
@@ -8738,17 +8219,18 @@ packages:
     resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
     dev: false
 
-  /yaml-eslint-parser@0.3.2:
-    resolution: {integrity: sha512-32kYO6kJUuZzqte82t4M/gB6/+11WAuHiEnK7FreMo20xsCKPeFH5tDBU7iWxR7zeJpNnMXfJyXwne48D0hGrg==}
+  /yaml-eslint-parser@1.3.0:
+    resolution: {integrity: sha512-E/+VitOorXSLiAqtTd7Yqax0/pAS3xaYMP+AUUJGOK1OZG3rhcj9fcJOM5HJ2VrP1FrStVCWr1muTfQCdj4tAA==}
+    engines: {node: ^14.17.0 || >=16.0.0}
     dependencies:
-      eslint-visitor-keys: 1.3.0
-      lodash: 4.17.21
-      yaml: 1.10.2
+      eslint-visitor-keys: 3.4.3
+      yaml: 2.7.1
     dev: true
 
-  /yaml@1.10.2:
-    resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
-    engines: {node: '>= 6'}
+  /yaml@2.7.1:
+    resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==}
+    engines: {node: '>= 14'}
+    hasBin: true
     dev: true
 
   /yargs-parser@18.1.3:
@@ -8815,8 +8297,8 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
-  /yocto-queue@1.1.1:
-    resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==}
+  /yocto-queue@1.2.1:
+    resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==}
     engines: {node: '>=12.20'}
     dev: true
 
@@ -8833,7 +8315,3 @@ packages:
       compress-commons: 6.0.2
       readable-stream: 4.7.0
     dev: true
-
-  /zwitch@2.0.4:
-    resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
-    dev: true
diff --git a/quasar.config.js b/quasar.config.js
index 8b6125a90..2bc0be37f 100644
--- a/quasar.config.js
+++ b/quasar.config.js
@@ -53,7 +53,7 @@ export default configure(function (/* ctx */) {
         build: {
             target: {
                 browser: ['es2022', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
-                node: 'node18',
+                node: 'node20',
             },
 
             vueRouterMode: 'hash', // available values: 'hash', 'history'
@@ -92,6 +92,7 @@ export default configure(function (/* ctx */) {
             vitePlugins: [
                 [
                     VueI18nPlugin({
+                        strictMessage: false,
                         runtimeOnly: false,
                         include: [
                             path.resolve(__dirname, './src/i18n/locale/**'),
diff --git a/quasar.config.js.temporary.compiled.1744020058024.mjs b/quasar.config.js.temporary.compiled.1744020058024.mjs
new file mode 100644
index 000000000..54ecb84d9
--- /dev/null
+++ b/quasar.config.js.temporary.compiled.1744020058024.mjs
@@ -0,0 +1,227 @@
+/* eslint-disable */
+/**
+ * THIS FILE IS GENERATED AUTOMATICALLY.
+ * 1. DO NOT edit this file directly as it won't do anything.
+ * 2. EDIT the original quasar.config file INSTEAD.
+ * 3. DO NOT git commit this file. It should be ignored.
+ *
+ * This file is still here because there was an error in
+ * the original quasar.config file and this allows you to
+ * investigate the Node.js stack error.
+ *
+ * After you fix the original file, this file will be
+ * deleted automatically.
+ **/
+
+
+// quasar.config.js
+import { configure } from "quasar/wrappers";
+import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
+import path from "path";
+var __quasar_inject_dirname__ = "/home/jsegarra/Projects/salix-front";
+var target = `http://${process.env.CI ? "back" : "localhost"}:3000`;
+var quasar_config_default = configure(function() {
+  return {
+    eslint: {
+      // fix: true,
+      // include = [],
+      // exclude = [],
+      // rawOptions = {},
+      warnings: true,
+      errors: true
+    },
+    // https://v2.quasar.dev/quasar-cli/prefetch-feature
+    // preFetch: true,
+    // app boot file (/src/boot)
+    // --> boot files are part of "main.js"
+    // https://v2.quasar.dev/quasar-cli/boot-files
+    boot: ["i18n", "axios", "vnDate", "validations", "quasar", "quasar.defaults"],
+    // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
+    css: ["app.scss"],
+    // https://github.com/quasarframework/quasar/tree/dev/extras
+    extras: [
+      // 'ionicons-v4',
+      // 'mdi-v5',
+      // 'fontawesome-v6',
+      // 'eva-icons',
+      // 'themify',
+      // 'line-awesome',
+      // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
+      "roboto-font",
+      "material-icons-outlined",
+      "material-symbols-outlined"
+    ],
+    // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
+    build: {
+      target: {
+        browser: ["es2022", "edge88", "firefox78", "chrome87", "safari13.1"],
+        node: "node20"
+      },
+      vueRouterMode: "hash",
+      // available values: 'hash', 'history'
+      // vueRouterBase,
+      // vueDevtools,
+      // vueOptionsAPI: false,
+      // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
+      // publicPath: '/',
+      // analyze: true,
+      // env: {},
+      rawDefine: {
+        "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
+      },
+      // ignorePublicFolder: true,
+      // minify: false,
+      // polyfillModulePreload: true,
+      // distDir
+      extendViteConf(viteConf) {
+        delete viteConf.build.polyfillModulePreload;
+        viteConf.build.modulePreload = {
+          polyfill: false
+        };
+      },
+      // viteVuePluginOptions: {},
+      alias: {
+        composables: path.join(__quasar_inject_dirname__, "./src/composables"),
+        filters: path.join(__quasar_inject_dirname__, "./src/filters")
+      },
+      vitePlugins: [
+        [
+          VueI18nPlugin({
+            strictMessage: false,
+            runtimeOnly: false,
+            include: [
+              path.resolve(__quasar_inject_dirname__, "./src/i18n/locale/**"),
+              path.resolve(__quasar_inject_dirname__, "./src/pages/**/locale/**")
+            ]
+          })
+        ]
+      ]
+    },
+    // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
+    devServer: {
+      server: {
+        type: "http"
+      },
+      proxy: {
+        "/api": {
+          target,
+          logLevel: "debug",
+          changeOrigin: true,
+          secure: false
+        }
+      },
+      open: false,
+      allowedHosts: [
+        "front",
+        // Agrega este nombre de host
+        "localhost"
+        // Opcional, para pruebas locales
+      ]
+    },
+    // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
+    framework: {
+      config: {
+        config: {
+          dark: "auto"
+        }
+      },
+      lang: "en-GB",
+      // iconSet: 'material-icons', // Quasar icon set
+      // lang: 'en-US', // Quasar language pack
+      // For special cases outside of where the auto-import strategy can have an impact
+      // (like functional components as one of the examples),
+      // you can manually specify Quasar components/directives to be available everywhere:
+      //
+      // components: [],
+      // directives: [],
+      // Quasar plugins
+      plugins: ["Notify", "Dialog"],
+      all: "auto",
+      autoImportComponentCase: "pascal"
+    },
+    // animations: 'all', // --- includes all animations
+    // https://v2.quasar.dev/options/animations
+    animations: [],
+    // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles
+    // sourceFiles: {
+    //   rootComponent: 'src/App.vue',
+    //   router: 'src/router/index',
+    //   store: 'src/store/index',
+    //   registerServiceWorker: 'src-pwa/register-service-worker',
+    //   serviceWorker: 'src-pwa/custom-service-worker',
+    //   pwaManifestFile: 'src-pwa/manifest.json',
+    //   electronMain: 'src-electron/electron-main',
+    //   electronPreload: 'src-electron/electron-preload'
+    // },
+    // https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
+    ssr: {
+      // ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
+      // will mess up SSR
+      // extendSSRWebserverConf (esbuildConf) {},
+      // extendPackageJson (json) {},
+      pwa: false,
+      // manualStoreHydration: true,
+      // manualPostHydrationTrigger: true,
+      prodPort: 3e3,
+      // The default port that the production server should use
+      // (gets superseded if process.env.PORT is specified at runtime)
+      middlewares: [
+        "render"
+        // keep this as last one
+      ]
+    },
+    // https://v2.quasar.dev/quasar-cli/developing-pwa/configuring-pwa
+    pwa: {
+      workboxMode: "generateSW",
+      // or 'injectManifest'
+      injectPwaMetaTags: true,
+      swFilename: "sw.js",
+      manifestFilename: "manifest.json",
+      useCredentialsForManifestTag: false
+      // useFilenameHashes: true,
+      // extendGenerateSWOptions (cfg) {}
+      // extendInjectManifestOptions (cfg) {},
+      // extendManifestJson (json) {}
+      // extendPWACustomSWConf (esbuildConf) {}
+    },
+    // Full list of options: https://v2.quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
+    cordova: {
+      // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
+    },
+    // Full list of options: https://v2.quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
+    capacitor: {
+      hideSplashscreen: true
+    },
+    // Full list of options: https://v2.quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
+    electron: {
+      // extendElectronMainConf (esbuildConf)
+      // extendElectronPreloadConf (esbuildConf)
+      inspectPort: 5858,
+      bundler: "packager",
+      // 'packager' or 'builder'
+      packager: {
+        // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
+        // OS X / Mac App Store
+        // appBundleId: '',
+        // appCategoryType: '',
+        // osxSign: '',
+        // protocol: 'myapp://path',
+        // Windows only
+        // win32metadata: { ... }
+      },
+      builder: {
+        // https://www.electron.build/configuration/configuration
+        appId: "salix-frontend"
+      }
+    },
+    // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
+    bex: {
+      contentScripts: ["my-content-script"]
+      // extendBexScriptsConf (esbuildConf) {}
+      // extendBexManifestJson (json) {}
+    }
+  };
+});
+export {
+  quasar_config_default as default
+};
diff --git a/src/boot/__tests__/axios.spec.js b/src/boot/__tests__/axios.spec.js
index 7dffaefc1..85d578517 100644
--- a/src/boot/__tests__/axios.spec.js
+++ b/src/boot/__tests__/axios.spec.js
@@ -9,6 +9,30 @@ vi.mock('src/composables/useSession', () => ({
     }),
 }));
 
+// Mock axios
+vi.mock('axios', () => ({
+    default: {
+        create: vi.fn(() => ({
+            interceptors: {
+                request: { use: vi.fn() },
+                response: { use: vi.fn() },
+            },
+        })),
+        interceptors: {
+            request: { use: vi.fn() },
+            response: { use: vi.fn() },
+        },
+        defaults: {
+            baseURL: '',
+        },
+    },
+}));
+
+vi.mock('src/router', () => ({
+    Router: {
+        push: vi.fn(),
+    },
+}));
 vi.mock('src/stores/useStateQueryStore', () => ({
     useStateQueryStore: () => ({
         add: () => vi.fn(),
@@ -29,7 +53,7 @@ describe('Axios boot', () => {
                         'Accept-Language': 'en-US',
                         Authorization: 'DEFAULT_TOKEN',
                     },
-                })
+                }),
             );
         });
     });
diff --git a/src/boot/quasar.defaults.js b/src/boot/quasar.defaults.js
index 9638e2057..e2b195b16 100644
--- a/src/boot/quasar.defaults.js
+++ b/src/boot/quasar.defaults.js
@@ -1,3 +1,4 @@
+/* eslint-disable eslint/export */
 export * from './defaults/qTable';
 export * from './defaults/qInput';
 export * from './defaults/qSelect';
diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue
index 8d7188f77..1d49d1d75 100644
--- a/src/components/CrudModel.vue
+++ b/src/components/CrudModel.vue
@@ -181,9 +181,8 @@ async function saveChanges(data) {
         return;
     }
     let changes = data || getChanges();
-    if ($props.beforeSaveFn) {
-        changes = await $props.beforeSaveFn(changes, getChanges);
-    }
+    if ($props.beforeSaveFn) changes = await $props.beforeSaveFn(changes, getChanges);
+
     try {
         if (changes?.creates?.length === 0 && changes?.updates?.length === 0) {
             return;
@@ -194,7 +193,7 @@ async function saveChanges(data) {
         isLoading.value = false;
     }
     originalData.value = JSON.parse(JSON.stringify(formData.value));
-    if (changes.creates?.length) await vnPaginateRef.value.fetch();
+    if (changes?.creates?.length) await vnPaginateRef.value.fetch();
 
     hasChanges.value = false;
     emit('saveChanges', data);
@@ -333,6 +332,7 @@ watch(formUrl, async () => {
                 :disable="!selected?.length"
                 :title="t('globals.remove')"
                 v-if="$props.defaultRemove"
+                data-cy="crudModelDefaultRemoveBtn"
             />
             <QBtn
                 :label="tMobile('globals.reset')"
diff --git a/src/components/FilterItemForm.vue b/src/components/FilterItemForm.vue
index cacfde1b3..cca8d80c3 100644
--- a/src/components/FilterItemForm.vue
+++ b/src/components/FilterItemForm.vue
@@ -188,7 +188,7 @@ const selectItem = ({ id }) => {
             >
                 <template #body-cell-id="{ row }">
                     <QTd auto-width @click.stop>
-                        <QBtn flat color="blue">{{ row.id }}</QBtn>
+                        <QBtn flat class="link">{{ row.id }}</QBtn>
                         <ItemDescriptorProxy :id="row.id" />
                     </QTd>
                 </template>
diff --git a/src/components/FilterTravelForm.vue b/src/components/FilterTravelForm.vue
index c522d0269..4aad327b2 100644
--- a/src/components/FilterTravelForm.vue
+++ b/src/components/FilterTravelForm.vue
@@ -196,7 +196,7 @@ const selectTravel = ({ id }) => {
             >
                 <template #body-cell-id="{ row }">
                     <QTd auto-width @click.stop data-cy="travelFk-travel-form">
-                        <QBtn flat color="blue">{{ row.id }}</QBtn>
+                        <QBtn flat class="link">{{ row.id }}</QBtn>
                         <TravelDescriptorProxy :id="row.id" />
                     </QTd>
                 </template>
diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index c4d9a4149..1fec1e6c9 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -13,13 +13,12 @@ import VnConfirm from './ui/VnConfirm.vue';
 import { tMobile } from 'src/composables/tMobile';
 import { useArrayData } from 'src/composables/useArrayData';
 import { getDifferences, getUpdatedValues } from 'src/filters';
-
 const { push } = useRouter();
 const quasar = useQuasar();
 const state = useState();
 const stateStore = useStateStore();
 const { t } = useI18n();
-const { validate } = useValidator();
+const { validate, validations } = useValidator();
 const { notify } = useNotify();
 const route = useRoute();
 const myForm = ref(null);
@@ -119,7 +118,7 @@ const defaultButtons = computed(() => ({
         color: 'primary',
         icon: 'save',
         label: 'globals.save',
-        click: async () => await save(),
+        click: async (evt) => submitForm(evt),
         type: 'submit',
     },
     reset: {
@@ -132,6 +131,13 @@ const defaultButtons = computed(() => ({
     ...$props.defaultButtons,
 }));
 
+const submitForm = async (evt) => {
+    const isFormValid = await myForm.value.validate();
+    if (isFormValid) {
+        await save(evt);
+    }
+};
+
 onMounted(async () => {
     nextTick(() => (componentIsRendered.value = true));
 
@@ -227,10 +233,9 @@ async function save() {
         const method = $props.urlCreate ? 'post' : 'patch';
         const url =
             $props.urlCreate || $props.urlUpdate || $props.url || arrayData.store.url;
-        let response;
-
-        if ($props.saveFn) response = await $props.saveFn(body);
-        else response = await axios[method](url, body);
+        const response = await Promise.resolve(
+            $props.saveFn ? $props.saveFn(body) : axios[method](url, body),
+        );
 
         if ($props.urlCreate) notify('globals.dataCreated', 'positive');
 
@@ -307,11 +312,13 @@ async function onKeyup(evt) {
             selectionStart = selectionEnd = selectionStart + 1;
             return;
         }
-        await save();
+        await myForm.value.submit(evt);
     }
 }
 
 defineExpose({
+    submitForm,
+    myForm,
     save,
     isLoading,
     hasChanges,
@@ -325,7 +332,7 @@ defineExpose({
         <QForm
             ref="myForm"
             v-if="formData"
-            @submit.prevent
+            @submit.prevent="save"
             @keyup.prevent="onKeyup"
             @reset="reset"
             class="q-pa-md"
@@ -339,6 +346,7 @@ defineExpose({
                     name="form"
                     :data="formData"
                     :validate="validate"
+                    :validations="validations()"
                     :filter="filter"
                 />
                 <SkeletonForm v-else />
diff --git a/src/components/FormModelPopup.vue b/src/components/FormModelPopup.vue
index 85943e91e..34aec96d8 100644
--- a/src/components/FormModelPopup.vue
+++ b/src/components/FormModelPopup.vue
@@ -41,9 +41,12 @@ const onDataSaved = async (formData, requestResponse) => {
     emit('onDataSaved', formData, requestResponse);
 };
 
-const onClick = async (saveAndContinue) => {
+const onClick = async (saveAndContinue = showSaveAndContinueBtn) => {
+    await formModelRef.value.myForm.validate(true);
     isSaveAndContinue.value = saveAndContinue;
-    await formModelRef.value.save();
+    if (formModelRef.value) {
+        await formModelRef.value.submitForm();
+    }
 };
 
 defineExpose({
@@ -59,16 +62,23 @@ defineExpose({
         ref="formModelRef"
         :observe-form-changes="false"
         :default-actions="false"
+        @submit="onClick"
         v-bind="$attrs"
         @on-data-saved="onDataSaved"
+        :prevent-submit="false"
     >
-        <template #form="{ data, validate }">
+        <template #form="{ data, validate, validations }">
             <span ref="closeButton" class="close-icon" v-close-popup>
                 <QIcon name="close" size="sm" />
             </span>
             <h1 class="title">{{ title }}</h1>
             <p>{{ subtitle }}</p>
-            <slot name="form-inputs" :data="data" :validate="validate" />
+            <slot
+                name="form-inputs"
+                :data="data"
+                :validate="validate"
+                :validations="validations"
+            />
             <div class="q-mt-lg row justify-end">
                 <QBtn
                     :label="t('globals.cancel')"
@@ -87,12 +97,13 @@ defineExpose({
                     :flat="showSaveAndContinueBtn"
                     :label="t('globals.save')"
                     :title="t('globals.save')"
-                    @click="onClick(false)"
+                    :type="!showSaveAndContinueBtn ? 'submit' : 'button'"
                     color="primary"
                     class="q-ml-sm"
                     :disabled="isLoading"
                     :loading="isLoading"
                     data-cy="FormModelPopup_save"
+                    @click="showSaveAndContinueBtn ? onClick(false) : null"
                     z-max
                 />
                 <QBtn
@@ -100,12 +111,13 @@ defineExpose({
                     :label="t('globals.isSaveAndContinue')"
                     :title="t('globals.isSaveAndContinue')"
                     color="primary"
+                    :type="showSaveAndContinueBtn ? 'submit' : 'button'"
                     class="q-ml-sm"
                     :disabled="isLoading"
                     :loading="isLoading"
                     data-cy="FormModelPopup_isSaveAndContinue"
+                    @click="showSaveAndContinueBtn ? onClick(true) : null"
                     z-max
-                    @click="onClick(true)"
                 />
             </div>
         </template>
diff --git a/src/components/ItemsFilterPanel.vue b/src/components/ItemsFilterPanel.vue
index f73753a6b..0f1e3f1eb 100644
--- a/src/components/ItemsFilterPanel.vue
+++ b/src/components/ItemsFilterPanel.vue
@@ -198,8 +198,7 @@ const setCategoryList = (data) => {
                         v-model="params.typeFk"
                         :options="itemTypesOptions"
                         dense
-                        outlined
-                        rounded
+                        filled
                         use-input
                         :disable="!selectedCategoryFk"
                         @update:model-value="
@@ -235,8 +234,7 @@ const setCategoryList = (data) => {
                         v-model="value.selectedTag"
                         :options="tagOptions"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :emit-value="false"
                         use-input
                         :is-clearable="false"
@@ -252,8 +250,7 @@ const setCategoryList = (data) => {
                         option-value="value"
                         option-label="value"
                         dense
-                        outlined
-                        rounded
+                        filled
                         emit-value
                         use-input
                         :disable="!value"
@@ -265,7 +262,6 @@ const setCategoryList = (data) => {
                         v-model="value.value"
                         :label="t('components.itemsFilterPanel.value')"
                         :disable="!value"
-                        is-outlined
                         :is-clearable="false"
                         @keyup.enter="applyTags(params, searchFn)"
                     />
diff --git a/src/components/LeftMenu.vue b/src/components/LeftMenu.vue
index 6a7865e68..4d44501c0 100644
--- a/src/components/LeftMenu.vue
+++ b/src/components/LeftMenu.vue
@@ -77,6 +77,7 @@ watch(
 function findMatches(search, item) {
     const matches = [];
     function findRoute(search, item) {
+        if (!item?.children) return;
         for (const child of item.children) {
             if (search?.indexOf(child.name) > -1) {
                 matches.push(child);
@@ -92,7 +93,7 @@ function findMatches(search, item) {
 }
 
 function addChildren(module, route, parent) {
-    const menus = route?.meta?.menu ?? route?.menus?.[props.source]; //backwards compatible
+    const menus = route?.meta?.menu;
     if (!menus) return;
 
     const matches = findMatches(menus, route);
@@ -107,11 +108,7 @@ function getRoutes() {
         main: getMainRoutes,
         card: getCardRoutes,
     };
-    try {
-        handleRoutes[props.source]();
-    } catch (error) {
-        throw new Error(`Method is not defined`);
-    }
+    handleRoutes[props.source]();
 }
 function getMainRoutes() {
     const modules = Object.assign([], navigation.getModules().value);
@@ -122,7 +119,6 @@ function getMainRoutes() {
         );
         if (!moduleDef) continue;
         item.children = [];
-
         addChildren(item.module, moduleDef, item.children);
     }
 
@@ -132,21 +128,16 @@ function getMainRoutes() {
 function getCardRoutes() {
     const currentRoute = route.matched[1];
     const currentModule = toLowerCamel(currentRoute.name);
-    let moduleDef = routes.find((route) => toLowerCamel(route.name) === currentModule);
+    let moduleDef;
 
-    if (!moduleDef) return;
-    if (!moduleDef?.menus) moduleDef = betaGetRoutes();
-    addChildren(currentModule, moduleDef, items.value);
-}
-
-function betaGetRoutes() {
-    let menuRoute;
     let index = route.matched.length - 1;
-    while (!menuRoute && index > 0) {
-        if (route.matched[index]?.meta?.menu) menuRoute = route.matched[index];
+    while (!moduleDef && index > 0) {
+        if (route.matched[index]?.meta?.menu) moduleDef = route.matched[index];
         index--;
     }
-    return menuRoute;
+
+    if (!moduleDef) return;
+    addChildren(currentModule, moduleDef, items.value);
 }
 
 async function togglePinned(item, event) {
diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue
index dbb6f1fe6..7329ddae2 100644
--- a/src/components/NavBar.vue
+++ b/src/components/NavBar.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { onMounted, ref } from 'vue';
+import { onMounted, ref, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useState } from 'src/composables/useState';
 import { useStateStore } from 'stores/useStateStore';
@@ -18,6 +18,14 @@ const state = useState();
 const user = state.getUser();
 const appName = 'Lilium';
 const pinnedModulesRef = ref();
+const hostname = window.location.hostname;
+const env = ref();
+
+const getEnvironment = computed(() => {
+    env.value = hostname.split('-');
+    if (env.value.length <= 1) return;
+    return env.value[0];
+});
 
 onMounted(() => stateStore.setMounted());
 const refresh = () => window.location.reload();
@@ -49,6 +57,9 @@ const refresh = () => window.location.reload();
                         {{ t('globals.backToDashboard') }}
                     </QTooltip>
                 </QBtn>
+                <QBadge v-if="getEnvironment" color="primary" align="top">
+                    {{ getEnvironment }}
+                </QBadge>
             </RouterLink>
             <VnBreadcrumbs v-if="$q.screen.gt.sm" />
             <QSpinner
diff --git a/src/components/TicketProblems.vue b/src/components/TicketProblems.vue
index 255bea9cd..c15e31d80 100644
--- a/src/components/TicketProblems.vue
+++ b/src/components/TicketProblems.vue
@@ -18,14 +18,14 @@ defineProps({ row: { type: Object, required: true } });
             </QIcon>
         </router-link>
         <QIcon
-            v-if="row?.reserved"
+            v-if="row?.isDeleted"
             color="primary"
-            name="vn:reserva"
+            name="vn:deletedTicket"
             size="xs"
-            data-cy="ticketSaleReservedIcon"
+            data-cy="ticketDeletedIcon"
         >
             <QTooltip>
-                {{ t('ticketSale.reserved') }}
+                {{ t('Ticket deleted') }}
             </QTooltip>
         </QIcon>
         <QIcon
diff --git a/src/components/TransferInvoiceForm.vue b/src/components/TransferInvoiceForm.vue
index c4ef1454a..1434b79bc 100644
--- a/src/components/TransferInvoiceForm.vue
+++ b/src/components/TransferInvoiceForm.vue
@@ -87,7 +87,7 @@ const makeInvoice = async () => {
             (data) => (
                 (rectificativeTypeOptions = data),
                 (transferInvoiceParams.cplusRectificationTypeFk = data.filter(
-                    (type) => type.description == 'I – Por diferencias'
+                    (type) => type.description == 'I – Por diferencias',
                 )[0].id)
             )
         "
@@ -100,7 +100,7 @@ const makeInvoice = async () => {
             (data) => (
                 (siiTypeInvoiceOutsOptions = data),
                 (transferInvoiceParams.siiTypeInvoiceOutFk = data.filter(
-                    (type) => type.code == 'R4'
+                    (type) => type.code == 'R4',
                 )[0].id)
             )
         "
@@ -122,7 +122,6 @@ const makeInvoice = async () => {
                 <VnRow>
                     <VnSelect
                         :label="t('Client')"
-                        :options="clientsOptions"
                         hide-selected
                         option-label="name"
                         option-value="id"
diff --git a/src/components/VnTable/VnColumn.vue b/src/components/VnTable/VnColumn.vue
index d0e245388..3ce62c5de 100644
--- a/src/components/VnTable/VnColumn.vue
+++ b/src/components/VnTable/VnColumn.vue
@@ -55,6 +55,8 @@ const $props = defineProps({
     },
 });
 
+const label = $props.showLabel && $props.column.label ? $props.column.label : '';
+
 const defaultSelect = {
     attrs: {
         row: $props.row,
@@ -62,7 +64,7 @@ const defaultSelect = {
         class: 'fit',
     },
     forceAttrs: {
-        label: $props.showLabel && $props.column.label,
+        label,
     },
 };
 
@@ -74,7 +76,7 @@ const defaultComponents = {
             class: 'fit',
         },
         forceAttrs: {
-            label: $props.showLabel && $props.column.label,
+            label,
         },
     },
     number: {
@@ -84,7 +86,7 @@ const defaultComponents = {
             class: 'fit',
         },
         forceAttrs: {
-            label: $props.showLabel && $props.column.label,
+            label,
         },
     },
     date: {
@@ -96,7 +98,7 @@ const defaultComponents = {
             class: 'fit',
         },
         forceAttrs: {
-            label: $props.showLabel && $props.column.label,
+            label,
         },
     },
     time: {
@@ -105,7 +107,7 @@ const defaultComponents = {
             disable: !$props.isEditable,
         },
         forceAttrs: {
-            label: $props.showLabel && $props.column.label,
+            label,
         },
     },
     checkbox: {
@@ -125,7 +127,7 @@ const defaultComponents = {
             return defaultAttrs;
         },
         forceAttrs: {
-            label: $props.showLabel && $props.column.label,
+            label,
             autofocus: true,
         },
         events: {
diff --git a/src/components/VnTable/VnFilter.vue b/src/components/VnTable/VnFilter.vue
index e9660e4c2..82d7c772c 100644
--- a/src/components/VnTable/VnFilter.vue
+++ b/src/components/VnTable/VnFilter.vue
@@ -6,6 +6,7 @@ import VnSelect from 'components/common/VnSelect.vue';
 import VnInput from 'components/common/VnInput.vue';
 import VnInputDate from 'components/common/VnInputDate.vue';
 import VnInputTime from 'components/common/VnInputTime.vue';
+import VnCheckbox from 'components/common/VnCheckbox.vue';
 import VnColumn from 'components/VnTable/VnColumn.vue';
 
 const $props = defineProps({
@@ -106,7 +107,7 @@ const components = {
         },
     },
     checkbox: {
-        component: markRaw(QCheckbox),
+        component: markRaw(VnCheckbox),
         event: updateEvent,
         attrs: {
             class: $props.showTitle ? 'q-py-sm' : 'q-px-md q-py-xs fit',
diff --git a/src/components/VnTable/VnOrder.vue b/src/components/VnTable/VnOrder.vue
index 47ed9acf4..fe071a57f 100644
--- a/src/components/VnTable/VnOrder.vue
+++ b/src/components/VnTable/VnOrder.vue
@@ -70,7 +70,7 @@ function textAlignToFlex(textAlign) {
         :style="textAlignToFlex(align)"
     >
         <span :title="label">{{ label }}</span>
-        <div v-if="name && model?.index">
+        <div v-if="name && (model?.index || vertical)">
             <QChip
                 :label="!vertical ? model?.index : ''"
                 :icon="
@@ -83,14 +83,14 @@ function textAlignToFlex(textAlign) {
                 :size="vertical ? '' : 'sm'"
                 :class="[
                     model?.index ? 'color-vn-text' : 'bg-transparent',
-                    vertical ? 'q-px-none' : '',
+                    vertical ? 'q-mx-none q-py-lg' : '',
                 ]"
                 class="no-box-shadow"
                 :clickable="true"
                 style="min-width: 40px; max-height: 30px"
             >
                 <div
-                    class="column flex-center"
+                    class="column justify-center text-center"
                     v-if="vertical"
                     :style="!model?.index && 'color: #5d5d5d'"
                 >
diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 4622c9fa9..36554320b 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -19,6 +19,7 @@ import { useQuasar, date } from 'quasar';
 import { useStateStore } from 'stores/useStateStore';
 import { useFilterParams } from 'src/composables/useFilterParams';
 import { dashIfEmpty, toDate } from 'src/filters';
+import { useTableHeight } from './filters/useTableHeight';
 
 import CrudModel from 'src/components/CrudModel.vue';
 import FormModelPopup from 'components/FormModelPopup.vue';
@@ -117,7 +118,7 @@ const $props = defineProps({
     },
     tableHeight: {
         type: String,
-        default: '90vh',
+        default: undefined,
     },
     footer: {
         type: Boolean,
@@ -140,7 +141,7 @@ const $props = defineProps({
     },
     dataCy: {
         type: String,
-        default: 'vn-table',
+        default: 'vnTable',
     },
 });
 
@@ -166,6 +167,7 @@ const tableRef = ref();
 const params = ref(useFilterParams($attrs['data-key']).params);
 const orders = ref(useFilterParams($attrs['data-key']).orders);
 const app = inject('app');
+const tableHeight = useTableHeight();
 
 const editingRow = ref(null);
 const editingField = ref(null);
@@ -227,6 +229,7 @@ watch(
 
 defineExpose({
     create: createForm,
+    showForm,
     reload,
     redirect: redirectFn,
     selected,
@@ -595,18 +598,17 @@ function cardClick(_, row) {
 
 function removeTextValue(data, getChanges) {
     let changes = data.updates;
-    if (!changes) return data;
-
-    for (const change of changes) {
-        for (const key in change.data) {
-            if (key.endsWith('VnTableTextValue')) {
-                delete change.data[key];
+    if (changes) {
+        for (const change of changes) {
+            for (const key in change.data) {
+                if (key.endsWith('VnTableTextValue')) {
+                    delete change.data[key];
+                }
             }
         }
+
+        data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
     }
-
-    data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
-
     if ($attrs?.beforeSaveFn) data = $attrs.beforeSaveFn(data, getChanges);
 
     return data;
@@ -634,6 +636,7 @@ const rowCtrlClickFunction = computed(() => {
                 :data-key="$attrs['data-key']"
                 :columns="columns"
                 :redirect="redirect"
+                v-bind="$attrs?.['table-filter']"
             >
                 <template
                     v-for="(_, slotName) in $slots"
@@ -678,14 +681,14 @@ const rowCtrlClickFunction = computed(() => {
                 table-header-class="bg-header"
                 card-container-class="grid-three"
                 flat
-                :style="isTableMode && `max-height: ${tableHeight}`"
+                :style="isTableMode && `max-height: ${$props.tableHeight || tableHeight}`"
                 :virtual-scroll="isTableMode"
                 @virtual-scroll="handleScroll"
                 @row-click="(event, row) => handleRowClick(event, row)"
                 @update:selected="emit('update:selected', $event)"
                 @selection="(details) => handleSelection(details, rows)"
                 :hide-selected-banner="true"
-                :data-cy="$props.dataCy ?? 'vnTable'"
+                :data-cy
             >
                 <template #top-left v-if="!$props.withoutHeader">
                     <slot name="top-left"> </slot>
@@ -776,12 +779,13 @@ const rowCtrlClickFunction = computed(() => {
                         :data-col-field="col?.name"
                     >
                         <div
-                            class="no-padding no-margin peter"
+                            class="no-padding no-margin"
                             style="
                                 overflow: hidden;
                                 text-overflow: ellipsis;
                                 white-space: nowrap;
                             "
+                            :data-cy="`vnTableCell_${col.name}`"
                         >
                             <slot
                                 :name="`column-${col.name}`"
@@ -896,7 +900,7 @@ const rowCtrlClickFunction = computed(() => {
                                         {{ row[splittedColumns.title.name] }}
                                     </span>
                                 </QCardSection>
-                                <!-- Fields -->
+                                <!-- Fields  -->
                                 <QCardSection
                                     class="q-pl-sm q-py-xs"
                                     :class="$props.cardClass"
@@ -920,12 +924,24 @@ const rowCtrlClickFunction = computed(() => {
                                                         :row-index="index"
                                                     >
                                                         <VnColumn
-                                                            :column="col"
+                                                            :column="{
+                                                                ...col,
+                                                                disable:
+                                                                    col?.component ===
+                                                                    'checkbox'
+                                                                        ? true
+                                                                        : false,
+                                                            }"
                                                             :row="row"
                                                             :is-editable="false"
                                                             v-model="row[col.name]"
                                                             component-prop="columnField"
-                                                            :show-label="true"
+                                                            :show-label="
+                                                                col?.component ===
+                                                                'checkbox'
+                                                                    ? false
+                                                                    : true
+                                                            "
                                                         />
                                                     </slot>
                                                 </span>
@@ -966,6 +982,8 @@ const rowCtrlClickFunction = computed(() => {
                             v-for="col of cols.filter((cols) => cols.visible ?? true)"
                             :key="col?.id"
                             :class="getColAlign(col)"
+                            :style="col?.width ? `max-width: ${col?.width}` : ''"
+                            style="font-size: small"
                         >
                             <slot
                                 :name="`column-footer-${col.name}`"
@@ -1027,39 +1045,45 @@ const rowCtrlClickFunction = computed(() => {
             :model="$attrs['data-key'] + 'Create'"
             @on-data-saved="(_, res) => createForm.onDataSaved(res)"
         >
-            <template #form-inputs="{ data }">
-                <div :style="createComplement?.containerStyle">
-                    <div
-                        :style="createComplement?.previousStyle"
-                        v-if="!quasar.screen.xs"
-                    >
-                        <slot name="previous-create-dialog" :data="data" />
-                    </div>
-                    <div class="grid-create" :style="createComplement?.columnGridStyle">
-                        <slot
-                            v-for="column of splittedColumns.create"
-                            :key="column.name"
-                            :name="`column-create-${column.name}`"
-                            :data="data"
-                            :column-name="column.name"
-                            :label="column.label"
+            <template #form-inputs="{ data, validations }">
+                <slot name="alter-create" :data="data">
+                    <div :style="createComplement?.containerStyle">
+                        <div
+                            :style="createComplement?.previousStyle"
+                            v-if="!quasar.screen.xs"
                         >
-                            <VnColumn
-                                :column="{
-                                    ...column,
-                                    ...{ disable: column?.createDisable ?? false },
-                                }"
-                                :row="{}"
-                                default="input"
-                                v-model="data[column.name]"
-                                :show-label="true"
-                                component-prop="columnCreate"
-                                :data-cy="`${column.name}-create-popup`"
-                            />
-                        </slot>
-                        <slot name="more-create-dialog" :data="data" />
+                            <slot name="previous-create-dialog" :data="data" />
+                        </div>
+                        <div
+                            class="grid-create"
+                            :style="createComplement?.columnGridStyle"
+                        >
+                            <slot
+                                v-for="column of splittedColumns.create"
+                                :key="column.name"
+                                :name="`column-create-${column.name}`"
+                                :data="data"
+                                :validations="validations"
+                                :column-name="column.name"
+                                :label="column.label"
+                            >
+                                <VnColumn
+                                    :column="{
+                                        ...column,
+                                        ...column?.createAttrs,
+                                    }"
+                                    :row="{}"
+                                    default="input"
+                                    v-model="data[column.name]"
+                                    :show-label="true"
+                                    component-prop="columnCreate"
+                                    :data-cy="`${column.name}-create-popup`"
+                                />
+                            </slot>
+                            <slot name="more-create-dialog" :data="data" />
+                        </div>
                     </div>
-                </div>
+                </slot>
             </template>
         </FormModelPopup>
     </QDialog>
@@ -1137,8 +1161,12 @@ es:
 .grid-create {
     display: grid;
     grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
+    max-width: 100%;
     grid-gap: 20px;
     margin: 0 auto;
+    .col-span-2 {
+        grid-column: span 2;
+    }
 }
 
 .flex-one {
diff --git a/src/components/VnTable/VnTableFilter.vue b/src/components/VnTable/VnTableFilter.vue
index c62b8b0fc..a7b2108ed 100644
--- a/src/components/VnTable/VnTableFilter.vue
+++ b/src/components/VnTable/VnTableFilter.vue
@@ -31,6 +31,7 @@ function columnName(col) {
         :search-button="true"
         :disable-submit-event="true"
         :data-key="$attrs['data-key']"
+        :search-url
     >
         <template #body="{ params, orders, searchFn }">
             <div
@@ -39,13 +40,20 @@ function columnName(col) {
                 :key="col.id"
             >
                 <div class="filter">
-                    <VnFilter
-                        ref="tableFilterRef"
-                        :column="col"
-                        :data-key="$attrs['data-key']"
-                        v-model="params[columnName(col)]"
-                        :search-url="searchUrl"
-                    />
+                    <slot
+                        :name="`filter-${col.name}`"
+                        :params="params"
+                        :column-name="columnName(col)"
+                        :search-fn
+                    >
+                        <VnFilter
+                            ref="tableFilterRef"
+                            :column="col"
+                            :data-key="$attrs['data-key']"
+                            v-model="params[columnName(col)]"
+                            :search-url="searchUrl"
+                        />
+                    </slot>
                 </div>
                 <div class="order">
                     <VnTableOrder
@@ -82,13 +90,13 @@ function columnName(col) {
     display: flex;
     justify-content: center;
     align-items: center;
-    height: 45px;
+    min-height: 45px;
     gap: 10px;
 }
 
 .filter {
     width: 70%;
-    height: 40px;
+    min-height: 40px;
     text-align: center;
 }
 .order {
diff --git a/src/components/VnTable/__tests__/VnVisibleColumns.spec.js b/src/components/VnTable/__tests__/VnVisibleColumns.spec.js
index bf767688b..3e4e9ecc8 100644
--- a/src/components/VnTable/__tests__/VnVisibleColumns.spec.js
+++ b/src/components/VnTable/__tests__/VnVisibleColumns.spec.js
@@ -1,8 +1,7 @@
 import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest';
 import { createWrapper } from 'app/test/vitest/helper';
 import VnVisibleColumn from '../VnVisibleColumn.vue';
-import { axios } from 'app/test/vitest/helper';
-
+import { default as axios } from 'axios';
 describe('VnVisibleColumns', () => {
     let wrapper;
     let vm;
diff --git a/src/components/VnTable/filters/useTableHeight.js b/src/components/VnTable/filters/useTableHeight.js
new file mode 100644
index 000000000..2397ce16f
--- /dev/null
+++ b/src/components/VnTable/filters/useTableHeight.js
@@ -0,0 +1,18 @@
+import { onMounted, nextTick, ref } from 'vue';
+
+export function useTableHeight() {
+    const tableHeight = ref('90vh');
+
+    onMounted(async () => {
+        await nextTick();
+        let height = 100;
+        Array.from(document.querySelectorAll('[role="toolbar"]'))
+            .filter((element) => window.getComputedStyle(element).display !== 'none')
+            .forEach(() => {
+                height -= 10;
+            });
+        tableHeight.value = `${height}vh`;
+    });
+
+    return tableHeight;
+}
diff --git a/src/components/__tests__/CrudModel.spec.js b/src/components/__tests__/CrudModel.spec.js
index b0eafbc02..6278f8ee4 100644
--- a/src/components/__tests__/CrudModel.spec.js
+++ b/src/components/__tests__/CrudModel.spec.js
@@ -1,4 +1,6 @@
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
+
 import CrudModel from 'components/CrudModel.vue';
 import { vi, afterEach, beforeEach, beforeAll, describe, expect, it } from 'vitest';
 
diff --git a/src/components/__tests__/EditTableCellValueForm.spec.js b/src/components/__tests__/EditTableCellValueForm.spec.js
deleted file mode 100644
index fa47d8f73..000000000
--- a/src/components/__tests__/EditTableCellValueForm.spec.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import { createWrapper, axios } from 'app/test/vitest/helper';
-import EditForm from 'components/EditTableCellValueForm.vue';
-import { vi, afterEach, beforeAll, describe, expect, it } from 'vitest';
-
-const fieldA = 'fieldA';
-const fieldB = 'fieldB';
-
-describe('EditForm', () => {
-    let vm;
-    const mockRows = [
-        { id: 1, itemFk: 101 },
-        { id: 2, itemFk: 102 },
-    ];
-    const mockFieldsOptions = [
-        { label: 'Field A', field: fieldA, component: 'input', attrs: {} },
-        { label: 'Field B', field: fieldB, component: 'date', attrs: {} },
-    ];
-    const editUrl = '/api/edit';
-
-    beforeAll(() => {
-        vi.spyOn(axios, 'post').mockResolvedValue({ status: 200 });
-        vm = createWrapper(EditForm, {
-            props: {
-                rows: mockRows,
-                fieldsOptions: mockFieldsOptions,
-                editUrl,
-            },
-        }).vm;
-    });
-
-    afterEach(() => {
-        vi.clearAllMocks();
-    });
-
-    describe('onSubmit()', () => {
-        it('should call axios.post with the correct parameters in the payload', async () => {
-            const selectedField = { field: fieldA, component: 'input', attrs: {} };
-            const newValue = 'Test Value';
-
-            vm.selectedField = selectedField;
-            vm.newValue = newValue;
-
-            await vm.onSubmit();
-
-            const payload = axios.post.mock.calls[0][1];
-
-            expect(axios.post).toHaveBeenCalledWith(editUrl, expect.any(Object));
-            expect(payload.field).toEqual(fieldA);
-            expect(payload.newValue).toEqual(newValue);
-
-            expect(payload.lines).toEqual(expect.arrayContaining(mockRows));
-
-            expect(vm.isLoading).toEqual(false);
-        });
-    });
-});
diff --git a/src/components/__tests__/FilterItemForm.spec.js b/src/components/__tests__/FilterItemForm.spec.js
index 210d6bf02..fb8332c31 100644
--- a/src/components/__tests__/FilterItemForm.spec.js
+++ b/src/components/__tests__/FilterItemForm.spec.js
@@ -1,4 +1,6 @@
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
+
 import FilterItemForm from 'src/components/FilterItemForm.vue';
 import { vi, beforeAll, describe, expect, it } from 'vitest';
 
@@ -38,9 +40,9 @@ describe('FilterItemForm', () => {
                 { relation: 'producer', scope: { fields: ['name'] } },
                 { relation: 'ink', scope: { fields: ['name'] } },
             ],
-            where: {"name":{"like":"%bolas de madera%"}},
+            where: { name: { like: '%bolas de madera%' } },
         };
-        
+
         expect(axios.get).toHaveBeenCalledWith('Items/withName', {
             params: { filter: JSON.stringify(expectedFilter) },
         });
@@ -79,4 +81,4 @@ describe('FilterItemForm', () => {
         vm.selectItem({ id: 12345 });
         expect(wrapper.emitted('itemSelected')[0]).toEqual([12345]);
     });
-});
\ No newline at end of file
+});
diff --git a/src/components/__tests__/FormModel.spec.js b/src/components/__tests__/FormModel.spec.js
index 3dce04374..20e99b55b 100644
--- a/src/components/__tests__/FormModel.spec.js
+++ b/src/components/__tests__/FormModel.spec.js
@@ -1,5 +1,7 @@
 import { describe, expect, it, beforeAll, vi, afterAll } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
+
 import FormModel from 'src/components/FormModel.vue';
 
 describe('FormModel', () => {
diff --git a/src/components/__tests__/Leftmenu.spec.js b/src/components/__tests__/Leftmenu.spec.js
index 7c8470589..5bddc104c 100644
--- a/src/components/__tests__/Leftmenu.spec.js
+++ b/src/components/__tests__/Leftmenu.spec.js
@@ -1,6 +1,7 @@
-import { vi, describe, expect, it, beforeAll, beforeEach, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
-import Leftmenu from 'components/LeftMenu.vue';
+import { vi, describe, expect, it, beforeAll, afterEach, beforeEach } from 'vitest';
+import { default as axios } from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
+import LeftMenu from 'components/LeftMenu.vue';
 import * as vueRouter from 'vue-router';
 import { useNavigationStore } from 'src/stores/useNavigationStore';
 
@@ -15,10 +16,7 @@ vi.mock('src/router/modules', () => ({
             meta: {
                 title: 'customers',
                 icon: 'vn:client',
-            },
-            menus: {
-                main: ['CustomerList', 'CustomerCreate'],
-                card: ['CustomerBasicData'],
+                menu: ['CustomerList', 'CustomerCreate'],
             },
             children: [
                 {
@@ -50,14 +48,6 @@ vi.mock('src/router/modules', () => ({
                                 ],
                             },
                         },
-                        {
-                            path: 'create',
-                            name: 'CustomerCreate',
-                            meta: {
-                                title: 'createCustomer',
-                                icon: 'vn:addperson',
-                            },
-                        },
                     ],
                 },
             ],
@@ -98,7 +88,7 @@ vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
                 icon: 'vn:client',
                 moduleName: 'Customer',
                 keyBinding: 'c',
-                menu: 'customer',
+                menu: ['customer'],
             },
         },
     ],
@@ -112,7 +102,7 @@ function mount(source = 'main') {
     vi.spyOn(axios, 'get').mockResolvedValue({
         data: [],
     });
-    const wrapper = createWrapper(Leftmenu, {
+    const wrapper = createWrapper(LeftMenu, {
         propsData: {
             source,
         },
@@ -175,7 +165,7 @@ describe('getRoutes', () => {
     });
 });
 
-describe('Leftmenu as card', () => {
+describe('LeftMenu as card', () => {
     beforeAll(() => {
         vm = mount('card').vm;
     });
@@ -184,7 +174,7 @@ describe('Leftmenu as card', () => {
         vm.getRoutes();
     });
 });
-describe('Leftmenu as main', () => {
+describe('LeftMenu as main', () => {
     beforeEach(() => {
         vm = mount().vm;
     });
@@ -260,15 +250,6 @@ describe('Leftmenu as main', () => {
         });
     });
 
-    it('should handle a single matched route with a menu', () => {
-        const route = {
-            matched: [{ meta: { menu: 'customer' } }],
-        };
-
-        const result = vm.betaGetRoutes();
-
-        expect(result.meta.menu).toEqual(route.matched[0].meta.menu);
-    });
     it('should get routes for main source', () => {
         vm.getRoutes();
         expect(navigation.getModules).toHaveBeenCalled();
@@ -350,8 +331,9 @@ describe('addChildren', () => {
 
     it('should handle routes with no meta menu', () => {
         const route = {
-            meta: {},
-            menus: {},
+            meta: {
+                menu: [],
+            },
         };
 
         const parent = [];
diff --git a/src/components/common/SendEmailDialog.vue b/src/components/common/SendEmailDialog.vue
index 254eb9cf9..a8209bdf7 100644
--- a/src/components/common/SendEmailDialog.vue
+++ b/src/components/common/SendEmailDialog.vue
@@ -60,7 +60,7 @@ async function confirm() {
                     v-model="address"
                     is-outlined
                     autofocus
-                    data-cy="SendEmailNotifiactionDialogInput"
+                    data-cy="SendEmailNotificationDialogInput"
                 />
             </QCardSection>
             <QCardActions align="right">
diff --git a/src/components/common/SendSmsDialog.vue b/src/components/common/SendSmsDialog.vue
index 269a4ec9a..a953abd75 100644
--- a/src/components/common/SendSmsDialog.vue
+++ b/src/components/common/SendSmsDialog.vue
@@ -1,15 +1,15 @@
 <script setup>
-import {useDialogPluginComponent} from 'quasar';
-import {useI18n} from 'vue-i18n';
-import {computed, ref} from 'vue';
+import { useDialogPluginComponent } from 'quasar';
+import { useI18n } from 'vue-i18n';
+import { computed, ref } from 'vue';
 import VnInput from 'components/common/VnInput.vue';
 import axios from 'axios';
-import useNotify from "composables/useNotify";
+import useNotify from 'composables/useNotify';
 
 const MESSAGE_MAX_LENGTH = 160;
 
-const {t} = useI18n();
-const {notify} = useNotify();
+const { t } = useI18n();
+const { notify } = useNotify();
 const props = defineProps({
     title: {
         type: String,
@@ -34,7 +34,7 @@ const props = defineProps({
 });
 
 const emit = defineEmits([...useDialogPluginComponent.emits, 'sent']);
-const {dialogRef, onDialogHide} = useDialogPluginComponent();
+const { dialogRef, onDialogHide } = useDialogPluginComponent();
 
 const smsRules = [
     (val) => (val && val.length > 0) || t("The message can't be empty"),
@@ -43,10 +43,10 @@ const smsRules = [
         t("The message it's too long"),
 ];
 
-const message = ref('');
+const message = ref(t('routeDelay'));
 
 const charactersRemaining = computed(
-    () => MESSAGE_MAX_LENGTH - new Blob([message.value]).size
+    () => MESSAGE_MAX_LENGTH - new Blob([message.value]).size,
 );
 
 const charactersChipColor = computed(() => {
@@ -114,7 +114,7 @@ const onSubmit = async () => {
                                 <QTooltip>
                                     {{
                                         t(
-                                            'Special characters like accents counts as a multiple'
+                                            'Special characters like accents counts as a multiple',
                                         )
                                     }}
                                 </QTooltip>
@@ -144,7 +144,10 @@ const onSubmit = async () => {
     max-width: 450px;
 }
 </style>
+
 <i18n>
+en:
+    routeDelay: "Your order has been delayed in transit.\nDelivery will take place throughout the day.\nWe apologize for the inconvenience and appreciate your patience."
 es:
     Message: Mensaje
     Send: Enviar
@@ -153,4 +156,5 @@ es:
     The destination can't be empty: El destinatario no puede estar vacio
     The message can't be empty: El mensaje no puede estar vacio
     The message it's too long: El mensaje es demasiado largo
-</i18n>
+    routeDelay: "Retraso en ruta.\nInformamos que la ruta que lleva su pedido ha sufrido un retraso y la entrega se hará a lo largo del día.\nDisculpe las molestias."
+    </i18n>
diff --git a/src/components/common/VnAccountNumber.vue b/src/components/common/VnAccountNumber.vue
index 56add7329..8bff3e261 100644
--- a/src/components/common/VnAccountNumber.vue
+++ b/src/components/common/VnAccountNumber.vue
@@ -1,35 +1,14 @@
 <script setup>
-import { nextTick, ref } from 'vue';
 import VnInput from './VnInput.vue';
 import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
 
-const $props = defineProps({
-    insertable: {
-        type: Boolean,
-        default: false,
-    },
-});
-
-const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
 const model = defineModel({ prop: 'modelValue' });
-const inputRef = ref(false);
-
-function setCursorPosition(pos) {
-    const input = inputRef.value.vnInputRef.$el.querySelector('input');
-    input.focus();
-    input.setSelectionRange(pos, pos);
-}
-
-async function handleUpdateModel(val) {
-    model.value = val?.at(-1) === '.' ? useAccountShortToStandard(val) : val;
-    await nextTick(() => setCursorPosition(0));
-}
 </script>
 <template>
     <VnInput
         v-model="model"
         ref="inputRef"
-        :insertable
-        @update:model-value="handleUpdateModel"
+        @keydown.tab="model = useAccountShortToStandard($event.target.value) ?? model"
+        @input="model = $event.target.value.replace(/[^\d.]/g, '')"
     />
 </template>
diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue
index 44002c22a..0b9cc2cce 100644
--- a/src/components/common/VnCard.vue
+++ b/src/components/common/VnCard.vue
@@ -1,89 +1,93 @@
 <script setup>
-import { onBeforeMount, computed } from 'vue';
-import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router';
+import { onBeforeMount, computed, markRaw } from 'vue';
+import { useRoute, useRouter, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router';
 import { useArrayData } from 'src/composables/useArrayData';
 import { useStateStore } from 'stores/useStateStore';
 import useCardSize from 'src/composables/useCardSize';
 import VnSubToolbar from '../ui/VnSubToolbar.vue';
-import VnSearchbar from 'components/ui/VnSearchbar.vue';
-import LeftMenu from 'components/LeftMenu.vue';
-import RightMenu from 'components/common/RightMenu.vue';
+
+const emit = defineEmits(['onFetch']);
+
 const props = defineProps({
+    id: { type: Number, required: false, default: null },
     dataKey: { type: String, required: true },
     url: { type: String, default: undefined },
+    idInWhere: { type: Boolean, default: false },
     filter: { type: Object, default: () => {} },
     descriptor: { type: Object, required: true },
     filterPanel: { type: Object, default: undefined },
-    idInWhere: { type: Boolean, default: false },
     searchDataKey: { type: String, default: undefined },
     searchbarProps: { type: Object, default: undefined },
     redirectOnError: { type: Boolean, default: false },
+    visual: { type: Boolean, default: true },
 });
 
-const stateStore = useStateStore();
 const route = useRoute();
+const stateStore = useStateStore();
 const router = useRouter();
-const searchRightDataKey = computed(() => {
-    if (!props.searchDataKey) return route.name;
-    return props.searchDataKey;
-});
+const entityId = computed(() => props.id || route?.params?.id);
+let arrayData = getArrayData(entityId.value, props.url);
 
-const arrayData = useArrayData(props.dataKey, {
-    url: props.url,
-    userFilter: props.filter,
-    oneRecord: true,
+onBeforeRouteLeave(() => {
+    stateStore.cardDescriptorChangeValue(null);
 });
 
 onBeforeMount(async () => {
+    stateStore.cardDescriptorChangeValue(markRaw(props.descriptor));
+
+    const route = router.currentRoute.value;
     try {
-        await fetch(route.params.id);
+        await fetch(entityId.value);
     } catch {
-        const { matched: matches } = router.currentRoute.value;
+        const { matched: matches } = route;
         const { path } = matches.at(-1);
         router.push({ path: path.replace(/:id.*/, '') });
     }
 });
 
 onBeforeRouteUpdate(async (to, from) => {
-    const id = to.params.id;
-    if (id !== from.params.id) await fetch(id, true);
+    if (hasRouteParam(to.params)) {
+        const { matched } = router.currentRoute.value;
+        const { name } = matched.at(-3);
+        if (name) {
+            router.push({ name, params: to.params });
+        }
+    }
+    if (entityId.value !== to.params.id) await fetch(to.params.id, true);
 });
 
 async function fetch(id, append = false) {
-    const regex = /\/(\d+)/;
     if (props.idInWhere) arrayData.store.filter.where = { id };
-    else if (!regex.test(props.url)) arrayData.store.url = `${props.url}/${id}`;
-    else arrayData.store.url = props.url.replace(regex, `/${id}`);
+    else {
+        arrayData = getArrayData(id);
+    }
     await arrayData.fetch({ append, updateRouter: false });
+    emit('onFetch', arrayData.store.data);
+}
+function hasRouteParam(params, valueToCheck = ':addressId') {
+    return Object.values(params).includes(valueToCheck);
+}
+
+function formatUrl(id) {
+    const newId = id || entityId.value;
+    const regex = /\/(\d+)/;
+    if (!regex.test(props.url)) return `${props.url}/${newId}`;
+    return props.url.replace(regex, `/${newId}`);
+}
+
+function getArrayData(id, url) {
+    return useArrayData(props.dataKey, {
+        url: url ?? formatUrl(id),
+        userFilter: props.filter,
+        oneRecord: true,
+    });
 }
 </script>
 <template>
-    <QDrawer
-        v-model="stateStore.leftDrawer"
-        show-if-above
-        :width="256"
-        v-if="stateStore.isHeaderMounted()"
-    >
-        <QScrollArea class="fit">
-            <component :is="descriptor" />
-            <QSeparator />
-            <LeftMenu source="card" />
-        </QScrollArea>
-    </QDrawer>
-    <slot name="searchbar" v-if="props.searchDataKey">
-        <VnSearchbar :data-key="props.searchDataKey" v-bind="props.searchbarProps" />
-    </slot>
-    <RightMenu>
-        <template #right-panel v-if="props.filterPanel">
-            <component :is="props.filterPanel" :data-key="searchRightDataKey" />
-        </template>
-    </RightMenu>
-    <QPageContainer>
-        <QPage>
-            <VnSubToolbar />
-            <div :class="[useCardSize(), $attrs.class]">
-                <RouterView :key="$route.path" />
-            </div>
-        </QPage>
-    </QPageContainer>
+    <template v-if="visual">
+        <VnSubToolbar />
+        <div :class="[useCardSize(), $attrs.class]">
+            <RouterView :key="$route.path" />
+        </div>
+    </template>
 </template>
diff --git a/src/components/common/VnCardBeta.vue b/src/components/common/VnCardBeta.vue
deleted file mode 100644
index 620dc2ad2..000000000
--- a/src/components/common/VnCardBeta.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-<script setup>
-import { onBeforeMount } from 'vue';
-import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router';
-import { useArrayData } from 'src/composables/useArrayData';
-import { useStateStore } from 'stores/useStateStore';
-import useCardSize from 'src/composables/useCardSize';
-import VnSubToolbar from '../ui/VnSubToolbar.vue';
-
-const props = defineProps({
-    dataKey: { type: String, required: true },
-    url: { type: String, default: undefined },
-    idInWhere: { type: Boolean, default: false },
-    filter: { type: Object, default: () => {} },
-    descriptor: { type: Object, required: true },
-    filterPanel: { type: Object, default: undefined },
-    searchDataKey: { type: String, default: undefined },
-    searchbarProps: { type: Object, default: undefined },
-    redirectOnError: { type: Boolean, default: false },
-});
-
-const stateStore = useStateStore();
-const router = useRouter();
-const arrayData = useArrayData(props.dataKey, {
-    url: props.url,
-    userFilter: props.filter,
-    oneRecord: true,
-});
-
-onBeforeRouteLeave(() => {
-    stateStore.cardDescriptorChangeValue(null);
-});
-
-onBeforeMount(async () => {
-    stateStore.cardDescriptorChangeValue(props.descriptor);
-
-    const route = router.currentRoute.value;
-    try {
-        await fetch(route.params.id);
-    } catch {
-        const { matched: matches } = route;
-        const { path } = matches.at(-1);
-        router.push({ path: path.replace(/:id.*/, '') });
-    }
-});
-
-onBeforeRouteUpdate(async (to, from) => {
-    if (hasRouteParam(to.params)) {
-        const { matched } = router.currentRoute.value;
-        const { name } = matched.at(-3);
-        if (name) {
-            router.push({ name, params: to.params });
-        }
-    }
-    const id = to.params.id;
-    if (id !== from.params.id) await fetch(id, true);
-});
-
-async function fetch(id, append = false) {
-    const regex = /\/(\d+)/;
-    if (props.idInWhere) arrayData.store.filter.where = { id };
-    else if (!regex.test(props.url)) arrayData.store.url = `${props.url}/${id}`;
-    else arrayData.store.url = props.url.replace(regex, `/${id}`);
-    await arrayData.fetch({ append, updateRouter: false });
-}
-function hasRouteParam(params, valueToCheck = ':addressId') {
-    return Object.values(params).includes(valueToCheck);
-}
-</script>
-<template>
-    <VnSubToolbar />
-    <div :class="[useCardSize(), $attrs.class]">
-        <RouterView :key="$route.path" />
-    </div>
-</template>
diff --git a/src/components/common/VnCheckbox.vue b/src/components/common/VnCheckbox.vue
index 94e91328b..daaf891dc 100644
--- a/src/components/common/VnCheckbox.vue
+++ b/src/components/common/VnCheckbox.vue
@@ -27,7 +27,11 @@ const checkboxModel = computed({
 </script>
 <template>
     <div>
-        <QCheckbox v-bind="$attrs" v-model="checkboxModel" />
+        <QCheckbox
+            v-bind="$attrs"
+            v-model="checkboxModel"
+            :data-cy="$attrs['data-cy'] ?? `vnCheckbox${$attrs['label'] ?? ''}`"
+        />
         <QIcon
             v-if="info"
             v-bind="$attrs"
diff --git a/src/components/common/VnColor.vue b/src/components/common/VnColor.vue
index 8a5a787b0..dccbc7102 100644
--- a/src/components/common/VnColor.vue
+++ b/src/components/common/VnColor.vue
@@ -1,4 +1,6 @@
 <script setup>
+import { computed } from 'vue';
+
 const $props = defineProps({
     colors: {
         type: String,
@@ -6,9 +8,9 @@ const $props = defineProps({
     },
 });
 
-const colorArray = JSON.parse($props.colors)?.value;
+const colorArray = computed(() => JSON.parse($props.colors)?.value);
 const maxHeight = 30;
-const colorHeight = maxHeight / colorArray?.length;
+const colorHeight = maxHeight / colorArray.value?.length;
 </script>
 <template>
     <div v-if="colors" class="color-div" :style="{ height: `${maxHeight}px` }">
diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue
index 9884a447c..c713ac5ec 100644
--- a/src/components/common/VnDms.vue
+++ b/src/components/common/VnDms.vue
@@ -35,6 +35,10 @@ const $props = defineProps({
         type: String,
         default: null,
     },
+    hasFile: {
+        type: Boolean,
+        default: false,
+    },
 });
 
 const warehouses = ref();
@@ -90,6 +94,7 @@ function defaultData() {
     if ($props.formInitialData) return (dms.value = $props.formInitialData);
     return addDefaultData({
         reference: route.params.id,
+        hasFile: $props.hasFile,
     });
 }
 
@@ -177,6 +182,7 @@ function addDefaultData(data) {
                             name="vn:attach"
                             class="cursor-pointer"
                             @click="inputFileRef.pickFiles()"
+                            data-cy="attachFile"
                         >
                             <QTooltip>{{ t('globals.selectFile') }}</QTooltip>
                         </QIcon>
diff --git a/src/components/common/VnDmsInput.vue b/src/components/common/VnDmsInput.vue
new file mode 100644
index 000000000..5a3ef351b
--- /dev/null
+++ b/src/components/common/VnDmsInput.vue
@@ -0,0 +1,166 @@
+<script setup>
+import VnConfirm from '../ui/VnConfirm.vue';
+import VnInput from './VnInput.vue';
+import VnDms from './VnDms.vue';
+import axios from 'axios';
+import { useQuasar } from 'quasar';
+import { ref } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { downloadFile } from 'src/composables/downloadFile';
+
+const { t } = useI18n();
+const quasar = useQuasar();
+const documentDialogRef = ref({});
+const editDownloadDisabled = ref(false);
+const $props = defineProps({
+    defaultDmsCode: {
+        type: String,
+        default: 'invoiceIn',
+    },
+    disable: {
+        type: Boolean,
+        default: true,
+    },
+    data: {
+        type: Object,
+        default: null,
+    },
+    formRef: {
+        type: Object,
+        default: null,
+    },
+});
+
+function deleteFile(dmsFk) {
+    quasar
+        .dialog({
+            component: VnConfirm,
+            componentProps: {
+                title: t('globals.confirmDeletion'),
+                message: t('globals.confirmDeletionMessage'),
+            },
+        })
+        .onOk(async () => {
+            await axios.post(`dms/${dmsFk}/removeFile`);
+            $props.formRef.formData.dmsFk = null;
+            $props.formRef.formData.dms = undefined;
+            $props.formRef.hasChanges = true;
+            $props.formRef.save();
+        });
+}
+</script>
+<template>
+    <div class="row no-wrap">
+        <VnInput
+            :label="t('Document')"
+            v-model="data.dmsFk"
+            clearable
+            clear-icon="close"
+            class="full-width"
+            :disable="disable"
+        />
+        <div
+            v-if="data.dmsFk"
+            class="row no-wrap q-pa-xs q-gutter-x-xs"
+            data-cy="dms-buttons"
+        >
+            <QBtn
+                :disable="editDownloadDisabled"
+                @click="downloadFile(data.dmsFk)"
+                icon="cloud_download"
+                color="primary"
+                flat
+                :class="{
+                    'no-pointer-events': editDownloadDisabled,
+                }"
+                padding="xs"
+                round
+            >
+                <QTooltip>{{ t('Download file') }}</QTooltip>
+            </QBtn>
+            <QBtn
+                :disable="editDownloadDisabled"
+                @click="
+                    () => {
+                        documentDialogRef.show = true;
+                        documentDialogRef.dms = data.dms;
+                    }
+                "
+                icon="edit"
+                color="primary"
+                flat
+                :class="{
+                    'no-pointer-events': editDownloadDisabled,
+                }"
+                padding="xs"
+                round
+            >
+                <QTooltip>{{ t('Edit document') }}</QTooltip>
+            </QBtn>
+            <QBtn
+                :disable="editDownloadDisabled"
+                @click="deleteFile(data.dmsFk)"
+                icon="delete"
+                color="primary"
+                flat
+                round
+                :class="{
+                    'no-pointer-events': editDownloadDisabled,
+                }"
+                padding="xs"
+            >
+                <QTooltip>{{ t('Delete file') }}</QTooltip>
+            </QBtn>
+        </div>
+        <QBtn
+            v-else
+            icon="add_circle"
+            color="primary"
+            flat
+            round
+            v-shortcut="'+'"
+            padding="xs"
+            @click="
+                () => {
+                    documentDialogRef.show = true;
+                    delete documentDialogRef.dms;
+                }
+            "
+            data-cy="dms-create"
+        >
+            <QTooltip>{{ t('Create document') }}</QTooltip>
+        </QBtn>
+    </div>
+    <QDialog v-model="documentDialogRef.show">
+        <VnDms
+            model="dms"
+            :default-dms-code="defaultDmsCode"
+            :form-initial-data="documentDialogRef.dms"
+            :url="
+                documentDialogRef.dms
+                    ? `Dms/${documentDialogRef.dms.id}/updateFile`
+                    : 'Dms/uploadFile'
+            "
+            :description="documentDialogRef.supplierName"
+            @on-data-saved="
+                (_, { data }) => {
+                    let dmsData = data;
+                    if (Array.isArray(data)) dmsData = data[0];
+                    formRef.formData.dmsFk = dmsData.id;
+                    formRef.formData.dms = dmsData;
+                    formRef.hasChanges = true;
+                    formRef.save();
+                }
+            "
+        />
+    </QDialog>
+</template>
+<i18n>
+es:
+    Document: Documento
+    Download file: Descargar archivo
+    Edit document: Editar documento
+    Delete file: Eliminar archivo
+    Create document: Crear documento
+
+</i18n>
diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue
index 424781a26..aafa9f4ba 100644
--- a/src/components/common/VnDmsList.vue
+++ b/src/components/common/VnDmsList.vue
@@ -389,10 +389,7 @@ defineExpose({
                     </div>
                 </template>
             </QTable>
-            <div 
-                v-else 
-                class="info-row q-pa-md text-center"
-            >
+            <div v-else class="info-row q-pa-md text-center">
                 <h5>
                     {{ t('No data to display') }}
                 </h5>
@@ -416,6 +413,7 @@ defineExpose({
             v-shortcut
             @click="showFormDialog()"
             class="fill-icon"
+            data-cy="addButton"
         >
             <QTooltip>
                 {{ t('Upload file') }}
diff --git a/src/components/common/VnDropdown.vue b/src/components/common/VnDropdown.vue
new file mode 100644
index 000000000..1b3f2237b
--- /dev/null
+++ b/src/components/common/VnDropdown.vue
@@ -0,0 +1,53 @@
+<script setup>
+import { ref } from 'vue';
+import VnSelect from './VnSelect.vue';
+
+const stateBtnDropdownRef = ref();
+
+const emit = defineEmits(['changeState']);
+
+const $props = defineProps({
+    disable: {
+        type: Boolean,
+        default: null,
+    },
+    options: {
+        type: Array,
+        default: null,
+    },
+    optionLabel: {
+        type: String,
+        default: 'name',
+    },
+    optionValue: {
+        type: String,
+        default: 'id',
+    },
+});
+
+async function changeState(value) {
+    stateBtnDropdownRef.value?.hide();
+    emit('changeState', value);
+}
+</script>
+
+<template>
+    <QBtnDropdown
+        ref="stateBtnDropdownRef"
+        color="black"
+        text-color="white"
+        :label="$t('globals.changeState')"
+        :disable="$props.disable"
+    >
+        <VnSelect
+            :options="$props.options"
+            :option-label="$props.optionLabel"
+            :option-value="$props.optionValue"
+            hide-selected
+            hide-dropdown-icon
+            focus-on-mount
+            @update:model-value="changeState"
+        >
+        </VnSelect>
+    </QBtnDropdown>
+</template>
diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue
index 9821992cb..474d68116 100644
--- a/src/components/common/VnInput.vue
+++ b/src/components/common/VnInput.vue
@@ -84,7 +84,7 @@ const mixinRules = [
     ...($attrs.rules ?? []),
     (val) => {
         const maxlength = $props.maxlength;
-        if (maxlength && +val.length > maxlength)
+        if (maxlength && +val?.length > maxlength)
             return t(`maxLength`, { value: maxlength });
         const { min, max } = vnInputRef.value.$attrs;
         if (!min) return null;
diff --git a/src/components/common/VnInputDate.vue b/src/components/common/VnInputDate.vue
index 1f4705faa..343130f1d 100644
--- a/src/components/common/VnInputDate.vue
+++ b/src/components/common/VnInputDate.vue
@@ -107,7 +107,7 @@ const manageDate = (date) => {
             @click="isPopupOpen = !isPopupOpen"
             @keydown="isPopupOpen = false"
             hide-bottom-space
-            :data-cy="$attrs.dataCy ?? $attrs.label + '_inputDate'"
+            :data-cy="($attrs['data-cy'] ?? $attrs.label) + '_inputDate'"
         >
             <template #append>
                 <QIcon
diff --git a/src/components/common/VnJsonValue.vue b/src/components/common/VnJsonValue.vue
index a2e858d0d..ba37ab1d6 100644
--- a/src/components/common/VnJsonValue.vue
+++ b/src/components/common/VnJsonValue.vue
@@ -1,6 +1,6 @@
 <script setup>
 import { watch } from 'vue';
-import { toDateString } from 'src/filters';
+import { toDateHourMinSec } from 'src/filters';
 
 const props = defineProps({
     value: { type: [String, Number, Boolean, Object], default: undefined },
@@ -40,7 +40,7 @@ const updateValue = () => {
                 break;
             case 'object':
                 if (props.value instanceof Date) {
-                    t = toDateString(props.value);
+                    t = toDateHourMinSec(props.value);
                 } else {
                     t = props.value.toString();
                 }
diff --git a/src/components/common/VnLog.vue b/src/components/common/VnLog.vue
index 8f106a9f1..e2f18866a 100644
--- a/src/components/common/VnLog.vue
+++ b/src/components/common/VnLog.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, onUnmounted, watch } from 'vue';
+import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute, useRouter } from 'vue-router';
 import axios from 'axios';
@@ -10,12 +10,12 @@ import { useColor } from 'src/composables/useColor';
 import { useCapitalize } from 'src/composables/useCapitalize';
 import { useValidator } from 'src/composables/useValidator';
 import VnAvatar from '../ui/VnAvatar.vue';
-import VnJsonValue from '../common/VnJsonValue.vue';
-import FetchData from '../FetchData.vue';
-import VnSelect from './VnSelect.vue';
+import VnLogValue from './VnLogValue.vue';
 import VnUserLink from '../ui/VnUserLink.vue';
 import VnPaginate from '../ui/VnPaginate.vue';
+import VnLogFilter from 'src/components/common/VnLogFilter.vue';
 import RightMenu from './RightMenu.vue';
+import { useFilterParams } from 'src/composables/useFilterParams';
 
 const stateStore = useStateStore();
 const validationsStore = useValidator();
@@ -72,39 +72,8 @@ const filter = {
 };
 
 const paginate = ref();
-const actions = ref();
-const changeInput = ref();
-const searchInput = ref();
-const userRadio = ref();
-const userSelect = ref();
-const dateFrom = ref();
-const dateFromDialog = ref(false);
-const dateTo = ref();
-const dateToDialog = ref(false);
-const selectedFilters = ref({});
-const userTypes = [
-    { label: 'All', value: undefined },
-    { label: 'User', value: { neq: null } },
-    { label: 'System', value: null },
-];
-const checkboxOptions = ref({
-    insert: {
-        label: 'Creates',
-        selected: false,
-    },
-    update: {
-        label: 'Edits',
-        selected: false,
-    },
-    delete: {
-        label: 'Deletes',
-        selected: false,
-    },
-    select: {
-        label: 'Accesses',
-        selected: false,
-    },
-});
+const dataKey = computed(() => `${props.model}Log`);
+const userParams = ref(useFilterParams(dataKey.value).params);
 
 let validations = models;
 let pointRecord = ref(null);
@@ -246,131 +215,55 @@ async function setLogTree(data) {
 function filterByRecord(modelLog) {
     byRecord.value = true;
     const { id, model } = modelLog;
-
-    searchInput.value = id;
-    selectedFilters.value.changedModelId = id;
-    selectedFilters.value.changedModel = model;
-    applyFilter();
+    applyFilter({ changedModelId: id, changedModel: model });
 }
 
-async function applyFilter() {
-    filter.where = { and: [] };
-    if (
-        !selectedFilters.value.changedModel ||
-        (!selectedFilters.value.changedModelValue &&
-            !selectedFilters.value.changedModelId)
-    )
-        byRecord.value = false;
-
-    if (!byRecord.value) filter.where.and.push({ originFk: route.params.id });
-
-    if (Object.keys(selectedFilters.value).length) {
-        filter.where.and.push(selectedFilters.value);
-    }
-
-    paginate.value.fetch({ filter });
+async function applyFilter(params = {}) {
+    paginate.value.arrayData.resetPagination();
+    paginate.value.arrayData.applyFilter({
+        filter: {},
+        params: { originFk: route.params.id, ...params },
+    });
 }
 
-function setDate(type) {
-    let from = dateFrom.value
-        ? date.formatDate(dateFrom.value.split('-').reverse().join('-'), 'YYYY-MM-DD')
-        : undefined;
-    from = date.adjustDate(from, { hour: 0, minute: 0, second: 0, millisecond: 0 }, true);
-
-    let to = dateTo.value
-        ? date.formatDate(dateTo.value.split('-').reverse().join('-'), 'YYYY-MM-DD')
-        : date.formatDate(dateFrom.value.split('-').reverse().join('-'), 'YYYY-MM-DD');
-    to = date.adjustDate(
-        to,
-        { hour: 21, minute: 59, second: 59, millisecond: 999 },
-        true,
-    );
-
-    switch (type) {
-        case 'from':
-            return { between: [from, to] };
-        case 'to': {
-            if (dateFrom.value) {
+function exprBuilder(param, value) {
+    switch (param) {
+        case 'changedModelValue':
+            return { [param]: { like: `%${value}%` } };
+        case 'change':
+            if (value)
                 return {
-                    between: [from, to],
+                    or: [
+                        { oldJson: { like: `%${value}%` } },
+                        { newJson: { like: `%${value}%` } },
+                        { description: { like: `%${value}%` } },
+                    ],
                 };
-            }
-            return { lte: to };
-        }
+            break;
+        case 'action':
+            if (value?.length) return { [param]: { inq: value } };
+            break;
+        case 'from':
+            return { creationDate: { gte: value } };
+        case 'to':
+            return { creationDate: { lte: value } };
+        case 'userType':
+            if (value === 'User') return { userFk: { neq: null } };
+            if (value === 'System') return { userFk: null };
+            break;
+        default:
+            return { [param]: value };
     }
 }
 
-function selectFilter(type, dateType) {
-    const filter = {};
-    const actions = { inq: [] };
-    let reload = true;
-
-    if (type === 'search') {
-        if (/^\s*[0-9]+\s*$/.test(searchInput.value) || props.byRecord) {
-            selectedFilters.value.changedModelId = searchInput.value.trim();
-        } else if (!searchInput.value) {
-            selectedFilters.value.changedModelId = undefined;
-            selectedFilters.value.changedModelValue = undefined;
-        } else {
-            selectedFilters.value.changedModelValue = { like: `%${searchInput.value}%` };
-        }
-    }
-    if (type === 'action' && selectedFilters.value.changedModel === null) {
-        selectedFilters.value.changedModel = undefined;
-    }
-    if (type === 'userRadio') {
-        selectedFilters.value.userFk = userRadio.value;
-    }
-    if (type === 'change') {
-        if (changeInput.value)
-            selectedFilters.value.or = [
-                { oldJson: { like: `%${changeInput.value}%` } },
-                { newJson: { like: `%${changeInput.value}%` } },
-                { description: { like: `%${changeInput.value}%` } },
-            ];
-        else selectedFilters.value.or = undefined;
-    }
-    if (type === 'userSelect') {
-        selectedFilters.value.userFk =
-            userSelect.value !== null ? userSelect.value : undefined;
-    }
-    if (type === 'date') {
-        if (!dateFrom.value && !dateTo.value) {
-            selectedFilters.value.creationDate = undefined;
-        } else if (dateType === 'to') {
-            selectedFilters.value.creationDate = setDate('to');
-        } else if (dateType === 'from') {
-            selectedFilters.value.creationDate = setDate('from');
-        }
-    }
-
-    Object.keys(checkboxOptions.value).forEach((key) => {
-        if (checkboxOptions.value[key].selected) actions.inq.push(key);
-    });
-    selectedFilters.value.action = actions.inq.length ? actions : undefined;
-
-    Object.keys(selectedFilters.value).forEach((key) => {
-        if (selectedFilters.value[key]) filter[key] = selectedFilters.value[key];
-    });
-
-    if (reload) applyFilter(filter);
-}
-
 async function clearFilter() {
-    selectedFilters.value = {};
     byRecord.value = false;
-    userSelect.value = undefined;
-    searchInput.value = undefined;
-    changeInput.value = undefined;
-    dateFrom.value = undefined;
-    dateTo.value = undefined;
-    userRadio.value = undefined;
-    Object.keys(checkboxOptions.value).forEach(
-        (opt) => (checkboxOptions.value[opt].selected = false),
-    );
     await applyFilter();
 }
 
+onMounted(() => {
+    stateStore.rightDrawerChangeValue(true);
+});
 onUnmounted(() => {
     stateStore.rightDrawer = false;
 });
@@ -383,32 +276,18 @@ watch(
 );
 </script>
 <template>
-    <FetchData
-        :url="`${props.model}Logs/${route.params.id}/models`"
-        :filter="{ order: ['changedModel'] }"
-        @on-fetch="
-            (data) =>
-                (actions = data.map((item) => {
-                    const changedModel = item.changedModel;
-                    return {
-                        locale: useCapitalize(
-                            validations[changedModel]?.locale?.name ?? changedModel,
-                        ),
-                        value: changedModel,
-                    };
-                }))
-        "
-        auto-load
-    />
     <VnPaginate
         ref="paginate"
-        :data-key="`${model}Log`"
-        :url="`${model}Logs`"
+        :data-key
+        :url="dataKey + 's'"
         :user-filter="filter"
         :skeleton="false"
         auto-load
         @on-fetch="setLogTree"
+        @on-change="setLogTree"
         search-url="logs"
+        :exprBuilder
+        :order="['creationDate DESC', 'id DESC']"
     >
         <template #body>
             <div
@@ -467,6 +346,7 @@ watch(
                                             backgroundColor: useColor(modelLog.model),
                                         }"
                                         :title="`${modelLog.model} #${modelLog.id}`"
+                                        data-cy="vnLog-model-chip"
                                     >
                                         {{ t(modelLog.modelI18n) }}
                                     </QChip>
@@ -560,10 +440,9 @@ watch(
                                                                             value.nameI18n
                                                                         }}:
                                                                     </span>
-                                                                    <VnJsonValue
-                                                                        :value="
-                                                                            value.val.val
-                                                                        "
+                                                                    <VnLogValue
+                                                                        :value="value.val"
+                                                                        :name="value.name"
                                                                     />
                                                                 </QItem>
                                                             </QCardSection>
@@ -581,6 +460,7 @@ watch(
                                                             }`,
                                                         )
                                                     "
+                                                    data-cy="vnLog-action-icon"
                                                 />
                                             </div>
                                         </QItem>
@@ -614,7 +494,10 @@ watch(
                                                     >
                                                         {{ prop.nameI18n }}:
                                                     </span>
-                                                    <VnJsonValue :value="prop.val.val" />
+                                                    <VnLogValue
+                                                        :value="prop.val"
+                                                        :name="prop.name"
+                                                    />
                                                     <span
                                                         v-if="
                                                             propIndex <
@@ -642,8 +525,9 @@ watch(
                                                         {{ prop.nameI18n }}:
                                                     </span>
                                                     <span v-if="log.action == 'update'">
-                                                        <VnJsonValue
-                                                            :value="prop.old.val"
+                                                        <VnLogValue
+                                                            :value="prop.old"
+                                                            :name="prop.name"
                                                         />
                                                         <span
                                                             v-if="prop.old.id"
@@ -652,8 +536,9 @@ watch(
                                                             #{{ prop.old.id }}
                                                         </span>
                                                         →
-                                                        <VnJsonValue
-                                                            :value="prop.val.val"
+                                                        <VnLogValue
+                                                            :value="prop.val"
+                                                            :name="prop.name"
                                                         />
                                                         <span
                                                             v-if="prop.val.id"
@@ -663,8 +548,9 @@ watch(
                                                         </span>
                                                     </span>
                                                     <span v-else="prop.old.val">
-                                                        <VnJsonValue
-                                                            :value="prop.val.val"
+                                                        <VnLogValue
+                                                            :value="prop.val"
+                                                            :name="prop.name"
                                                         />
                                                         <span
                                                             v-if="prop.old.id"
@@ -692,176 +578,12 @@ watch(
     </VnPaginate>
     <RightMenu>
         <template #right-panel>
-            <QList dense>
-                <QSeparator />
-                <QItem class="q-mt-sm">
-                    <QInput
-                        :label="t('globals.search')"
-                        v-model="searchInput"
-                        class="full-width"
-                        clearable
-                        clear-icon="close"
-                        @keyup.enter="() => selectFilter('search')"
-                        @focusout="() => selectFilter('search')"
-                        @clear="() => selectFilter('search')"
-                    >
-                        <template #append>
-                            <QIcon name="info" class="cursor-pointer">
-                                <QTooltip>{{ t('tooltips.search') }}</QTooltip>
-                            </QIcon>
-                        </template>
-                    </QInput>
-                </QItem>
-                <QItem>
-                    <VnSelect
-                        class="full-width"
-                        :label="t('globals.entity')"
-                        v-model="selectedFilters.changedModel"
-                        option-label="locale"
-                        option-value="value"
-                        :options="actions"
-                        @update:model-value="selectFilter('action')"
-                        hide-selected
-                    />
-                </QItem>
-                <QItem class="q-mt-sm">
-                    <QOptionGroup
-                        size="sm"
-                        v-model="userRadio"
-                        :options="userTypes"
-                        color="primary"
-                        @update:model-value="selectFilter('userRadio')"
-                        right-label
-                    >
-                        <template #label="{ label }">
-                            {{ t(`Users.${label}`) }}
-                        </template>
-                    </QOptionGroup>
-                </QItem>
-                <QItem class="q-mt-sm">
-                    <QItemSection v-if="userRadio !== null">
-                        <VnSelect
-                            class="full-width"
-                            :label="t('globals.user')"
-                            v-model="userSelect"
-                            option-label="name"
-                            option-value="id"
-                            :url="`${model}Logs/${route.params.id}/editors`"
-                            :fields="['id', 'nickname', 'name', 'image']"
-                            sort-by="nickname"
-                            @update:model-value="selectFilter('userSelect')"
-                            hide-selected
-                        >
-                            <template #option="{ opt, itemProps }">
-                                <QItem
-                                    v-bind="itemProps"
-                                    class="q-pa-xs row items-center"
-                                >
-                                    <QItemSection class="col-3 items-center">
-                                        <VnAvatar :worker-id="opt.id" />
-                                    </QItemSection>
-                                    <QItemSection class="col-9 justify-center">
-                                        <span>{{ opt.name }}</span>
-                                        <span class="text-grey">{{ opt.nickname }}</span>
-                                    </QItemSection>
-                                </QItem>
-                            </template>
-                        </VnSelect>
-                    </QItemSection>
-                </QItem>
-                <QItem class="q-mt-sm">
-                    <QInput
-                        :label="t('globals.changes')"
-                        v-model="changeInput"
-                        class="full-width"
-                        clearable
-                        clear-icon="close"
-                        @keyup.enter="selectFilter('change')"
-                        @focusout="selectFilter('change')"
-                        @clear="selectFilter('change')"
-                    >
-                        <template #append>
-                            <QIcon name="info" class="cursor-pointer">
-                                <QTooltip max-width="250px">{{
-                                    t('tooltips.changes')
-                                }}</QTooltip>
-                            </QIcon>
-                        </template>
-                    </QInput>
-                </QItem>
-                <QItem
-                    :class="index == 'create' ? 'q-mt-md' : 'q-mt-xs'"
-                    v-for="(checkboxOption, index) in checkboxOptions"
-                    :key="index"
-                >
-                    <QCheckbox
-                        size="sm"
-                        v-model="checkboxOption.selected"
-                        :label="t(`actions.${checkboxOption.label}`)"
-                        @update:model-value="selectFilter"
-                    />
-                </QItem>
-                <QItem class="q-mt-sm">
-                    <QInput
-                        class="full-width"
-                        :label="t('globals.date')"
-                        @click="dateFromDialog = true"
-                        @focus="(evt) => evt.target.blur()"
-                        @clear="selectFilter('date', 'to')"
-                        v-model="dateFrom"
-                        clearable
-                        clear-icon="close"
-                    />
-                </QItem>
-                <QItem class="q-mt-sm">
-                    <QInput
-                        class="full-width"
-                        :label="t('globals.to')"
-                        @click="dateToDialog = true"
-                        @focus="(evt) => evt.target.blur()"
-                        @clear="selectFilter('date', 'from')"
-                        v-model="dateTo"
-                        clearable
-                        clear-icon="close"
-                    />
-                </QItem>
-            </QList>
+            <VnLogFilter :data-key />
         </template>
     </RightMenu>
-    <QDialog v-model="dateFromDialog">
-        <QDate
-            :years-in-month-view="false"
-            v-model="dateFrom"
-            dense
-            flat
-            minimal
-            @update:model-value="
-                (value) => {
-                    dateFromDialog = false;
-                    dateFrom = date.formatDate(value, 'DD-MM-YYYY');
-                    selectFilter('date', 'from');
-                }
-            "
-        />
-    </QDialog>
-    <QDialog v-model="dateToDialog">
-        <QDate
-            v-model="dateTo"
-            dense
-            flat
-            minimal
-            @update:model-value="
-                (value) => {
-                    dateToDialog = false;
-                    dateTo = date.formatDate(value, 'DD-MM-YYYY');
-                    selectFilter('date', 'to');
-                }
-            "
-        />
-    </QDialog>
     <QPageSticky position="bottom-right" :offset="[25, 25]">
         <QBtn
-            v-if="Object.values(selectedFilters).some((filter) => filter !== undefined)"
+            v-if="Object.keys(userParams).some((filter) => filter !== 'originFk')"
             color="primary"
             icon="filter_alt_off"
             size="md"
diff --git a/src/components/common/VnLogFilter.vue b/src/components/common/VnLogFilter.vue
index b5941239c..c7be68e9e 100644
--- a/src/components/common/VnLogFilter.vue
+++ b/src/components/common/VnLogFilter.vue
@@ -1,77 +1,249 @@
 <script setup>
-import { ref } from 'vue';
 import { useI18n } from 'vue-i18n';
-import FetchData from 'components/FetchData.vue';
-import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
+import VnTableFilter from '../VnTable/VnTableFilter.vue';
+import VnSelect from './VnSelect.vue';
+import { useRoute } from 'vue-router';
+import VnInput from './VnInput.vue';
+import { ref, computed, watch } from 'vue';
+import VnInputDate from './VnInputDate.vue';
+import { useFilterParams } from 'src/composables/useFilterParams';
+import FetchData from '../FetchData.vue';
+import { useValidator } from 'src/composables/useValidator';
+import { useCapitalize } from 'src/composables/useCapitalize';
+import VnAvatar from '../ui/VnAvatar.vue';
 
-const { t } = useI18n();
-const props = defineProps({
+const $props = defineProps({
     dataKey: {
         type: String,
-        required: true,
+        default: null,
     },
 });
 
-const workers = ref();
+const { t } = useI18n();
+const route = useRoute();
+const validationsStore = useValidator();
+const { models } = validationsStore;
+const entities = ref([]);
+const editors = ref([]);
+const userParams = ref(useFilterParams($props.dataKey).params);
+let validations = models;
+const userTypes = [
+    { value: 'All', label: t(`Users.All`) },
+    { value: 'User', label: t(`Users.User`) },
+    { value: 'System', label: t(`Users.System`) },
+];
+const checkboxOptions = ref([
+    { name: 'insert', label: 'Creates', selected: false },
+    { name: 'update', label: 'Edits', selected: false },
+    { name: 'delete', label: 'Deletes', selected: false },
+    { name: 'select', label: 'Accesses', selected: false },
+]);
+const columns = computed(() => [
+    { name: 'changedModelValue' },
+    { name: 'changedModel' },
+    { name: 'userType', orderBy: false },
+    { name: 'userFk' },
+    { name: 'change', orderBy: false },
+    { name: 'action' },
+    { name: 'from', orderBy: 'creationDate' },
+    { name: 'to', orderBy: 'creationDate' },
+]);
+
+const userParamsWatcher = watch(
+    () => userParams.value,
+    (params) => {
+        if (params.action) {
+            params.action.forEach((option) => {
+                checkboxOptions.value.find((o) => o.name === option).selected = true;
+            });
+            userParamsWatcher();
+        }
+    },
+);
+
+function getActions() {
+    const actions = checkboxOptions.value
+        .filter((option) => option.selected)
+        ?.map((o) => o.name);
+    return actions.length ? actions : null;
+}
 </script>
 
 <template>
     <FetchData
-        url="Workers/activeWithInheritedRole"
-        :filter="{ where: { role: 'salesPerson' } }"
-        @on-fetch="(data) => (workers = data)"
+        :url="`${dataKey}s/${route.params.id}/models`"
+        :filter="{ order: ['changedModel'] }"
+        @on-fetch="
+            (data) =>
+                (entities = data.map((item) => {
+                    const changedModel = item.changedModel;
+                    return {
+                        locale: useCapitalize(
+                            validations[changedModel]?.locale?.name ?? changedModel,
+                        ),
+                        value: changedModel,
+                    };
+                }))
+        "
         auto-load
     />
-    <VnFilterPanel :data-key="props.dataKey" :search-button="true">
-        <template #tags="{ tag, formatFn }">
-            <div class="q-gutter-x-xs">
-                <strong>{{ t(`params.${tag.label}`) }}: </strong>
-                <span>{{ formatFn(tag.value) }}</span>
+    <FetchData
+        :url="`${dataKey}s/${route.params.id}/editors`"
+        :filter="{ fields: ['id', 'nickname', 'name', 'image'] }"
+        sort-by="nickname"
+        @on-fetch="(data) => (editors = data)"
+        auto-load
+    />
+    <VnTableFilter
+        v-if="dataKey"
+        :data-key
+        :columns="columns"
+        :redirect="false"
+        :hiddenTags="['originFk', 'creationDate']"
+        search-url="logs"
+        :showTagChips="false"
+    >
+        <template #filter-changedModelValue="{ params, columnName, searchFn }">
+            <VnInput
+                :label="t('globals.search')"
+                v-model="params[columnName]"
+                @keyup.enter="searchFn"
+                @blur="searchFn"
+                @remove="searchFn"
+                :info="t('tooltips.search')"
+                dense
+                filled
+                data-cy="vnLog-search"
+            />
+        </template>
+        <template #filter-changedModel="{ params, columnName, searchFn }">
+            <VnSelect
+                :label="t('globals.entity')"
+                v-model="params[columnName]"
+                option-label="locale"
+                option-value="value"
+                :options="entities"
+                @update:model-value="() => searchFn()"
+                dense
+                filled
+                data-cy="vnLog-entity"
+            />
+        </template>
+        <template #filter-userType="{ params, columnName, searchFn }">
+            <QOptionGroup
+                class="text-left"
+                size="sm"
+                v-model="params[columnName]"
+                :options="userTypes"
+                color="primary"
+                @update:model-value="
+                    () => {
+                        params.userFk = null;
+                        searchFn();
+                    }
+                "
+            />
+        </template>
+        <template #filter-userFk="{ params, columnName, searchFn }">
+            <VnSelect
+                :label="t('globals.user')"
+                v-model="params[columnName]"
+                :options="editors"
+                @update:modelValue="() => searchFn()"
+                :disable="params.userType === 'System'"
+                dense
+                filled
+            >
+                <template #option="{ opt, itemProps }">
+                    <QItem v-bind="itemProps" class="q-pa-xs row items-center">
+                        <QItemSection class="col-3 items-center">
+                            <VnAvatar :worker-id="opt.id" />
+                        </QItemSection>
+                        <QItemSection class="col-9 justify-center">
+                            <span>{{ opt.name }}</span>
+                            <span class="text-grey">{{ opt.nickname }}</span>
+                        </QItemSection>
+                    </QItem>
+                </template>
+            </VnSelect>
+        </template>
+        <template #filter-change="{ params, columnName, searchFn }">
+            <VnInput
+                :label="t('globals.changes')"
+                v-model="params[columnName]"
+                @keyup.enter="searchFn"
+                @blur="searchFn"
+                @remove="searchFn"
+                :info="t('tooltips.changes')"
+                dense
+                filled
+            />
+        </template>
+        <template #filter-action="{ searchFn }">
+            <div class="column">
+                <QCheckbox
+                    v-for="checkboxOption in checkboxOptions"
+                    :key="checkboxOption"
+                    size="sm"
+                    v-model="checkboxOption.selected"
+                    :label="t(`actions.${checkboxOption.label}`)"
+                    @update:model-value="
+                        () => searchFn(undefined, 'action', getActions())
+                    "
+                    data-cy="vnLog-checkbox"
+                />
             </div>
         </template>
-        <template #body="{ params, searchFn }">
-            <QDate
-                v-model="params.created"
-                @update:model-value="searchFn()"
+        <template #filter-from="{ params, columnName, searchFn }">
+            <VnInputDate
+                :label="t('globals.from')"
+                v-model="params[columnName]"
                 dense
-                flat
-                minimal
-            >
-            </QDate>
-            <QSeparator />
-            <QItem>
-                <QItemSection v-if="!workers">
-                    <QSkeleton type="QInput" class="full-width" />
-                </QItemSection>
-                <QItemSection v-if="workers">
-                    <QSelect
-                        :label="t('User')"
-                        v-model="params.userFk"
-                        @update:model-value="searchFn()"
-                        :options="workers"
-                        option-value="id"
-                        option-label="name"
-                        emit-value
-                        map-options
-                        use-input
-                        :input-debounce="0"
-                    />
-                </QItemSection>
-            </QItem>
+                filled
+                @update:modelValue="() => searchFn()"
+            />
         </template>
-    </VnFilterPanel>
+        <template #filter-to="{ params, columnName, searchFn }">
+            <VnInputDate
+                :label="t('globals.to')"
+                v-model="params[columnName]"
+                dense
+                filled
+                @update:modelValue="() => searchFn()"
+            />
+        </template>
+    </VnTableFilter>
 </template>
-
 <i18n>
-en:
-    params:
-        search: Contains
-        userFk: User
-        created: Created
 es:
+    tooltips:
+        search: Buscar por identificador o concepto
+        changes: Buscar por cambios. Los atributos deben buscarse por su nombre interno, para obtenerlo situar el cursor sobre el atributo.
+    actions:
+        Creates: Crea
+        Edits: Modifica
+        Deletes: Elimina
+        Accesses: Accede
+    Users:
+        User: Usuario
+        All: Todo
+        System: Sistema
     params:
-        search: Contiene
-        userFk: Usuario
-        created: Creada
-    User: Usuario
+        changedModel: Entity
+
+en:
+    tooltips:
+        search: Search by identifier or concept
+        changes: Search by changes. Attributes must be searched by their internal name, to get it place the cursor over the attribute.
+    actions:
+        Creates: Creates
+        Edits: Edits
+        Deletes: Deletes
+        Accesses: Accesses
+    Users:
+        User: User
+        All: All
+        System: System
+    params:
+        changedModel: Entidad
 </i18n>
diff --git a/src/components/common/VnLogValue.vue b/src/components/common/VnLogValue.vue
new file mode 100644
index 000000000..3f1617ce7
--- /dev/null
+++ b/src/components/common/VnLogValue.vue
@@ -0,0 +1,28 @@
+<script setup>
+import { useDescriptorStore } from 'src/stores/useDescriptorStore';
+import VnJsonValue from './VnJsonValue.vue';
+import { computed } from 'vue';
+const descriptorStore = useDescriptorStore();
+
+const $props = defineProps({
+    value: { type: Object, default: () => {} },
+    name: { type: String, default: undefined },
+});
+
+const descriptor = computed(() => descriptorStore.has($props.name));
+</script>
+<template>
+    <VnJsonValue :value="value.val" />
+    <span
+        v-if="(value.id || typeof value.val == 'number') && descriptor"
+        style="margin-left: 2px"
+    >
+        <QIcon
+            name="launch"
+            class="link"
+            :data-cy="'iconLaunch-' + $props.name"
+            style="padding-bottom: 2px"
+        />
+        <component :is="descriptor" :id="value.id ?? value.val" />
+    </span>
+</template>
diff --git a/src/components/common/VnSection.vue b/src/components/common/VnSection.vue
index 4bd17124f..34eb14601 100644
--- a/src/components/common/VnSection.vue
+++ b/src/components/common/VnSection.vue
@@ -40,10 +40,6 @@ const $props = defineProps({
         type: Boolean,
         default: true,
     },
-    keepData: {
-        type: Boolean,
-        default: true,
-    },
 });
 
 const route = useRoute();
@@ -61,7 +57,6 @@ onBeforeMount(() => {
     if ($props.dataKey)
         arrayData = useArrayData($props.dataKey, {
             searchUrl: 'table',
-            keepData: $props.keepData,
             ...$props.arrayDataProps,
             navigate: $props.redirect,
         });
diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue
index 9433ec819..944a2c6d9 100644
--- a/src/components/common/VnSelect.vue
+++ b/src/components/common/VnSelect.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue';
+import { ref, toRefs, computed, watch, onMounted, useAttrs, nextTick } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useArrayData } from 'src/composables/useArrayData';
 import { useRequired } from 'src/composables/useRequired';
@@ -152,6 +152,10 @@ const value = computed({
     },
 });
 
+const computedSortBy = computed(() => {
+    return $props.sortBy || $props.optionLabel + ' ASC';
+});
+
 watch(options, (newValue) => {
     setOptions(newValue);
 });
@@ -186,7 +190,7 @@ function findKeyInOptions() {
 }
 
 function setOptions(data) {
-    data = dataByOrder(data, $props.sortBy);
+    data = dataByOrder(data, computedSortBy.value);
     myOptions.value = JSON.parse(JSON.stringify(data));
     myOptionsOriginal.value = JSON.parse(JSON.stringify(data));
     emit('update:options', data);
@@ -216,7 +220,8 @@ function filter(val, options) {
 async function fetchFilter(val) {
     if (!$props.url) return;
 
-    const { fields, include, sortBy, limit } = $props;
+    const { fields, include, limit } = $props;
+    const sortBy = computedSortBy.value;
     const key =
         optionFilterValue.value ??
         (new RegExp(/\d/g).test(val)
@@ -295,6 +300,7 @@ async function onScroll({ to, direction, from, index }) {
         await arrayData.loadMore();
         setOptions(arrayData.store.data);
         vnSelectRef.value.scrollTo(lastIndex);
+        await nextTick();
         isLoading.value = false;
     }
 }
diff --git a/src/components/common/__tests__/VnChangePassword.spec.js b/src/components/common/__tests__/VnChangePassword.spec.js
index f5a967bb5..b610ce44d 100644
--- a/src/components/common/__tests__/VnChangePassword.spec.js
+++ b/src/components/common/__tests__/VnChangePassword.spec.js
@@ -1,4 +1,5 @@
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import VnChangePassword from 'src/components/common/VnChangePassword.vue';
 import { vi, beforeEach, afterEach, beforeAll, describe, expect, it } from 'vitest';
 import { Notify } from 'quasar';
diff --git a/src/components/common/__tests__/VnDms.spec.js b/src/components/common/__tests__/VnDms.spec.js
index d12bd781d..a2fdb4810 100644
--- a/src/components/common/__tests__/VnDms.spec.js
+++ b/src/components/common/__tests__/VnDms.spec.js
@@ -1,4 +1,5 @@
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
 import { vi, afterEach, beforeEach, beforeAll, describe, expect, it } from 'vitest';
 import VnDms from 'src/components/common/VnDms.vue';
 
@@ -40,12 +41,10 @@ describe('VnDms', () => {
         companyFk: 2,
         dmsTypeFk: 3,
         description: 'This is a test description',
-        files: [
-            {
-                name: 'example.txt',
-                content: new Blob(['file content'], { type: 'text/plain' }),
-            },
-        ],
+        files: {
+            name: 'example.txt',
+            content: new Blob(['file content'], { type: 'text/plain' }),
+        },
     };
 
     const expectedBody = {
diff --git a/src/components/common/__tests__/VnDmsList.spec.js b/src/components/common/__tests__/VnDmsList.spec.js
index deb78d62c..ee62f6971 100644
--- a/src/components/common/__tests__/VnDmsList.spec.js
+++ b/src/components/common/__tests__/VnDmsList.spec.js
@@ -1,4 +1,6 @@
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
+
 import VnDmsList from 'src/components/common/VnDmsList.vue';
 import { vi, afterEach, beforeAll, describe, expect, it } from 'vitest';
 
@@ -10,6 +12,9 @@ describe('VnDmsList', () => {
     };
 
     beforeAll(() => {
+        vi.mock('src/composables/getUrl', () => ({
+            getUrl: vi.fn().mockResolvedValue(''),
+        }));
         vi.spyOn(axios, 'get').mockResolvedValue({ data: [] });
         vm = createWrapper(VnDmsList, {
             props: {
diff --git a/src/components/common/__tests__/VnJsonValue.spec.js b/src/components/common/__tests__/VnJsonValue.spec.js
index 393b39f3a..c3aa1a769 100644
--- a/src/components/common/__tests__/VnJsonValue.spec.js
+++ b/src/components/common/__tests__/VnJsonValue.spec.js
@@ -65,7 +65,7 @@ describe('VnJsonValue', () => {
         const date = new Date('2023-01-01');
         const wrapper = buildComponent({ value: date });
         const span = wrapper.find('span');
-        expect(span.text()).toBe('2023-01-01');
+        expect(span.text()).toBe('01/01/2023, 01:00:00');
         expect(span.classes()).toContain('json-object');
     });
 
diff --git a/src/components/common/__tests__/VnLog.spec.js b/src/components/common/__tests__/VnLog.spec.js
index 53d2732a0..fcb516cc5 100644
--- a/src/components/common/__tests__/VnLog.spec.js
+++ b/src/components/common/__tests__/VnLog.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import VnLog from 'src/components/common/VnLog.vue';
 
 describe('VnLog', () => {
@@ -108,27 +109,4 @@ describe('VnLog', () => {
         expect(vm.logTree[0].originFk).toEqual(1);
         expect(vm.logTree[0].logs[0].user.name).toEqual('salesPerson');
     });
-
-    it('should correctly set the selectedFilters when filtering', () => {
-        vm.searchInput = '1';
-        vm.userSelect = '21';
-        vm.checkboxOptions.insert.selected = true;
-        vm.checkboxOptions.update.selected = true;
-
-        vm.selectFilter('search');
-        vm.selectFilter('userSelect');
-
-        expect(vm.selectedFilters.changedModelId).toEqual('1');
-        expect(vm.selectedFilters.userFk).toEqual('21');
-        expect(vm.selectedFilters.action).toEqual({ inq: ['insert', 'update'] });
-    });
-
-    it('should correctly set the date from', () => {
-        vm.dateFrom = '18-09-2023';
-        vm.selectFilter('date', 'from');
-        expect(vm.selectedFilters.creationDate.between).toEqual([
-            new Date('2023-09-18T00:00:00.000Z'),
-            new Date('2023-09-18T21:59:59.999Z'),
-        ]);
-    });
 });
diff --git a/src/components/common/__tests__/VnLogFilter.spec.js b/src/components/common/__tests__/VnLogFilter.spec.js
new file mode 100644
index 000000000..a28fa85b1
--- /dev/null
+++ b/src/components/common/__tests__/VnLogFilter.spec.js
@@ -0,0 +1,28 @@
+import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
+import { createWrapper } from 'app/test/vitest/helper';
+import VnLogFilter from 'src/components/common/VnLogFilter.vue';
+
+describe('VnLogFilter', () => {
+    let vm;
+    beforeAll(async () => {
+        vm = createWrapper(VnLogFilter, {
+            props: {
+                dataKey: 'ClaimLog',
+            },
+        }).vm;
+    });
+
+    afterEach(() => {
+        vi.clearAllMocks();
+    });
+
+    it('should getActions selected', async () => {
+        vm.checkboxOptions.find((o) => o.name == 'insert').selected = true;
+        vm.checkboxOptions.find((o) => o.name == 'update').selected = true;
+
+        const actions = vm.getActions();
+
+        expect(actions.length).toEqual(2);
+        expect(actions).toEqual(['insert', 'update']);
+    });
+});
diff --git a/src/components/common/__tests__/VnLogValue.spec.js b/src/components/common/__tests__/VnLogValue.spec.js
new file mode 100644
index 000000000..c23743a02
--- /dev/null
+++ b/src/components/common/__tests__/VnLogValue.spec.js
@@ -0,0 +1,26 @@
+import { describe, it, expect } from 'vitest';
+import VnLogValue from 'src/components/common/VnLogValue.vue';
+import { createWrapper } from 'app/test/vitest/helper';
+
+const buildComponent = (props) => {
+    return createWrapper(VnLogValue, {
+        props,
+        global: {},
+    }).wrapper;
+};
+
+describe('VnLogValue', () => {
+    const id = 1;
+    it('renders without descriptor', async () => {
+        expect(getIcon('inventFk').exists()).toBe(false);
+    });
+
+    it('renders with descriptor', async () => {
+        expect(getIcon('claimFk').text()).toBe('launch');
+    });
+
+    function getIcon(name) {
+        const wrapper = buildComponent({ value: { val: id }, name });
+        return wrapper.find('.q-icon');
+    }
+});
diff --git a/src/components/common/__tests__/VnNotes.spec.js b/src/components/common/__tests__/VnNotes.spec.js
index 6a10dc097..0d256a736 100644
--- a/src/components/common/__tests__/VnNotes.spec.js
+++ b/src/components/common/__tests__/VnNotes.spec.js
@@ -1,5 +1,6 @@
 import { describe, it, expect, vi, afterEach, beforeEach, afterAll } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
 import VnNotes from 'src/components/ui/VnNotes.vue';
 
 describe('VnNotes', () => {
@@ -8,6 +9,7 @@ describe('VnNotes', () => {
     let spyFetch;
     let postMock;
     let patchMock;
+    let deleteMock;
     let expectedInsertBody;
     let expectedUpdateBody;
     const defaultOptions = {
@@ -47,6 +49,7 @@ describe('VnNotes', () => {
     beforeEach(() => {
         postMock = vi.spyOn(axios, 'post');
         patchMock = vi.spyOn(axios, 'patch');
+        deleteMock = vi.spyOn(axios, 'delete');
     });
 
     afterEach(() => {
@@ -143,4 +146,16 @@ describe('VnNotes', () => {
             );
         });
     });
+
+    describe('delete', () => {
+        it('Should call axios.delete with url and vnPaginateRef.fetch', async () => {
+            generateWrapper();
+            createSpyFetch();
+
+            await vm.deleteNote({ id: 1 });
+
+            expect(deleteMock).toHaveBeenCalledWith(`${vm.$props.url}/1`);
+            expect(spyFetch).toHaveBeenCalled();
+        });
+    });
 });
diff --git a/src/components/ui/CardDescriptor.vue b/src/components/ui/CardDescriptor.vue
index a29d1d429..5f9a89d64 100644
--- a/src/components/ui/CardDescriptor.vue
+++ b/src/components/ui/CardDescriptor.vue
@@ -1,332 +1,38 @@
 <script setup>
-import { onBeforeMount, watch, computed, ref } from 'vue';
-import { useI18n } from 'vue-i18n';
-import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
-import { useArrayData } from 'composables/useArrayData';
-import { useSummaryDialog } from 'src/composables/useSummaryDialog';
-import { useState } from 'src/composables/useState';
-import { useRoute } from 'vue-router';
-import { useClipboard } from 'src/composables/useClipboard';
-import VnMoreOptions from './VnMoreOptions.vue';
+import { ref } from 'vue';
+import VnDescriptor from './VnDescriptor.vue';
 
 const $props = defineProps({
-    url: {
-        type: String,
-        default: '',
-    },
-    filter: {
-        type: Object,
-        default: null,
-    },
-    title: {
-        type: String,
-        default: '',
-    },
-    subtitle: {
+    id: {
         type: Number,
-        default: null,
+        default: false,
     },
-    dataKey: {
-        type: String,
-        default: null,
-    },
-    summary: {
+    card: {
         type: Object,
         default: null,
     },
-    width: {
-        type: String,
-        default: 'md-width',
-    },
 });
 
-const state = useState();
-const route = useRoute();
-const { t } = useI18n();
-const { copyText } = useClipboard();
-const { viewSummary } = useSummaryDialog();
-let arrayData;
-let store;
-let entity;
-const isLoading = ref(false);
-const isSameDataKey = computed(() => $props.dataKey === route.meta.moduleName);
-defineExpose({ getData });
-
-onBeforeMount(async () => {
-    arrayData = useArrayData($props.dataKey, {
-        url: $props.url,
-        userFilter: $props.filter,
-        skip: 0,
-        oneRecord: true,
-    });
-    store = arrayData.store;
-    entity = computed(() => {
-        const data = store.data ?? {};
-        if (data) emit('onFetch', data);
-        return data;
-    });
-
-    // It enables to load data only once if the module is the same as the dataKey
-    if (!isSameDataKey.value || !route.params.id) await getData();
-    watch(
-        () => [$props.url, $props.filter],
-        async () => {
-            if (!isSameDataKey.value) await getData();
-        },
-    );
-});
-
-const routeName = computed(() => {
-    const DESCRIPTOR_PROXY = 'DescriptorProxy';
-
-    let name = $props.dataKey;
-    if ($props.dataKey.includes(DESCRIPTOR_PROXY)) {
-        name = name.split(DESCRIPTOR_PROXY)[0];
-    }
-    return `${name}Summary`;
-});
-async function getData() {
-    store.url = $props.url;
-    store.filter = $props.filter ?? {};
-    isLoading.value = true;
-    try {
-        const { data } = await arrayData.fetch({ append: false, updateRouter: false });
-        state.set($props.dataKey, data);
-        emit('onFetch', data);
-    } finally {
-        isLoading.value = false;
-    }
-}
-
-function getValueFromPath(path) {
-    if (!path) return;
-    const keys = path.toString().split('.');
-    let current = entity.value;
-
-    for (const key of keys) {
-        if (current[key] === undefined) return undefined;
-        else current = current[key];
-    }
-    return current;
-}
-
-function copyIdText(id) {
-    copyText(id, {
-        component: {
-            copyValue: id,
-        },
-    });
-}
-
 const emit = defineEmits(['onFetch']);
-
-const iconModule = computed(() => route.matched[1].meta.icon);
-const toModule = computed(() =>
-    route.matched[1].path.split('/').length > 2
-        ? route.matched[1].redirect
-        : route.matched[1].children[0].redirect,
-);
+const entity = ref();
 </script>
 
 <template>
-    <div class="descriptor">
-        <template v-if="entity && !isLoading">
-            <div class="header bg-primary q-pa-sm justify-between">
-                <slot name="header-extra-action"
-                    ><QBtn
-                        round
-                        flat
-                        dense
-                        size="md"
-                        :icon="iconModule"
-                        color="white"
-                        class="link"
-                        :to="$attrs['to-module'] ?? toModule"
-                    >
-                        <QTooltip>
-                            {{ t('globals.goToModuleIndex') }}
-                        </QTooltip>
-                    </QBtn></slot
-                >
-                <QBtn
-                    @click.stop="viewSummary(entity.id, $props.summary, $props.width)"
-                    round
-                    flat
-                    dense
-                    size="md"
-                    icon="preview"
-                    color="white"
-                    class="link"
-                    v-if="summary"
-                >
-                    <QTooltip>
-                        {{ t('components.smartCard.openSummary') }}
-                    </QTooltip>
-                </QBtn>
-                <RouterLink :to="{ name: routeName, params: { id: entity.id } }">
-                    <QBtn
-                        class="link"
-                        color="white"
-                        dense
-                        flat
-                        icon="launch"
-                        round
-                        size="md"
-                    >
-                        <QTooltip>
-                            {{ t('components.cardDescriptor.summary') }}
-                        </QTooltip>
-                    </QBtn>
-                </RouterLink>
-                <VnMoreOptions v-if="$slots.menu">
-                    <template #menu="{ menuRef }">
-                        <slot name="menu" :entity="entity" :menu-ref="menuRef" />
-                    </template>
-                </VnMoreOptions>
-            </div>
-            <slot name="before" />
-            <div class="body q-py-sm">
-                <QList dense>
-                    <QItemLabel header class="ellipsis text-h5" :lines="1">
-                        <div class="title">
-                            <span v-if="$props.title" :title="getValueFromPath(title)">
-                                {{ getValueFromPath(title) ?? $props.title }}
-                            </span>
-                            <slot v-else name="description" :entity="entity">
-                                <span :title="entity.name">
-                                    {{ entity.name }}
-                                </span>
-                            </slot>
-                        </div>
-                    </QItemLabel>
-                    <QItem>
-                        <QItemLabel class="subtitle">
-                            #{{ getValueFromPath(subtitle) ?? entity.id }}
-                        </QItemLabel>
-                        <QBtn
-                            round
-                            flat
-                            dense
-                            size="sm"
-                            icon="content_copy"
-                            color="primary"
-                            @click.stop="copyIdText(entity.id)"
-                        >
-                            <QTooltip>
-                                {{ t('globals.copyId') }}
-                            </QTooltip>
-                        </QBtn>
-                    </QItem>
-                </QList>
-                <div class="list-box q-mt-xs">
-                    <slot name="body" :entity="entity" />
-                </div>
-            </div>
-            <div class="icons">
-                <slot name="icons" :entity="entity" />
-            </div>
-            <div class="actions justify-center" data-cy="descriptor_actions">
-                <slot name="actions" :entity="entity" />
-            </div>
-            <slot name="after" />
-        </template>
-        <!-- Skeleton -->
-        <SkeletonDescriptor v-if="!entity || isLoading" />
-    </div>
-    <QInnerLoading
-        :label="t('globals.pleaseWait')"
-        :showing="isLoading"
-        color="primary"
-    />
-</template>
-
-<style lang="scss">
-.body {
-    background-color: var(--vn-section-color);
-    .text-h5 {
-        font-size: 20px;
-        padding-top: 5px;
-        padding-bottom: 0px;
-    }
-    .q-item {
-        min-height: 20px;
-
-        .link {
-            margin-left: 10px;
-        }
-    }
-    .vn-label-value {
-        display: flex;
-        padding: 0px 16px;
-        .label {
-            color: var(--vn-label-color);
-            font-size: 14px;
-
-            &:not(:has(a))::after {
-                content: ':';
+    <component
+        :is="card"
+        :id
+        :visual="false"
+        v-bind="$attrs"
+        @on-fetch="
+            (data) => {
+                entity = data;
+                emit('onFetch', data);
             }
-        }
-        .value {
-            color: var(--vn-text-color);
-            font-size: 14px;
-            margin-left: 4px;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-            text-align: left;
-        }
-        .info {
-            margin-left: 5px;
-        }
-    }
-}
-</style>
-
-<style lang="scss" scoped>
-.title {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    span {
-        color: var(--vn-text-color);
-        font-weight: bold;
-    }
-}
-.subtitle {
-    color: var(--vn-text-color);
-    font-size: 16px;
-    margin-bottom: 2px;
-}
-.list-box {
-    .q-item__label {
-        color: var(--vn-label-color);
-        padding-bottom: 0%;
-    }
-}
-.descriptor {
-    width: 256px;
-    .header {
-        display: flex;
-        align-items: center;
-    }
-    .icons {
-        margin: 0 10px;
-        display: flex;
-        justify-content: center;
-        .q-icon {
-            margin-right: 5px;
-        }
-    }
-    .actions {
-        margin: 0 5px;
-        justify-content: center !important;
-    }
-}
-</style>
-<i18n>
-    en:
-        globals:
-            copyId: Copy ID
-    es:
-        globals:
-            copyId: Copiar ID
-</i18n>
+        "
+    />
+    <VnDescriptor v-model="entity" v-bind="$attrs">
+        <template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
+            <slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
+        </template>
+    </VnDescriptor>
+</template>
diff --git a/src/components/ui/CardSummary.vue b/src/components/ui/CardSummary.vue
index 6d43f9426..27794b25f 100644
--- a/src/components/ui/CardSummary.vue
+++ b/src/components/ui/CardSummary.vue
@@ -81,6 +81,7 @@ async function fetch() {
                                 name: `${moduleName ?? route.meta.moduleName}Summary`,
                                 params: { id: entityId || entity.id },
                             }"
+                            data-cy="goToSummaryBtn"
                         >
                             <QIcon name="open_in_new" color="white" size="sm" />
                         </router-link>
@@ -158,6 +159,7 @@ async function fetch() {
                 display: flex;
                 flex-direction: row;
                 margin-top: 2px;
+                align-items: start;
                 .label {
                     color: var(--vn-label-color);
                     width: 9em;
@@ -168,9 +170,15 @@ async function fetch() {
                     flex-grow: 0;
                     flex-shrink: 0;
                 }
+                &.ellipsis > .value {
+                    text-overflow: ellipsis;
+                    white-space: pre;
+                }
                 .value {
                     color: var(--vn-text-color);
                     overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
                 }
             }
             .header {
@@ -200,6 +208,23 @@ async function fetch() {
         }
     }
 }
+
+.vn-card-group {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+    gap: 16px;
+}
+
+.vn-card-content {
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    > div {
+        max-height: 70px;
+    }
+}
 </style>
 <style lang="scss" scoped>
 .summaryHeader .vn-label-value {
diff --git a/src/components/ui/EntityDescriptor.vue b/src/components/ui/EntityDescriptor.vue
new file mode 100644
index 000000000..a5dced551
--- /dev/null
+++ b/src/components/ui/EntityDescriptor.vue
@@ -0,0 +1,78 @@
+<script setup>
+import { onBeforeMount, watch, computed, ref } from 'vue';
+import { useArrayData } from 'composables/useArrayData';
+import { useState } from 'src/composables/useState';
+import { useRoute } from 'vue-router';
+import VnDescriptor from './VnDescriptor.vue';
+
+const $props = defineProps({
+    url: {
+        type: String,
+        default: '',
+    },
+    filter: {
+        type: Object,
+        default: null,
+    },
+    dataKey: {
+        type: String,
+        default: null,
+    },
+});
+
+const state = useState();
+const route = useRoute();
+let arrayData;
+let store;
+let entity;
+const isLoading = ref(false);
+const isSameDataKey = computed(() => $props.dataKey === route.meta.moduleName);
+defineExpose({ getData });
+
+onBeforeMount(async () => {
+    arrayData = useArrayData($props.dataKey, {
+        url: $props.url,
+        userFilter: $props.filter,
+        skip: 0,
+        oneRecord: true,
+    });
+    store = arrayData.store;
+    entity = computed(() => {
+        const data = store.data ?? {};
+        if (data) emit('onFetch', data);
+        return data;
+    });
+
+    // It enables to load data only once if the module is the same as the dataKey
+    if (!isSameDataKey.value || !route.params.id) await getData();
+    watch(
+        () => [$props.url, $props.filter],
+        async () => {
+            if (!isSameDataKey.value) await getData();
+        },
+    );
+});
+
+async function getData() {
+    store.url = $props.url;
+    store.filter = $props.filter ?? {};
+    isLoading.value = true;
+    try {
+        const { data } = await arrayData.fetch({ append: false, updateRouter: false });
+        state.set($props.dataKey, data);
+        emit('onFetch', data);
+    } finally {
+        isLoading.value = false;
+    }
+}
+
+const emit = defineEmits(['onFetch']);
+</script>
+
+<template>
+    <VnDescriptor v-model="entity" v-bind="$attrs" :module="dataKey">
+        <template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
+            <slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
+        </template>
+    </VnDescriptor>
+</template>
diff --git a/src/components/ui/VnDescriptor.vue b/src/components/ui/VnDescriptor.vue
new file mode 100644
index 000000000..994233eb0
--- /dev/null
+++ b/src/components/ui/VnDescriptor.vue
@@ -0,0 +1,322 @@
+<script setup>
+import { computed, ref } from 'vue';
+import { useI18n } from 'vue-i18n';
+import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
+import { useSummaryDialog } from 'src/composables/useSummaryDialog';
+import { useRoute, useRouter } from 'vue-router';
+import { useClipboard } from 'src/composables/useClipboard';
+import VnMoreOptions from './VnMoreOptions.vue';
+
+const entity = defineModel({ type: Object, default: null });
+const $props = defineProps({
+    title: {
+        type: String,
+        default: '',
+    },
+    subtitle: {
+        type: Number,
+        default: null,
+    },
+    summary: {
+        type: Object,
+        default: null,
+    },
+    width: {
+        type: String,
+        default: 'md-width',
+    },
+    module: {
+        type: String,
+        default: null,
+    },
+    toModule: {
+        type: Object,
+        default: null,
+    },
+});
+
+const route = useRoute();
+const router = useRouter();
+const { t } = useI18n();
+const { copyText } = useClipboard();
+const { viewSummary } = useSummaryDialog();
+const DESCRIPTOR_PROXY = 'DescriptorProxy';
+const moduleName = ref();
+const isSameModuleName = route.matched[1].meta.moduleName !== moduleName.value;
+
+function getName() {
+    let name = $props.module;
+    if ($props.module.includes(DESCRIPTOR_PROXY)) {
+        name = name.split(DESCRIPTOR_PROXY)[0];
+    }
+    return name;
+}
+const routeName = computed(() => {
+    let routeName = getName();
+    return `${routeName}Summary`;
+});
+
+function getValueFromPath(path) {
+    if (!path) return;
+    const keys = path.toString().split('.');
+    let current = entity.value;
+
+    for (const key of keys) {
+        if (current[key] === undefined) return undefined;
+        else current = current[key];
+    }
+    return current;
+}
+
+function copyIdText(id) {
+    copyText(id, {
+        component: {
+            copyValue: id,
+        },
+    });
+}
+
+const emit = defineEmits(['onFetch']);
+
+const iconModule = computed(() => {
+    moduleName.value = getName();
+    if ($props.toModule) {
+        return router.getRoutes().find((r) => r.name === $props.toModule.name).meta.icon;
+    }
+    if (isSameModuleName) {
+        return router.options.routes[1].children.find((r) => r.name === moduleName.value)
+            ?.meta?.icon;
+    } else {
+        return route.matched[1].meta.icon;
+    }
+});
+
+const toModule = computed(() => {
+    moduleName.value = getName();
+    if ($props.toModule) return $props.toModule;
+    if (isSameModuleName) {
+        return router.options.routes[1].children.find((r) => r.name === moduleName.value)
+            ?.redirect;
+    } else {
+        return route.matched[1].path.split('/').length > 2
+            ? route.matched[1].redirect
+            : route.matched[1].children[0].redirect;
+    }
+});
+</script>
+
+<template>
+    <div class="descriptor" data-cy="vnDescriptor">
+        <template v-if="entity && entity?.id">
+            <div class="header bg-primary q-pa-sm justify-between">
+                <slot name="header-extra-action">
+                    <QBtn
+                        round
+                        flat
+                        dense
+                        size="md"
+                        :icon="iconModule"
+                        color="white"
+                        class="link"
+                        :to="toModule"
+                    >
+                        <QTooltip>
+                            {{ t('globals.goToModuleIndex') }}
+                        </QTooltip>
+                    </QBtn>
+                </slot>
+                <QBtn
+                    @click.stop="viewSummary(entity.id, summary, width)"
+                    round
+                    flat
+                    dense
+                    size="md"
+                    icon="preview"
+                    color="white"
+                    class="link"
+                    v-if="summary"
+                    data-cy="openSummaryBtn"
+                >
+                    <QTooltip>
+                        {{ t('components.smartCard.openSummary') }}
+                    </QTooltip>
+                </QBtn>
+                <RouterLink :to="{ name: routeName, params: { id: entity.id } }">
+                    <QBtn
+                        class="link"
+                        color="white"
+                        dense
+                        flat
+                        icon="launch"
+                        round
+                        size="md"
+                        data-cy="goToSummaryBtn"
+                    >
+                        <QTooltip>
+                            {{ t('components.vnDescriptor.summary') }}
+                        </QTooltip>
+                    </QBtn>
+                </RouterLink>
+                <VnMoreOptions v-if="$slots.menu">
+                    <template #menu="{ menuRef }">
+                        <slot name="menu" :entity="entity" :menu-ref="menuRef" />
+                    </template>
+                </VnMoreOptions>
+            </div>
+            <slot name="before" />
+            <div class="body q-py-sm">
+                <QList dense>
+                    <QItemLabel header class="ellipsis text-h5" :lines="1">
+                        <div class="title">
+                            <span
+                                v-if="title"
+                                :title="getValueFromPath(title)"
+                                :data-cy="`${$attrs['data-cy'] ?? 'vnDescriptor'}_title`"
+                            >
+                                {{ getValueFromPath(title) ?? title }}
+                            </span>
+                            <slot v-else name="description" :entity="entity">
+                                <span
+                                    :title="entity.name"
+                                    :data-cy="`${$attrs['data-cy'] ?? 'vnDescriptor'}_description`"
+                                    v-text="entity.name"
+                                />
+                            </slot>
+                        </div>
+                    </QItemLabel>
+                    <QItem>
+                        <QItemLabel
+                            class="subtitle"
+                            :data-cy="`${$attrs['data-cy'] ?? 'vnDescriptor'}_subtitle`"
+                        >
+                            #{{ getValueFromPath(subtitle) ?? entity.id }}
+                        </QItemLabel>
+                        <QBtn
+                            round
+                            flat
+                            dense
+                            size="sm"
+                            icon="content_copy"
+                            color="primary"
+                            @click.stop="copyIdText(entity.id)"
+                        >
+                            <QTooltip>
+                                {{ t('globals.copyId') }}
+                            </QTooltip>
+                        </QBtn>
+                    </QItem>
+                </QList>
+                <div
+                    class="list-box q-mt-xs"
+                    :data-cy="`${$attrs['data-cy'] ?? 'vnDescriptor'}_listbox`"
+                >
+                    <slot name="body" :entity="entity" />
+                </div>
+            </div>
+            <div class="icons">
+                <slot name="icons" :entity="entity" />
+            </div>
+            <div class="actions justify-center" data-cy="descriptor_actions">
+                <slot name="actions" :entity="entity" />
+            </div>
+            <slot name="after" />
+        </template>
+        <SkeletonDescriptor v-if="!entity" />
+    </div>
+    <QInnerLoading :label="t('globals.pleaseWait')" :showing="!entity" color="primary" />
+</template>
+
+<style lang="scss">
+.body {
+    background-color: var(--vn-section-color);
+    .text-h5 {
+        font-size: 20px;
+        padding-top: 5px;
+        padding-bottom: 0px;
+    }
+    .q-item {
+        min-height: 20px;
+
+        .link {
+            margin-left: 10px;
+        }
+    }
+    .vn-label-value {
+        display: flex;
+        padding: 0px 16px;
+        .label {
+            color: var(--vn-label-color);
+            font-size: 14px;
+
+            &:not(:has(a))::after {
+                content: ':';
+            }
+        }
+        &.ellipsis > .value {
+            text-overflow: ellipsis;
+            white-space: pre;
+        }
+        .value {
+            color: var(--vn-text-color);
+            font-size: 14px;
+            margin-left: 4px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            text-align: left;
+        }
+        .info {
+            margin-left: 5px;
+        }
+    }
+}
+</style>
+
+<style lang="scss" scoped>
+.title {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    span {
+        color: var(--vn-text-color);
+        font-weight: bold;
+    }
+}
+.subtitle {
+    color: var(--vn-text-color);
+    font-size: 16px;
+    margin-bottom: 2px;
+}
+.list-box {
+    .q-item__label {
+        color: var(--vn-label-color);
+        padding-bottom: 0%;
+    }
+}
+.descriptor {
+    width: 256px;
+    .header {
+        display: flex;
+        align-items: center;
+    }
+    .icons {
+        margin: 0 10px;
+        display: flex;
+        justify-content: center;
+        .q-icon {
+            margin-right: 5px;
+        }
+    }
+    .actions {
+        margin: 0 5px;
+        justify-content: center !important;
+    }
+}
+</style>
+<i18n>
+    en:
+        globals:
+            copyId: Copy ID
+    es:
+        globals:
+            copyId: Copiar ID
+</i18n>
diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue
index d6b525dc8..dc9e4e776 100644
--- a/src/components/ui/VnFilterPanel.vue
+++ b/src/components/ui/VnFilterPanel.vue
@@ -54,13 +54,17 @@ const $props = defineProps({
         default: 'table',
     },
     redirect: {
-        type: Boolean,
+        type: [String, Boolean],
         default: true,
     },
     arrayData: {
         type: Object,
         default: null,
     },
+    showTagChips: {
+        type: Boolean,
+        default: true,
+    },
 });
 
 const emit = defineEmits([
@@ -88,13 +92,14 @@ const userOrders = ref(useFilterParams($props.dataKey).orders);
 defineExpose({ search, params: userParams, remove });
 
 const isLoading = ref(false);
-async function search(evt) {
+async function search(evt, name, value) {
     try {
         if (evt && $props.disableSubmitEvent) return;
 
         store.filter.where = {};
         isLoading.value = true;
         const filter = { ...userParams.value, ...$props.modelValue };
+        if (name) filter[name] = value;
         store.userParamsChanged = true;
         await arrayData.addFilter({
             params: filter,
@@ -214,7 +219,7 @@ const getLocale = (label) => {
         </QTooltip>
     </QBtn>
     <QForm @submit="search" id="filterPanelForm" @keyup.enter="search()">
-        <QList dense>
+        <QList dense v-if="showTagChips">
             <QItem class="q-mt-xs">
                 <QItemSection top>
                     <QItemLabel header lines="1" class="text-uppercase q-py-xs q-px-none">
@@ -249,7 +254,7 @@ const getLocale = (label) => {
                         :key="chip.label"
                         :removable="!unremovableParams?.includes(chip.label)"
                         @remove="remove(chip.label)"
-                        data-cy="vnFilterPanelChip"
+                        :data-cy="`vnFilterPanelChip_${chip.label}`"
                     >
                         <slot
                             name="tags"
diff --git a/src/components/ui/VnLinkMail.vue b/src/components/ui/VnLinkMail.vue
index a54f463f5..6c5129a9b 100644
--- a/src/components/ui/VnLinkMail.vue
+++ b/src/components/ui/VnLinkMail.vue
@@ -1,8 +1,11 @@
 <script setup>
+import { dashIfEmpty } from 'src/filters';
+
 defineProps({ email: { type: [String], default: null } });
 </script>
 <template>
     <QBtn
+        class="q-pr-xs"
         v-if="email"
         flat
         round
@@ -13,4 +16,5 @@ defineProps({ email: { type: [String], default: null } });
         :href="`mailto:${email}`"
         @click.stop
     />
+    <span>{{ dashIfEmpty(email) }}</span>
 </template>
diff --git a/src/components/ui/VnLinkPhone.vue b/src/components/ui/VnLinkPhone.vue
index a9e9bc0fc..e34a70011 100644
--- a/src/components/ui/VnLinkPhone.vue
+++ b/src/components/ui/VnLinkPhone.vue
@@ -1,7 +1,7 @@
 <script setup>
 import { ref, reactive, useAttrs, onBeforeMount, capitalize } from 'vue';
 import axios from 'axios';
-import { parsePhone } from 'src/filters';
+import { dashIfEmpty, parsePhone } from 'src/filters';
 import useOpenURL from 'src/composables/useOpenURL';
 
 const props = defineProps({
@@ -12,49 +12,65 @@ const props = defineProps({
 
 const phone = ref(props.phoneNumber);
 const config = reactive({
-    sip: { icon: 'phone', href: `sip:${props.phoneNumber}` },
     'say-simple': {
         icon: 'vn:saysimple',
         url: null,
         channel: props.channel,
     },
+    sip: { icon: 'phone', href: `sip:${props.phoneNumber}` },
 });
-const type = Object.keys(config).find((key) => key in useAttrs()) || 'sip';
+
+const attrs = useAttrs();
+const types = Object.keys(config)
+    .filter((key) => key in attrs)
+    .sort();
+const activeTypes = types.length ? types : ['sip'];
 
 onBeforeMount(async () => {
     if (!phone.value) return;
-    let { channel } = config[type];
 
-    if (type === 'say-simple') {
-        const { url, defaultChannel } = (await axios.get('SaySimpleConfigs/findOne'))
-            .data;
-        if (!channel) channel = defaultChannel;
+    for (const type of activeTypes) {
+        if (type === 'say-simple') {
+            let { channel } = config[type];
+            const { url, defaultChannel } = (await axios.get('SaySimpleConfigs/findOne'))
+                .data;
+            if (!channel) channel = defaultChannel;
 
-        phone.value = await parsePhone(props.phoneNumber, props.country?.toLowerCase());
-        config[
-            type
-        ].url = `${url}?customerIdentity=%2B${phone.value}&channelId=${channel}`;
+            phone.value = await parsePhone(
+                props.phoneNumber,
+                props.country?.toLowerCase(),
+            );
+            config[type].url =
+                `${url}?customerIdentity=%2B${phone.value}&channelId=${channel}`;
+        }
     }
 });
 
-function handleClick() {
+function handleClick(type) {
     if (config[type].url) useOpenURL(config[type].url);
     else if (config[type].href) window.location.href = config[type].href;
 }
 </script>
+
 <template>
-    <QBtn
-        v-if="phone"
-        flat
-        round
-        :icon="config[type].icon"
-        size="sm"
-        color="primary"
-        padding="none"
-        @click.stop="handleClick"
-    >
-        <QTooltip>
-            {{ capitalize(type).replace('-', '') }}
-        </QTooltip>
-    </QBtn>
+    <div class="flex items-center gap-2">
+        <template v-for="type in activeTypes">
+            <QBtn
+                :key="type"
+                v-if="phone"
+                flat
+                round
+                :icon="config[type].icon"
+                size="sm"
+                color="primary"
+                padding="none"
+                @click.stop="() => handleClick(type)"
+            >
+                <QTooltip>
+                    {{ capitalize(type).replace('-', '') }}
+                </QTooltip>
+            </QBtn></template
+        >
+        <span>{{ dashIfEmpty(phone) }}</span>
+    </div>
 </template>
diff --git a/src/components/ui/VnLv.vue b/src/components/ui/VnLv.vue
index a198c9c05..aa7342742 100644
--- a/src/components/ui/VnLv.vue
+++ b/src/components/ui/VnLv.vue
@@ -28,13 +28,14 @@ function copyValueText() {
 const val = computed(() => $props.value);
 </script>
 <template>
-    <div class="vn-label-value">
+    <div class="vn-label-value" :data-cy="`${$attrs['data-cy'] ?? 'vnLv'}${label ?? ''}`">
         <QCheckbox
             v-if="typeof value === 'boolean'"
             v-model="val"
             :label="label"
             disable
             dense
+            size="sm"
         />
         <template v-else>
             <div v-if="label || $slots.label" class="label">
@@ -42,9 +43,9 @@ const val = computed(() => $props.value);
                     <span style="color: var(--vn-label-color)">{{ label }}</span>
                 </slot>
             </div>
-            <div class="value">
+            <div class="value" v-if="value || $slots.value">
                 <slot name="value">
-                    <span :title="value">
+                    <span :title="value" style="text-overflow: ellipsis">
                         {{ dash ? dashIfEmpty(value) : value }}
                     </span>
                 </slot>
diff --git a/src/components/ui/VnMoreOptions.vue b/src/components/ui/VnMoreOptions.vue
index 8a1c7a0f2..bc81233d5 100644
--- a/src/components/ui/VnMoreOptions.vue
+++ b/src/components/ui/VnMoreOptions.vue
@@ -9,10 +9,10 @@
         data-cy="descriptor-more-opts"
     >
         <QTooltip>
-            {{ $t('components.cardDescriptor.moreOptions') }}
+            {{ $t('components.vnDescriptor.moreOptions') }}
         </QTooltip>
         <QMenu ref="menuRef" data-cy="descriptor-more-opts-menu">
-            <QList>
+            <QList data-cy="descriptor-more-opts_list">
                 <slot name="menu" :menu-ref="$refs.menuRef" />
             </QList>
         </QMenu>
diff --git a/src/components/ui/VnNotes.vue b/src/components/ui/VnNotes.vue
index eb0804af0..9cedbccfa 100644
--- a/src/components/ui/VnNotes.vue
+++ b/src/components/ui/VnNotes.vue
@@ -18,10 +18,10 @@ import VnInput from 'components/common/VnInput.vue';
 
 const emit = defineEmits(['onFetch']);
 
-const $attrs = useAttrs();
-
-const isRequired = computed(() => {
-    return Object.keys($attrs).includes('required');
+const originalAttrs = useAttrs();
+const $attrs = computed(() => {
+    const { required, deletable, ...rest } = originalAttrs;
+    return rest;
 });
 
 const $props = defineProps({
@@ -40,6 +40,11 @@ const quasar = useQuasar();
 const newNote = reactive({ text: null, observationTypeFk: null });
 const observationTypes = ref([]);
 const vnPaginateRef = ref();
+
+const defaultObservationType = computed(() => 
+    observationTypes.value.find(ot => ot.code === 'salesPerson')?.id
+);
+
 let originalText;
 
 function handleClick(e) {
@@ -48,6 +53,11 @@ function handleClick(e) {
     else insert();
 }
 
+async function deleteNote(e) {
+    await axios.delete(`${$props.url}/${e.id}`);
+    await vnPaginateRef.value.fetch();
+}
+
 async function insert() {
     if (!newNote.text || ($props.selectType && !newNote.observationTypeFk)) return;
 
@@ -111,14 +121,22 @@ function fetchData([data]) {
     originalText = data?.notes;
     emit('onFetch', data);
 }
+
+const handleObservationTypes = (data) => {
+    observationTypes.value = data;
+    if(defaultObservationType.value) {
+        newNote.observationTypeFk = defaultObservationType.value;
+    }
+};
+
 </script>
 <template>
     <FetchData
         v-if="selectType"
         url="ObservationTypes"
-        :filter="{ fields: ['id', 'description'] }"
+        :filter="{ fields: ['id', 'description', 'code'] }"
         auto-load
-        @on-fetch="(data) => (observationTypes = data)"
+        @on-fetch="handleObservationTypes"
     />
     <FetchData
         v-if="justInput"
@@ -144,7 +162,7 @@ function fetchData([data]) {
                     v-model="newNote.observationTypeFk"
                     option-label="description"
                     style="flex: 0.15"
-                    :required="isRequired"
+                    :required="'required' in originalAttrs"
                     @keyup.enter.stop="insert"
                 />
                 <VnInput
@@ -152,10 +170,10 @@ function fetchData([data]) {
                     type="textarea"
                     :label="$props.justInput && newNote.text ? '' : t('Add note here...')"
                     filled
-                    size="lg"
                     autogrow
+                    autofocus
                     @keyup.enter.stop="handleClick"
-                    :required="isRequired"
+                    :required="'required' in originalAttrs"
                     clearable
                 >
                     <template #append>
@@ -186,10 +204,9 @@ function fetchData([data]) {
         ref="vnPaginateRef"
         class="show"
         v-bind="$attrs"
-        search-url="notes"
+        :search-url="false"
         @on-fetch="
             newNote.text = '';
-            newNote.observationTypeFk = null;
         "
     >
         <template #body="{ rows }">
@@ -226,6 +243,21 @@ function fetchData([data]) {
                                 </QBadge>
                             </div>
                             <span v-text="toDateHourMin(note.created)" />
+                            <div>
+                                <QIcon
+                                    v-if="'deletable' in originalAttrs"
+                                    name="delete"
+                                    size="sm"
+                                    class="cursor-pointer"
+                                    color="primary"
+                                    @click="deleteNote(note)"
+                                    data-cy="notesRemoveNoteBtn"
+                                >
+                                    <QTooltip>
+                                        {{ t('ticketNotes.removeNote') }}
+                                    </QTooltip>
+                                </QIcon>
+                            </div>
                         </div>
                     </QCardSection>
                     <QCardSection class="q-pa-xs q-my-none q-py-none">
diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue
index 68968e6c5..4a5d2b459 100644
--- a/src/components/ui/VnPaginate.vue
+++ b/src/components/ui/VnPaginate.vue
@@ -117,7 +117,7 @@ onMounted(async () => {
 });
 
 onBeforeUnmount(() => {
-    if (!store.keepData) arrayData.reset(['data']);
+    arrayData.reset(['data']);
     arrayData.resetPagination();
 });
 
@@ -217,6 +217,7 @@ defineExpose({
     paginate,
     userParams: arrayData.store.userParams,
     currentFilter: arrayData.store.currentFilter,
+    arrayData,
 });
 </script>
 
diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue
index 1874d0ed9..59bcdf524 100644
--- a/src/components/ui/VnSearchbar.vue
+++ b/src/components/ui/VnSearchbar.vue
@@ -33,6 +33,10 @@ const props = defineProps({
         type: String,
         default: '',
     },
+    userFilter: {
+        type: Object,
+        default: null,
+    },
     filter: {
         type: Object,
         default: null,
diff --git a/src/components/ui/VnToSummary.vue b/src/components/ui/VnToSummary.vue
index 305d65e02..853d26230 100644
--- a/src/components/ui/VnToSummary.vue
+++ b/src/components/ui/VnToSummary.vue
@@ -26,6 +26,7 @@ const id = props.entityId;
         :to="{ name: routeName, params: { id: id } }"
         class="header link"
         :href="url"
+        data-cy="goToSummaryBtn"
     >
         <QIcon name="open_in_new" color="white" size="sm" />
     </router-link>
diff --git a/src/components/ui/__tests__/CardSummary.spec.js b/src/components/ui/__tests__/CardSummary.spec.js
index 6bd742310..bcef1d304 100644
--- a/src/components/ui/__tests__/CardSummary.spec.js
+++ b/src/components/ui/__tests__/CardSummary.spec.js
@@ -1,5 +1,7 @@
 import { vi, describe, expect, it, beforeAll, afterEach, beforeEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
+
 import CardSummary from 'src/components/ui/CardSummary.vue';
 import * as vueRouter from 'vue-router';
 
diff --git a/src/components/ui/__tests__/Paginate.spec.js b/src/components/ui/__tests__/Paginate.spec.js
index a67dfcdc6..968643b67 100644
--- a/src/components/ui/__tests__/Paginate.spec.js
+++ b/src/components/ui/__tests__/Paginate.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import VnPaginate from 'src/components/ui/VnPaginate.vue';
 
 describe('VnPaginate', () => {
diff --git a/src/components/ui/__tests__/VnLinkPhone.spec.js b/src/components/ui/__tests__/VnLinkPhone.spec.js
index a34ef90a5..3c92adf95 100644
--- a/src/components/ui/__tests__/VnLinkPhone.spec.js
+++ b/src/components/ui/__tests__/VnLinkPhone.spec.js
@@ -1,5 +1,5 @@
 import { describe, it, expect, beforeAll, vi } from 'vitest';
-import { axios } from 'app/test/vitest/helper';
+import axios from 'axios';
 import parsePhone from 'src/filters/parsePhone';
 
 describe('parsePhone filter', () => {
diff --git a/src/composables/__tests__/downloadFile.spec.js b/src/composables/__tests__/downloadFile.spec.js
index f53b56b3e..0cd38043f 100644
--- a/src/composables/__tests__/downloadFile.spec.js
+++ b/src/composables/__tests__/downloadFile.spec.js
@@ -1,15 +1,17 @@
 import { vi, describe, expect, it, beforeAll, afterAll } from 'vitest';
-import { axios } from 'app/test/vitest/helper';
+import axios from 'axios';
 import { downloadFile } from 'src/composables/downloadFile';
 import { useSession } from 'src/composables/useSession';
 const session = useSession();
 const token = session.getToken();
 
 describe('downloadFile', () => {
-    const baseUrl = 'http://localhost:9000';
     let defaulCreateObjectURL;
 
     beforeAll(() => {
+        vi.mock('src/composables/getUrl', () => ({
+            getUrl: vi.fn().mockResolvedValue(''),
+        }));
         defaulCreateObjectURL = window.URL.createObjectURL;
         window.URL.createObjectURL = vi.fn(() => 'blob:http://localhost:9000/blob-id');
     });
@@ -22,15 +24,14 @@ describe('downloadFile', () => {
             headers: { 'content-disposition': 'attachment; filename="test-file.txt"' },
         };
         vi.spyOn(axios, 'get').mockImplementation((url) => {
-            if (url == 'Urls/getUrl') return Promise.resolve({ data: baseUrl });
-            else if (url.includes('downloadFile')) return Promise.resolve(res);
+            if (url.includes('downloadFile')) return Promise.resolve(res);
         });
 
         await downloadFile(1);
 
         expect(axios.get).toHaveBeenCalledWith(
-            `${baseUrl}/api/dms/1/downloadFile?access_token=${token}`,
-            { responseType: 'blob' }
+            `/api/dms/1/downloadFile?access_token=${token}`,
+            { responseType: 'blob' },
         );
     });
 });
diff --git a/src/composables/__tests__/useAcl.spec.js b/src/composables/__tests__/useAcl.spec.js
index 6cb29984c..86cd58fa0 100644
--- a/src/composables/__tests__/useAcl.spec.js
+++ b/src/composables/__tests__/useAcl.spec.js
@@ -1,5 +1,7 @@
 import { vi, describe, expect, it, beforeAll, afterAll } from 'vitest';
-import { axios, flushPromises } from 'app/test/vitest/helper';
+import axios from 'axios';
+
+import { flushPromises } from '@vue/test-utils';
 import { useAcl } from 'src/composables/useAcl';
 
 describe('useAcl', () => {
diff --git a/src/composables/__tests__/useArrayData.spec.js b/src/composables/__tests__/useArrayData.spec.js
index a610ba9eb..a3fbbdd5d 100644
--- a/src/composables/__tests__/useArrayData.spec.js
+++ b/src/composables/__tests__/useArrayData.spec.js
@@ -1,15 +1,39 @@
 import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest';
-import { axios, flushPromises } from 'app/test/vitest/helper';
+import { default as axios } from 'axios';
 import { useArrayData } from 'composables/useArrayData';
 import { useRouter } from 'vue-router';
 import * as vueRouter from 'vue-router';
+import { setActivePinia, createPinia } from 'pinia';
 
 describe('useArrayData', () => {
     const filter = '{"limit":20,"skip":0}';
     const params = { supplierFk: 2 };
+
     beforeEach(() => {
-        vi.spyOn(useRouter(), 'replace');
-        vi.spyOn(useRouter(), 'push');
+        setActivePinia(createPinia());
+
+        // Mock route
+        vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
+            path: 'mockSection/list',
+            matched: [],
+            query: {},
+            params: {},
+            meta: { moduleName: 'mockName' },
+        });
+
+        // Mock router
+        vi.spyOn(vueRouter, 'useRouter').mockReturnValue({
+            push: vi.fn(),
+            replace: vi.fn(),
+            currentRoute: {
+                value: {
+                    path: 'mockSection/list',
+                    params: { id: 1 },
+                    meta: { moduleName: 'mockName' },
+                    matched: [{ path: 'mockName/:id' }],
+                },
+            },
+        });
     });
 
     afterEach(() => {
@@ -17,103 +41,69 @@ describe('useArrayData', () => {
     });
 
     it('should fetch and replace url with new params', async () => {
-        vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [] });
+        vi.spyOn(axios, 'get').mockResolvedValueOnce({ data: [] });
 
-        const arrayData = useArrayData('ArrayData', { url: 'mockUrl' });
+        const arrayData = useArrayData('ArrayData', {
+            url: 'mockUrl',
+            searchUrl: 'params',
+        });
 
         arrayData.store.userParams = params;
-        arrayData.fetch({});
+        await arrayData.fetch({});
 
-        await flushPromises();
         const routerReplace = useRouter().replace.mock.calls[0][0];
 
-        expect(axios.get.mock.calls[0][1].params).toEqual({
-            filter,
-            supplierFk: 2,
+        expect(axios.get).toHaveBeenCalledWith('mockUrl', {
+            signal: expect.any(Object),
+            params: {
+                filter,
+                supplierFk: 2,
+            },
         });
-        expect(routerReplace.path).toEqual('mockSection/list');
+
+        expect(routerReplace.path).toBe('mockSection/list');
         expect(JSON.parse(routerReplace.query.params)).toEqual(
             expect.objectContaining(params),
         );
     });
 
-    it('should get data and send new URL without keeping parameters, if there is only one record', async () => {
-        vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [{ id: 1 }] });
+    it('should redirect to detail when single record is returned with navigation', async () => {
+        vi.spyOn(axios, 'get').mockResolvedValueOnce({
+            data: [{ id: 1 }],
+        });
 
-        const arrayData = useArrayData('ArrayData', { url: 'mockUrl', navigate: {} });
+        const arrayData = useArrayData('ArrayData', {
+            url: 'mockUrl',
+            navigate: {},
+        });
 
         arrayData.store.userParams = params;
-        arrayData.fetch({});
+        await arrayData.fetch({});
 
-        await flushPromises();
         const routerPush = useRouter().push.mock.calls[0][0];
 
-        expect(axios.get.mock.calls[0][1].params).toEqual({
-            filter,
-            supplierFk: 2,
-        });
-        expect(routerPush.path).toEqual('mockName/1');
+        expect(routerPush.path).toBe('mockName/1');
         expect(routerPush.query).toBeUndefined();
     });
 
-    it('should get data and send new URL keeping parameters, if you have more than one record', async () => {
-        vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [{ id: 1 }, { id: 2 }] });
-
-        vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
-            matched: [],
-            query: {},
-            params: {},
-            meta: { moduleName: 'mockName' },
-            path: 'mockName/1',
-        });
-        vi.spyOn(vueRouter, 'useRouter').mockReturnValue({
-            push: vi.fn(),
-            replace: vi.fn(),
-            currentRoute: {
-                value: {
-                    params: {
-                        id: 1,
-                    },
-                    meta: { moduleName: 'mockName' },
-                    matched: [{ path: 'mockName/:id' }],
-                },
-            },
-        });
-
-        const arrayData = useArrayData('ArrayData', { url: 'mockUrl', navigate: {} });
-
-        arrayData.store.userParams = params;
-        arrayData.fetch({});
-
-        await flushPromises();
-        const routerPush = useRouter().push.mock.calls[0][0];
-
-        expect(axios.get.mock.calls[0][1].params).toEqual({
-            filter,
-            supplierFk: 2,
-        });
-        expect(routerPush.path).toEqual('mockName/');
-        expect(routerPush.query.params).toBeDefined();
-    });
-
-    it('should return one record', async () => {
-        vi.spyOn(axios, 'get').mockReturnValueOnce({
+    it('should return one record when oneRecord is true', async () => {
+        vi.spyOn(axios, 'get').mockResolvedValueOnce({
             data: [
                 { id: 1, name: 'Entity 1' },
                 { id: 2, name: 'Entity 2' },
             ],
         });
-        const arrayData = useArrayData('ArrayData', { url: 'mockUrl', oneRecord: true });
+
+        const arrayData = useArrayData('ArrayData', {
+            url: 'mockUrl',
+            oneRecord: true,
+        });
+
         await arrayData.fetch({});
 
-        expect(arrayData.store.data).toEqual({ id: 1, name: 'Entity 1' });
-    });
-
-    it('should handle empty data gracefully if has to return one record', async () => {
-        vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [] });
-        const arrayData = useArrayData('ArrayData', { url: 'mockUrl', oneRecord: true });
-        await arrayData.fetch({});
-
-        expect(arrayData.store.data).toBeUndefined();
+        expect(arrayData.store.data).toEqual({
+            id: 1,
+            name: 'Entity 1',
+        });
     });
 });
diff --git a/src/composables/__tests__/useRole.spec.js b/src/composables/__tests__/useRole.spec.js
index d0bca5342..017301a1b 100644
--- a/src/composables/__tests__/useRole.spec.js
+++ b/src/composables/__tests__/useRole.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it } from 'vitest';
-import { axios, flushPromises } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { flushPromises } from '@vue/test-utils';
 import { useRole } from 'composables/useRole';
 const role = useRole();
 
@@ -23,18 +24,19 @@ describe('useRole', () => {
                 name: `T'Challa`,
                 nickname: 'Black Panther',
                 lang: 'en',
+                worker: { department: { departmentFk: 155 } },
             };
             const expectedUser = {
                 id: 999,
                 name: `T'Challa`,
                 nickname: 'Black Panther',
                 lang: 'en',
+                departmentFk: 155,
             };
             const expectedRoles = ['salesPerson', 'admin'];
-            vi.spyOn(axios, 'get')
-            .mockResolvedValueOnce({
+            vi.spyOn(axios, 'get').mockResolvedValueOnce({
                 data: { roles: rolesData, user: fetchedUser },
-            })
+            });
 
             vi.spyOn(role.state, 'setUser');
             vi.spyOn(role.state, 'setRoles');
diff --git a/src/composables/__tests__/useSession.spec.js b/src/composables/__tests__/useSession.spec.js
index 789b149ec..e86847b70 100644
--- a/src/composables/__tests__/useSession.spec.js
+++ b/src/composables/__tests__/useSession.spec.js
@@ -1,5 +1,5 @@
 import { vi, describe, expect, it, beforeAll, beforeEach } from 'vitest';
-import { axios } from 'app/test/vitest/helper';
+import axios from 'axios';
 import { useSession } from 'composables/useSession';
 import { useState } from 'composables/useState';
 
@@ -75,6 +75,7 @@ describe('session', () => {
                 userConfig: {
                     darkMode: false,
                 },
+                worker: { department: { departmentFk: 155 } },
             };
             const rolesData = [
                 {
@@ -143,7 +144,7 @@ describe('session', () => {
                 await session.destroy(); // this clears token and user for any other test
             });
         },
-        {}
+        {},
     );
 
     describe('RenewToken', () => {
@@ -175,7 +176,7 @@ describe('session', () => {
             await session.checkValidity();
             expect(sessionStorage.getItem('token')).toEqual(expectedToken);
             expect(sessionStorage.getItem('tokenMultimedia')).toEqual(
-                expectedTokenMultimedia
+                expectedTokenMultimedia,
             );
         });
         it('Should renewToken', async () => {
@@ -204,7 +205,7 @@ describe('session', () => {
             await session.checkValidity();
             expect(sessionStorage.getItem('token')).not.toEqual(expectedToken);
             expect(sessionStorage.getItem('tokenMultimedia')).not.toEqual(
-                expectedTokenMultimedia
+                expectedTokenMultimedia,
             );
         });
     });
diff --git a/src/composables/__tests__/useTokenConfig.spec.js b/src/composables/__tests__/useTokenConfig.spec.js
index a25a4abb1..92664e65a 100644
--- a/src/composables/__tests__/useTokenConfig.spec.js
+++ b/src/composables/__tests__/useTokenConfig.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it } from 'vitest';
-import { axios, flushPromises } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { flushPromises } from '@vue/test-utils';
 import { useTokenConfig } from 'composables/useTokenConfig';
 const tokenConfig = useTokenConfig();
 
diff --git a/src/composables/downloadFile.js b/src/composables/downloadFile.js
index 4588265a2..0c4e8edb6 100644
--- a/src/composables/downloadFile.js
+++ b/src/composables/downloadFile.js
@@ -7,18 +7,33 @@ const { getTokenMultimedia } = useSession();
 const token = getTokenMultimedia();
 
 export async function downloadFile(id, model = 'dms', urlPath = '/downloadFile', url) {
-    const appUrl = (await getUrl('', 'lilium')).replace('/#/', '');
+    const appUrl = await getAppUrl();
     const response = await axios.get(
         url ?? `${appUrl}/api/${model}/${id}${urlPath}?access_token=${token}`,
-        { responseType: 'blob' }
+        { responseType: 'blob' },
     );
 
+    download(response);
+}
+
+export async function downloadDocuware(url, params) {
+    const appUrl = await getAppUrl();
+    const response = await axios.get(`${appUrl}/api/` + url, {
+        responseType: 'blob',
+        params,
+    });
+
+    download(response);
+}
+
+function download(response) {
     const contentDisposition = response.headers['content-disposition'];
     const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(contentDisposition);
-    const filename =
-        matches != null && matches[1]
-            ? matches[1].replace(/['"]/g, '')
-            : 'downloaded-file';
+    const filename = matches?.[1] ? matches[1].replace(/['"]/g, '') : 'downloaded-file';
 
     exportFile(filename, response.data);
 }
+
+async function getAppUrl() {
+    return (await getUrl('', 'lilium')).replace('/#/', '');
+}
diff --git a/src/composables/getColAlign.js b/src/composables/getColAlign.js
index a930fd7d8..c1841e134 100644
--- a/src/composables/getColAlign.js
+++ b/src/composables/getColAlign.js
@@ -9,6 +9,8 @@ export function getColAlign(col) {
         case 'number':
             align = 'right';
             break;
+        case 'time':
+        case 'date':
         case 'checkbox':
             align = 'center';
             break;
diff --git a/src/composables/updateMinPriceBeforeSave.js b/src/composables/updateMinPriceBeforeSave.js
new file mode 100644
index 000000000..d2895eeff
--- /dev/null
+++ b/src/composables/updateMinPriceBeforeSave.js
@@ -0,0 +1,51 @@
+import axios from 'axios';
+
+export async function beforeSave(data, getChanges, modelOrigin) {
+    try {
+        const changes = data.updates;
+        if (!changes) return data;
+        const patchPromises = [];
+
+        for (const change of changes) {
+            let patchData = {};
+
+            if ('hasMinPrice' in change.data) {
+                patchData.hasMinPrice = change.data?.hasMinPrice;
+                delete change.data.hasMinPrice;
+            }
+            if ('minPrice' in change.data) {
+                patchData.minPrice = change.data?.minPrice;
+                delete change.data.minPrice;
+            }
+
+            if (Object.keys(patchData).length > 0) {
+                const promise = axios
+                    .get(`${modelOrigin}/findOne`, {
+                        params: {
+                            filter: {
+                                fields: ['itemFk'],
+                                where: { id: change.where.id },
+                            },
+                        },
+                    })
+                    .then((row) => {
+                        return axios.patch(`Items/${row.data.itemFk}`, patchData);
+                    })
+                    .catch((error) => {
+                        console.error('Error processing change: ', change, error);
+                    });
+
+                patchPromises.push(promise);
+            }
+        }
+
+        await Promise.all(patchPromises);
+
+        data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
+
+        return data;
+    } catch (error) {
+        console.error('Error in beforeSave:', error);
+        throw error;
+    }
+}
diff --git a/src/composables/useAcl.js b/src/composables/useAcl.js
index ede359186..52704fee9 100644
--- a/src/composables/useAcl.js
+++ b/src/composables/useAcl.js
@@ -30,9 +30,16 @@ export function useAcl() {
         return false;
     }
 
+    function hasAcl(model, prop, accessType) {
+        const modelAcl = state.getAcls().value[model];
+        const propAcl = modelAcl?.[prop] || modelAcl?.['*'];
+        return !!(propAcl?.[accessType] || propAcl?.['*']);
+    }
+
     return {
         fetch,
         hasAny,
         state,
+        hasAcl,
     };
 }
diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js
index 3a171191e..2e880a16d 100644
--- a/src/composables/useArrayData.js
+++ b/src/composables/useArrayData.js
@@ -5,12 +5,11 @@ import { useArrayDataStore } from 'stores/useArrayDataStore';
 import { buildFilter } from 'filters/filterPanel';
 import { isDialogOpened } from 'src/filters';
 
-const arrayDataStore = useArrayDataStore();
-
 export function useArrayData(key, userOptions) {
     key ??= useRoute().meta.moduleName;
 
     if (!key) throw new Error('ArrayData: A key is required to use this composable');
+    const arrayDataStore = useArrayDataStore(); // Move inside function
 
     if (!arrayDataStore.get(key)) arrayDataStore.set(key);
 
@@ -56,7 +55,6 @@ export function useArrayData(key, userOptions) {
             'searchUrl',
             'navigate',
             'mapKey',
-            'keepData',
             'oneRecord',
         ];
         if (typeof userOptions === 'object') {
@@ -108,7 +106,7 @@ export function useArrayData(key, userOptions) {
         store.hasMoreData = limit && response.data.length >= limit;
 
         if (!append && !isDialogOpened() && updateRouter) {
-            if (updateStateParams(response.data)?.redirect && !store.keepData) return;
+            if (updateStateParams(response.data)?.redirect) return;
         }
         store.isLoading = false;
         canceller = null;
@@ -148,8 +146,7 @@ export function useArrayData(key, userOptions) {
     }
 
     async function applyFilter({ filter, params }, fetchOptions = {}) {
-        if (filter) store.userFilter = filter;
-        store.filter = {};
+        if (filter) store.filter = filter;
         if (params) store.userParams = { ...params };
 
         const response = await fetch(fetchOptions);
@@ -190,7 +187,7 @@ export function useArrayData(key, userOptions) {
 
         store.order = order;
         resetPagination();
-        fetch({});
+        await fetch({});
         index++;
 
         return { index, order };
diff --git a/src/composables/useFilterParams.js b/src/composables/useFilterParams.js
index 07dcdf99b..7c3f3bdeb 100644
--- a/src/composables/useFilterParams.js
+++ b/src/composables/useFilterParams.js
@@ -14,7 +14,7 @@ export function useFilterParams(key) {
     watch(
         () => arrayData.value.store?.currentFilter,
         (val, oldValue) => (val || oldValue) && setUserParams(val),
-        { immediate: true, deep: true }
+        { immediate: true, deep: true },
     );
 
     function parseOrder(urlOrders) {
@@ -54,7 +54,7 @@ export function useFilterParams(key) {
                     Object.assign(params, item);
                 });
                 delete params[key];
-            } else if (value && typeof value === 'object') {
+            } else if (value && typeof value === 'object' && !Array.isArray(value)) {
                 const param = Object.values(value)[0];
                 if (typeof param == 'string') params[key] = param.replaceAll('%', '');
             }
diff --git a/src/composables/useRole.js b/src/composables/useRole.js
index ff54b409c..e4e4f52c7 100644
--- a/src/composables/useRole.js
+++ b/src/composables/useRole.js
@@ -13,6 +13,7 @@ export function useRole() {
             name: data.user.name,
             nickname: data.user.nickname,
             lang: data.user.lang || 'es',
+            departmentFk: data.user?.worker?.department?.departmentFk,
         };
         state.setUser(userData);
         state.setRoles(roles);
diff --git a/src/composables/useSession.js b/src/composables/useSession.js
index e69819a68..36b31ab0a 100644
--- a/src/composables/useSession.js
+++ b/src/composables/useSession.js
@@ -60,7 +60,7 @@ export function useSession() {
                 const { data: isValidToken } = await axios.get('VnUsers/validateToken');
                 if (isValidToken)
                     destroyTokenPromises = Object.entries(tokens).map(([key, url]) =>
-                        destroyToken(url, storage, key)
+                        destroyToken(url, storage, key),
                     );
             }
         } finally {
diff --git a/src/composables/useValidator.js b/src/composables/useValidator.js
index 7a7032608..ae6c47d91 100644
--- a/src/composables/useValidator.js
+++ b/src/composables/useValidator.js
@@ -78,7 +78,8 @@ export function useValidator() {
                 if (min >= 0)
                     if (Math.floor(value) < min) return t('inputMin', { value: min });
             },
-            custom: (value) => validation.bindedFunction(value) || 'Invalid value',
+            custom: (value) =>
+                eval(`(${validation.bindedFunction})`)(value) || 'Invalid value',
         };
     };
 
diff --git a/src/css/app.scss b/src/css/app.scss
index 994ae7ff1..dd5dbe247 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -15,6 +15,7 @@ body.body--light {
     --vn-empty-tag: #acacac;
     --vn-black-text-color: black;
     --vn-text-color-contrast: white;
+    --vn-link-color: #1e90ff;
 
     background-color: var(--vn-page-color);
 
@@ -38,6 +39,7 @@ body.body--dark {
     --vn-empty-tag: #2d2d2d;
     --vn-black-text-color: black;
     --vn-text-color-contrast: black;
+    --vn-link-color: #66bfff;
 
     background-color: var(--vn-page-color);
 
@@ -49,7 +51,7 @@ a {
 }
 
 .link {
-    color: $color-link;
+    color: var(--vn-link-color);
     cursor: pointer;
 
     &--white {
@@ -58,14 +60,14 @@ a {
 }
 
 .tx-color-link {
-    color: $color-link !important;
+    color: var(--vn-link-color) !important;
 }
 .tx-color-font {
-    color: $color-link !important;
+    color: var(--vn-link-color) !important;
 }
 
 .header-link {
-    color: $color-link !important;
+    color: var(--vn-link-color) !important;
     cursor: pointer;
     border-bottom: solid $primary;
     border-width: 2px;
@@ -323,7 +325,6 @@ input::-webkit-inner-spin-button {
         min-height: auto !important;
         display: flex;
         align-items: flex-end;
-        padding-bottom: 2px;
         .q-field__native.row {
             min-height: auto !important;
         }
@@ -337,5 +338,8 @@ input::-webkit-inner-spin-button {
 }
 
 .containerShrinked {
-    width: 80%;
+    width: 70%;
+}
+.q-item__section--main ~ .q-item__section--side {
+    padding-inline: 0;
 }
diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss
index 22c6d2b56..45d18af7e 100644
--- a/src/css/quasar.variables.scss
+++ b/src/css/quasar.variables.scss
@@ -24,7 +24,6 @@ $alert: $negative;
 $white: #fff;
 $dark: #3d3d3d;
 // custom
-$color-link: #66bfff;
 $color-spacer-light: #a3a3a31f;
 $color-spacer: #7979794d;
 $border-thin-light: 1px solid $color-spacer-light;
diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index d7187371e..4f4d1d5f7 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -99,7 +99,6 @@ globals:
     file: File
     selectFile: Select a file
     copyClipboard: Copy on clipboard
-    salesPerson: SalesPerson
     send: Send
     code: Code
     since: Since
@@ -158,7 +157,9 @@ globals:
     changeState: Change state
     raid: 'Raid {daysInForward} days'
     isVies: Vies
+    department: Department
     noData: No data available
+    vehicle: Vehicle
     pageTitles:
         logIn: Login
         addressEdit: Update address
@@ -346,7 +347,6 @@ globals:
     params:
         description: Description
         clientFk: Client id
-        salesPersonFk: Sales person
         warehouseFk: Warehouse
         provinceFk: Province
         stateFk: State
@@ -370,6 +370,11 @@ globals:
         countryCodeFk: Country
         companyFk: Company
         nickname: Alias
+        changedModel: Entity
+        changedModelValue: Search
+        changedModelId: Entity id
+        userFk: User
+        action: Action
     model: Model
     fuel: Fuel
     active: Active
@@ -531,6 +536,7 @@ ticket:
         customerCard: Customer card
         ticketList: Ticket List
         newOrder: New Order
+        ticketClaimed: Claimed ticket
     boxing:
         expedition: Expedition
         created: Created
@@ -603,7 +609,6 @@ worker:
         balance: Balance
         medical: Medical
     list:
-        department: Department
         schedule: Schedule
         newWorker: New worker
     summary:
@@ -646,6 +651,7 @@ worker:
         model: Model
         serialNumber: Serial number
         removePDA: Deallocate PDA
+        sendToTablet: Send to tablet
     create:
         lastName: Last name
         birth: Birth
@@ -816,6 +822,7 @@ travel:
     search: Search travel
     searchInfo: You can search by travel id or name
     id: Id
+    awbFk: AWB
     travelList:
         tableVisibleColumns:
             ref: Reference
@@ -840,6 +847,7 @@ travel:
         availabledHour: Availabled hour
         thermographs: Thermographs
         hb: HB
+        roundedCc: Rounded CC
     basicData:
         daysInForward: Automatic movement (Raid)
         isRaid: Raid
@@ -862,7 +870,6 @@ components:
         mine: For me
         hasMinPrice: Minimum price
         # LatestBuysFilter
-        salesPersonFk: Buyer
         supplierFk: Supplier
         from: From
         to: To
@@ -870,6 +877,11 @@ components:
         active: Is active
         floramondo: Is floramondo
         showBadDates: Show future items
+        name: Nombre
+        rate2: Grouping price
+        rate3: Packing price
+        minPrice: Min. Price
+        itemFk: Item id
     userPanel:
         copyToken: Token copied to clipboard
         settings: Settings
@@ -883,7 +895,7 @@ components:
         openCard: View
         openSummary: Summary
         viewSummary: Summary
-    cardDescriptor:
+    vnDescriptor:
         mainList: Main list
         summary: Summary
         moreOptions: More options
@@ -893,6 +905,8 @@ components:
     VnLv:
         copyText: '{copyValue} has been copied to the clipboard'
     iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789'
+    VnNotes:
+        clientWithoutPhone: 'The following clients do not have a phone number and the message will not be sent to them: {clientWithoutPhone}'
 weekdays:
     sun: Sunday
     mon: Monday
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index fc3018f39..9c808e046 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -103,7 +103,6 @@ globals:
     file: Fichero
     selectFile: Seleccione un fichero
     copyClipboard: Copiar en portapapeles
-    salesPerson: Comercial
     send: Enviar
     code: Código
     since: Desde
@@ -163,6 +162,8 @@ globals:
     raid: 'Redada {daysInForward} días'
     isVies: Vies
     noData: Datos no disponibles
+    department: Departamento
+    vehicle: Vehículo
     pageTitles:
         logIn: Inicio de sesión
         addressEdit: Modificar consignatario
@@ -349,7 +350,6 @@ globals:
     params:
         description: Descripción
         clientFk: Id cliente
-        salesPersonFk: Comercial
         warehouseFk: Almacén
         provinceFk: Provincia
         stateFk: Estado
@@ -371,6 +371,11 @@ globals:
         countryCodeFk: País
         companyFk: Empresa
         nickname: Alias
+        changedModel: Entidad
+        changedModelValue: Buscar
+        changedModelId: Id de entidad
+        userFk: Usuario
+        action: Acción
 errors:
     statusUnauthorized: Acceso denegado
     statusInternalServerError: Ha ocurrido un error interno del servidor
@@ -531,13 +536,13 @@ ticket:
         state: Estado
         shipped: Enviado
         landed: Entregado
-        salesPerson: Comercial
         total: Total
     card:
         customerId: ID cliente
         customerCard: Ficha del cliente
         ticketList: Listado de tickets
         newOrder: Nuevo pedido
+        ticketClaimed: Ticket reclamado
     boxing:
         expedition: Expedición
         created: Creado
@@ -622,8 +627,6 @@ invoiceOut:
         errors:
             downloadCsvFailed: Error al descargar CSV
 order:
-    field:
-        salesPersonFk: Comercial
     form:
         clientFk: Cliente
         addressFk: Dirección
@@ -691,7 +694,6 @@ worker:
         formation: Formación
         medical: Mutua
     list:
-        department: Departamento
         schedule: Horario
         newWorker: Nuevo trabajador
     summary:
@@ -734,6 +736,7 @@ worker:
         model: Modelo
         serialNumber: Número de serie
         removePDA: Desasignar PDA
+        sendToTablet: Enviar a la tablet
     create:
         lastName: Apellido
         birth: Fecha de nacimiento
@@ -902,6 +905,7 @@ travel:
     search: Buscar envío
     searchInfo: Buscar envío por id o nombre
     id: Id
+    awbFk: Guía aérea
     travelList:
         tableVisibleColumns:
             ref: Referencia
@@ -926,6 +930,7 @@ travel:
         availabled: F. Disponible
         availabledHour: Hora Disponible
         hb: HB
+        roundedCc: CC redondeado
     basicData:
         daysInForward: Desplazamiento automatico (redada)
         isRaid: Redada
@@ -949,7 +954,6 @@ components:
         hasMinPrice: Precio mínimo
         wareHouseFk: Almacén
         # LatestBuysFilter
-        salesPersonFk: Comprador
         supplierFk: Proveedor
         visible: Visible
         active: Activo
@@ -957,6 +961,11 @@ components:
         to: Hasta
         floramondo: Floramondo
         showBadDates: Ver items a futuro
+        name: Nombre
+        rate2: Precio grouping
+        rate3: Precio packing
+        minPrice: Precio mínimo
+        itemFk: Id item
     userPanel:
         copyToken: Token copiado al portapapeles
         settings: Configuración
@@ -970,7 +979,7 @@ components:
         openCard: Ficha
         openSummary: Detalles
         viewSummary: Vista previa
-    cardDescriptor:
+    vnDescriptor:
         mainList: Listado principal
         summary: Resumen
         moreOptions: Más opciones
@@ -980,6 +989,8 @@ components:
     VnLv:
         copyText: '{copyValue} se ha copiado al portapepeles'
     iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789'
+    VnNotes:
+        clientWithoutPhone: 'Estos clientes no tienen asociado número de télefono y el sms no les será enviado: {clientWithoutPhone}'
 weekdays:
     sun: Domingo
     mon: Lunes
diff --git a/src/pages/Account/AccountFilter.vue b/src/pages/Account/AccountFilter.vue
index 50c3ee1ac..732e92f77 100644
--- a/src/pages/Account/AccountFilter.vue
+++ b/src/pages/Account/AccountFilter.vue
@@ -47,7 +47,7 @@ const rolesOptions = ref([]);
                         :label="t('globals.name')"
                         v-model="params.name"
                         lazy-rules
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -57,7 +57,7 @@ const rolesOptions = ref([]);
                         :label="t('account.card.alias')"
                         v-model="params.nickname"
                         lazy-rules
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -75,8 +75,7 @@ const rolesOptions = ref([]);
                         use-input
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                         :input-debounce="0"
                     />
                 </QItemSection>
diff --git a/src/pages/Account/AccountList.vue b/src/pages/Account/AccountList.vue
index 976af1d19..4f3f544c1 100644
--- a/src/pages/Account/AccountList.vue
+++ b/src/pages/Account/AccountList.vue
@@ -149,14 +149,12 @@ const columns = computed(() => [
                 :right-search="false"
             >
                 <template #more-create-dialog="{ data }">
-                    <QCardSection>
                         <VnInputPassword
                             :label="t('Password')"
                             v-model="data.password"
                             :required="true"
                             autocomplete="new-password"
                         />
-                    </QCardSection>
                 </template>
             </VnTable>
         </template>
diff --git a/src/pages/Account/Acls/AclFilter.vue b/src/pages/Account/Acls/AclFilter.vue
index 8035f92b8..222fe5b77 100644
--- a/src/pages/Account/Acls/AclFilter.vue
+++ b/src/pages/Account/Acls/AclFilter.vue
@@ -56,8 +56,7 @@ onBeforeMount(() => {
                         option-label="name"
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -72,8 +71,7 @@ onBeforeMount(() => {
                         option-label="name"
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -83,7 +81,7 @@ onBeforeMount(() => {
                         :label="t('acls.aclFilter.property')"
                         v-model="params.property"
                         lazy-rules
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -98,8 +96,7 @@ onBeforeMount(() => {
                         option-label="name"
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -114,8 +111,7 @@ onBeforeMount(() => {
                         option-label="name"
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
diff --git a/src/pages/Account/Alias/Card/AliasCard.vue b/src/pages/Account/Alias/Card/AliasCard.vue
index f37bd7d0f..f3faa5bee 100644
--- a/src/pages/Account/Alias/Card/AliasCard.vue
+++ b/src/pages/Account/Alias/Card/AliasCard.vue
@@ -1,10 +1,10 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import AliasDescriptor from './AliasDescriptor.vue';
 </script>
 
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Alias"
         url="MailAliases"
         :descriptor="AliasDescriptor"
diff --git a/src/pages/Account/Alias/Card/AliasDescriptor.vue b/src/pages/Account/Alias/Card/AliasDescriptor.vue
index 671ef7fbc..957047cc3 100644
--- a/src/pages/Account/Alias/Card/AliasDescriptor.vue
+++ b/src/pages/Account/Alias/Card/AliasDescriptor.vue
@@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { useQuasar } from 'quasar';
 
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 
 import axios from 'axios';
@@ -48,11 +48,12 @@ const removeAlias = () => {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         ref="descriptor"
         :url="`MailAliases/${entityId}`"
         data-key="Alias"
         title="alias"
+        :to-module="{ name: 'AccountAlias' }"
     >
         <template #menu>
             <QItem v-ripple clickable @click="removeAlias()">
@@ -62,7 +63,7 @@ const removeAlias = () => {
         <template #body="{ entity }">
             <VnLv :label="t('role.description')" :value="entity.description" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 
 <i18n>
diff --git a/src/pages/Account/Alias/Card/AliasSummary.vue b/src/pages/Account/Alias/Card/AliasSummary.vue
index b4b9abd25..cfd33ec82 100644
--- a/src/pages/Account/Alias/Card/AliasSummary.vue
+++ b/src/pages/Account/Alias/Card/AliasSummary.vue
@@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n';
 
 import CardSummary from 'components/ui/CardSummary.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
+import VnTitle from 'src/components/common/VnTitle.vue';
 
 const route = useRoute();
 const { t } = useI18n();
@@ -27,13 +28,10 @@ const entityId = computed(() => $props.id || route.params.id);
         <template #body="{ entity: alias }">
             <QCard class="vn-one">
                 <QCardSection class="q-pa-none">
-                    <router-link
-                        :to="{ name: 'AliasBasicData', params: { id: entityId } }"
-                        class="header header-link"
-                    >
-                        {{ t('globals.summary.basicData') }}
-                        <QIcon name="open_in_new" />
-                    </router-link>
+                    <VnTitle
+                        :url="`#/account/alias/${entityId}/basic-data`"
+                        :text="t('globals.summary.basicData')"
+                    />
                 </QCardSection>
                 <VnLv :label="t('role.id')" :value="alias.id" />
                 <VnLv :label="t('role.description')" :value="alias.description" />
diff --git a/src/pages/Account/Card/AccountCard.vue b/src/pages/Account/Card/AccountCard.vue
index a5037e301..e102415c7 100644
--- a/src/pages/Account/Card/AccountCard.vue
+++ b/src/pages/Account/Card/AccountCard.vue
@@ -1,10 +1,10 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import AccountDescriptor from './AccountDescriptor.vue';
 import filter from './AccountFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         url="VnUsers/preview"
         :id-in-where="true"
         data-key="Account"
diff --git a/src/pages/Account/Card/AccountDescriptor.vue b/src/pages/Account/Card/AccountDescriptor.vue
index 49328fe87..eb0a9013c 100644
--- a/src/pages/Account/Card/AccountDescriptor.vue
+++ b/src/pages/Account/Card/AccountDescriptor.vue
@@ -1,7 +1,7 @@
 <script setup>
 import { ref, computed, onMounted } from 'vue';
 import { useRoute } from 'vue-router';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
 import VnImg from 'src/components/ui/VnImg.vue';
@@ -20,7 +20,7 @@ onMounted(async () => {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         ref="descriptor"
         :url="`VnUsers/preview`"
         :filter="{ ...filter, where: { id: entityId } }"
@@ -78,7 +78,7 @@ onMounted(async () => {
                 </QIcon>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <style scoped>
 .q-item__label {
diff --git a/src/pages/Account/Card/AccountDescriptorMenu.vue b/src/pages/Account/Card/AccountDescriptorMenu.vue
index eafd62df6..f3eabb531 100644
--- a/src/pages/Account/Card/AccountDescriptorMenu.vue
+++ b/src/pages/Account/Card/AccountDescriptorMenu.vue
@@ -100,12 +100,8 @@ const onChangePass = (oldPass) => {
 };
 
 onMounted(() => {
-    hasitManagementAccess.value = useAcl().hasAny([
-        { model: 'VnUser', props: 'higherPrivileges', accessType: 'WRITE' },
-    ]);
-    hasSysadminAccess.value = useAcl().hasAny([
-        { model: 'VnUser', props: 'adminUser', accessType: 'WRITE' },
-    ]);
+    hasitManagementAccess.value = useAcl().hasAcl('VnUser', 'higherPrivileges', 'WRITE');
+    hasSysadminAccess.value = useAcl().hasAcl('VnUser', 'adminUser', 'WRITE');
 });
 </script>
 <template>
@@ -227,7 +223,7 @@ onMounted(() => {
         <QItemSection>{{ t('account.card.actions.deactivateUser.name') }}</QItemSection>
     </QItem>
     <QItem
-        v-if="useAcl().hasAny([{ model: 'VnRole', props: '*', accessType: 'WRITE' }])"
+        v-if="useAcl().hasAcl('VnRole', '*', 'WRITE')"
         v-ripple
         clickable
         @click="showSyncDialog = true"
diff --git a/src/pages/Account/Card/AccountDescriptorProxy.vue b/src/pages/Account/Card/AccountDescriptorProxy.vue
new file mode 100644
index 000000000..6a4b3e267
--- /dev/null
+++ b/src/pages/Account/Card/AccountDescriptorProxy.vue
@@ -0,0 +1,14 @@
+<script setup>
+import AccountDescriptor from './AccountDescriptor.vue';
+import AccountSummary from './AccountSummary.vue';
+</script>
+<template>
+    <QPopupProxy style="max-width: 10px">
+        <AccountDescriptor
+            v-if="$attrs.id"
+            v-bind="$attrs"
+            :summary="AccountSummary"
+            :proxy-render="true"
+        />
+    </QPopupProxy>
+</template>
diff --git a/src/pages/Account/Card/AccountSummary.vue b/src/pages/Account/Card/AccountSummary.vue
index f7a16e8c3..a098f10ee 100644
--- a/src/pages/Account/Card/AccountSummary.vue
+++ b/src/pages/Account/Card/AccountSummary.vue
@@ -5,6 +5,7 @@ import CardSummary from 'components/ui/CardSummary.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import filter from './AccountFilter.js';
 import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
+import VnTitle from 'src/components/common/VnTitle.vue';
 
 const $props = defineProps({ id: { type: Number, default: 0 } });
 
@@ -17,7 +18,7 @@ const entityId = computed(() => $props.id || route.params.id);
         data-key="Account"
         ref="AccountSummary"
         url="VnUsers/preview"
-        :filter="filter"
+        :filter="{ ...filter, where: { id: entityId } }"
     >
         <template #header="{ entity }">{{ entity.id }} - {{ entity.nickname }}</template>
         <template #menu>
@@ -26,13 +27,10 @@ const entityId = computed(() => $props.id || route.params.id);
         <template #body="{ entity }">
             <QCard class="vn-one">
                 <QCardSection class="q-pa-none">
-                    <router-link
-                        :to="{ name: 'AccountBasicData', params: { id: entityId } }"
-                        class="header header-link"
-                    >
-                        {{ $t('globals.pageTitles.basicData') }}
-                        <QIcon name="open_in_new" />
-                    </router-link>
+                    <VnTitle
+                        :url="`#/account/${entityId}/basic-data`"
+                        :text="$t('globals.pageTitles.basicData')"
+                    />
                 </QCardSection>
                 <VnLv :label="$t('account.card.nickname')" :value="entity.name" />
                 <VnLv :label="$t('account.card.role')" :value="entity.role?.name" />
diff --git a/src/pages/Account/Role/AccountRolesFilter.vue b/src/pages/Account/Role/AccountRolesFilter.vue
index cbe7a70c8..1358236c6 100644
--- a/src/pages/Account/Role/AccountRolesFilter.vue
+++ b/src/pages/Account/Role/AccountRolesFilter.vue
@@ -27,7 +27,7 @@ const props = defineProps({
                         :label="t('globals.name')"
                         v-model="params.name"
                         lazy-rules
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -37,7 +37,7 @@ const props = defineProps({
                         :label="t('role.description')"
                         v-model="params.description"
                         lazy-rules
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
diff --git a/src/pages/Account/Role/Card/RoleCard.vue b/src/pages/Account/Role/Card/RoleCard.vue
index ef5b9db04..43ad22b90 100644
--- a/src/pages/Account/Role/Card/RoleCard.vue
+++ b/src/pages/Account/Role/Card/RoleCard.vue
@@ -1,9 +1,9 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import RoleDescriptor from './RoleDescriptor.vue';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         url="VnRoles"
         data-key="Role"
         :id-in-where="true"
diff --git a/src/pages/Account/Role/Card/RoleDescriptor.vue b/src/pages/Account/Role/Card/RoleDescriptor.vue
index 517517af0..698bea4fa 100644
--- a/src/pages/Account/Role/Card/RoleDescriptor.vue
+++ b/src/pages/Account/Role/Card/RoleDescriptor.vue
@@ -2,7 +2,7 @@
 import { computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import axios from 'axios';
 import useNotify from 'src/composables/useNotify.js';
@@ -32,11 +32,12 @@ const removeRole = async () => {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         url="VnRoles"
         :filter="{ where: { id: entityId } }"
         data-key="Role"
         :summary="$props.summary"
+        :to-module="{ name: 'AccountRoles' }"
     >
         <template #menu>
             <QItem v-ripple clickable @click="removeRole()">
@@ -46,7 +47,7 @@ const removeRole = async () => {
         <template #body="{ entity }">
             <VnLv :label="t('role.description')" :value="entity.description" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <style scoped>
 .q-item__label {
diff --git a/src/pages/Account/Role/Card/RoleSummary.vue b/src/pages/Account/Role/Card/RoleSummary.vue
index 410f90b17..baa4afeca 100644
--- a/src/pages/Account/Role/Card/RoleSummary.vue
+++ b/src/pages/Account/Role/Card/RoleSummary.vue
@@ -4,6 +4,7 @@ import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import CardSummary from 'components/ui/CardSummary.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
+import VnTitle from 'src/components/common/VnTitle.vue';
 
 const route = useRoute();
 const { t } = useI18n();
@@ -29,13 +30,10 @@ const entityId = computed(() => $props.id || route.params.id);
         <template #body="{ entity }">
             <QCard class="vn-one">
                 <QCardSection class="q-pa-none">
-                    <a
-                        class="header header-link"
-                        :href="`#/VnUser/${entityId}/basic-data`"
-                    >
-                        {{ t('globals.pageTitles.basicData') }}
-                        <QIcon name="open_in_new" />
-                    </a>
+                    <VnTitle
+                        :url="`#/account/role/${entityId}/basic-data`"
+                        :text="$t('globals.pageTitles.basicData')"
+                    />
                 </QCardSection>
                 <VnLv :label="t('role.id')" :value="entity.id" />
                 <VnLv :label="t('globals.name')" :value="entity.name" />
diff --git a/src/pages/Claim/Card/ClaimAction.vue b/src/pages/Claim/Card/ClaimAction.vue
index baa36710c..a499d8b5d 100644
--- a/src/pages/Claim/Card/ClaimAction.vue
+++ b/src/pages/Claim/Card/ClaimAction.vue
@@ -328,7 +328,7 @@ async function post(query, params) {
                     <QTd>
                         <VnSelect
                             v-model="row.shelvingFk"
-                            :options="shelvings"
+                            url="Shelvings"
                             option-label="code"
                             option-value="id"
                             style="width: 100px"
diff --git a/src/pages/Claim/Card/ClaimBasicData.vue b/src/pages/Claim/Card/ClaimBasicData.vue
index 43941d1dc..7e7d42ae8 100644
--- a/src/pages/Claim/Card/ClaimBasicData.vue
+++ b/src/pages/Claim/Card/ClaimBasicData.vue
@@ -2,6 +2,7 @@
 import { ref } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
+import { getDifferences, getUpdatedValues } from 'src/filters';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
 import FetchData from 'components/FetchData.vue';
@@ -9,12 +10,18 @@ import FormModel from 'components/FormModel.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import VnInputDate from 'components/common/VnInputDate.vue';
-
 import VnAvatar from 'src/components/ui/VnAvatar.vue';
 
 const route = useRoute();
 const { t } = useI18n();
 const workersOptions = ref([]);
+
+function onBeforeSave(formData, originalData) {
+    return getUpdatedValues(
+        Object.keys(getDifferences(formData, originalData)),
+        formData,
+    );
+}
 </script>
 <template>
     <FetchData
@@ -27,6 +34,7 @@ const workersOptions = ref([]);
     <FormModel
         model="Claim"
         :url-update="`Claims/updateClaim/${route.params.id}`"
+        :mapper="onBeforeSave"
         auto-load
     >
         <template #form="{ data, validate }">
diff --git a/src/pages/Claim/Card/ClaimCard.vue b/src/pages/Claim/Card/ClaimCard.vue
index 05f3b53a8..307a6df40 100644
--- a/src/pages/Claim/Card/ClaimCard.vue
+++ b/src/pages/Claim/Card/ClaimCard.vue
@@ -1,10 +1,10 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import ClaimDescriptor from './ClaimDescriptor.vue';
 import filter from './ClaimFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Claim"
         url="Claims"
         :descriptor="ClaimDescriptor"
diff --git a/src/pages/Claim/Card/ClaimDescriptor.vue b/src/pages/Claim/Card/ClaimDescriptor.vue
index 4551c58fe..76ede81ed 100644
--- a/src/pages/Claim/Card/ClaimDescriptor.vue
+++ b/src/pages/Claim/Card/ClaimDescriptor.vue
@@ -5,7 +5,8 @@ import { useI18n } from 'vue-i18n';
 import { toDateHourMinSec, toPercentage } from 'src/filters';
 import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
 import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import VnUserLink from 'src/components/ui/VnUserLink.vue';
 import { getUrl } from 'src/composables/getUrl';
@@ -43,7 +44,7 @@ onMounted(async () => {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         :url="`Claims/${entityId}`"
         :filter="filter"
         title="client.name"
@@ -65,12 +66,12 @@ onMounted(async () => {
                 </template>
             </VnLv>
             <VnLv :label="t('claim.created')" :value="toDateHourMinSec(entity.created)" />
-            <VnLv :label="t('claim.commercial')">
+            <VnLv :label="t('globals.department')">
                 <template #value>
-                    <VnUserLink
-                        :name="entity.client?.salesPersonUser?.name"
-                        :worker-id="entity.client?.salesPersonFk"
-                    />
+                    <span class="link">
+                        {{ entity?.client?.department?.name || '-' }}
+                        <DepartmentDescriptorProxy :id="entity?.client?.departmentFk" />
+                    </span>
                 </template>
             </VnLv>
             <VnLv
@@ -146,7 +147,7 @@ onMounted(async () => {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <style scoped>
 .q-item__label {
diff --git a/src/pages/Claim/Card/ClaimDescriptorProxy.vue b/src/pages/Claim/Card/ClaimDescriptorProxy.vue
new file mode 100644
index 000000000..78e686745
--- /dev/null
+++ b/src/pages/Claim/Card/ClaimDescriptorProxy.vue
@@ -0,0 +1,14 @@
+<script setup>
+import ClaimDescriptor from './ClaimDescriptor.vue';
+import ClaimSummary from './ClaimSummary.vue';
+</script>
+<template>
+    <QPopupProxy style="max-width: 10px">
+        <ClaimDescriptor
+            v-if="$attrs.id"
+            v-bind="$attrs.id"
+            :summary="ClaimSummary"
+            :proxy-render="true"
+        />
+    </QPopupProxy>
+</template>
diff --git a/src/pages/Claim/Card/ClaimFilter.js b/src/pages/Claim/Card/ClaimFilter.js
index 50cabe228..4f119544c 100644
--- a/src/pages/Claim/Card/ClaimFilter.js
+++ b/src/pages/Claim/Card/ClaimFilter.js
@@ -14,7 +14,7 @@ export default {
             relation: 'client',
             scope: {
                 include: [
-                    { relation: 'salesPersonUser' },
+                    { relation: 'department' },
                     {
                         relation: 'claimsRatio',
                         scope: {
diff --git a/src/pages/Claim/Card/ClaimLines.vue b/src/pages/Claim/Card/ClaimLines.vue
index dee03b95d..7c948bb2f 100644
--- a/src/pages/Claim/Card/ClaimLines.vue
+++ b/src/pages/Claim/Card/ClaimLines.vue
@@ -117,7 +117,7 @@ const selected = ref([]);
 const mana = ref(0);
 async function fetchMana() {
     const ticketId = claim.value.ticketFk;
-    const response = await axios.get(`Tickets/${ticketId}/getSalesPersonMana`);
+    const response = await axios.get(`Tickets/${ticketId}/getDepartmentMana`);
     mana.value = response.data;
 }
 
diff --git a/src/pages/Claim/Card/ClaimSummary.vue b/src/pages/Claim/Card/ClaimSummary.vue
index 210b0c982..67d57004f 100644
--- a/src/pages/Claim/Card/ClaimSummary.vue
+++ b/src/pages/Claim/Card/ClaimSummary.vue
@@ -19,7 +19,9 @@ import ClaimNotes from 'src/pages/Claim/Card/ClaimNotes.vue';
 import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
 import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import ClaimDescriptorMenu from './ClaimDescriptorMenu.vue';
+import VnDropdown from 'src/components/common/VnDropdown.vue';
 
 const route = useRoute();
 const router = useRouter();
@@ -35,7 +37,7 @@ const $props = defineProps({
 });
 
 const entityId = computed(() => $props.id || route.params.id);
-const ClaimStates = ref([]);
+const claimStates = ref([]);
 const claimDmsRef = ref();
 const claimDms = ref([]);
 const multimediaDialog = ref();
@@ -172,7 +174,9 @@ function openDialog(dmsId) {
 }
 
 async function changeState(value) {
-    await axios.patch(`Claims/updateClaim/${entityId.value}`, { claimStateFk: value });
+    await axios.patch(`Claims/updateClaim/${entityId.value}`, {
+        claimStateFk: value,
+    });
     router.go(route.fullPath);
 }
 
@@ -182,13 +186,18 @@ function claimUrl(section) {
 </script>
 
 <template>
+    <FetchData
+        url="ClaimStates"
+        :filter="{ fields: ['id', 'description'] }"
+        @on-fetch="(data) => (claimStates = data)"
+        auto-load
+    />
     <FetchData
         url="ClaimDms"
         :filter="claimDmsFilter"
         @on-fetch="(data) => setClaimDms(data)"
         ref="claimDmsRef"
     />
-    <FetchData url="ClaimStates" @on-fetch="(data) => (ClaimStates = data)" auto-load />
     <CardSummary
         ref="summary"
         :url="`Claims/${entityId}/getSummary`"
@@ -200,34 +209,11 @@ function claimUrl(section) {
             {{ claim.id }} - {{ claim.client.name }} ({{ claim.client.id }})
         </template>
         <template #header-right>
-            <QBtnDropdown
-                side
-                top
-                color="black"
-                text-color="white"
-                :label="t('globals.changeState')"
-            >
-                <QList>
-                    <QVirtualScroll
-                        class="max-container-height"
-                        :items="ClaimStates"
-                        separator
-                        v-slot="{ item, index }"
-                    >
-                        <QItem
-                            :key="index"
-                            dense
-                            clickable
-                            v-close-popup
-                            @click="changeState(item.id)"
-                        >
-                            <QItemSection>
-                                <QItemLabel>{{ item.description }}</QItemLabel>
-                            </QItemSection>
-                        </QItem>
-                    </QVirtualScroll>
-                </QList>
-            </QBtnDropdown>
+            <VnDropdown
+                :options="claimStates"
+                option-label="description"
+                @change-state="changeState"
+            />
         </template>
         <template #menu="{ entity }">
             <ClaimDescriptorMenu :claim="entity.claim" />
@@ -252,13 +238,15 @@ function claimUrl(section) {
                 </VnLv>
                 <VnLv
                     v-if="$route.name != 'ClaimSummary'"
-                    :label="t('globals.salesPerson')"
+                    :label="t('customer.summary.team')"
                 >
                     <template #value>
-                        <VnUserLink
-                            :name="claim.client?.salesPersonUser?.name"
-                            :worker-id="claim.client?.salesPersonFk"
-                        />
+                        <span class="link">
+                            {{ claim?.client?.department?.name || '-' }}
+                            <DepartmentDescriptorProxy
+                                :id="claim?.client?.departmentFk"
+                            />
+                        </span>
                     </template>
                 </VnLv>
                 <VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.attendedBy')">
@@ -271,7 +259,7 @@ function claimUrl(section) {
                 </VnLv>
                 <VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.customer')">
                     <template #value>
-                        <span class="link cursor-pointer">
+                        <span class="link">
                             {{ claim.client?.name }}
                             <CustomerDescriptorProxy :id="claim.clientFk" />
                         </span>
diff --git a/src/pages/Claim/Card/ClaimSummaryAction.vue b/src/pages/Claim/Card/ClaimSummaryAction.vue
index e5273902c..be3b9e896 100644
--- a/src/pages/Claim/Card/ClaimSummaryAction.vue
+++ b/src/pages/Claim/Card/ClaimSummaryAction.vue
@@ -80,7 +80,7 @@ const columns = [
         :right-search="false"
         :column-search="false"
         :disable-option="{ card: true, table: true }"
-        search-url="actions"
+        :search-url="false"
         :filter="{ where: { claimFk: $props.id } }"
         :columns="columns"
         :limit="0"
@@ -88,13 +88,13 @@ const columns = [
         auto-load
     >
         <template #column-itemFk="{ row }">
-            <span class="link">
+            <span class="link" @click.stop>
                 {{ row.itemFk }}
                 <ItemDescriptorProxy :id="row.itemFk" />
             </span>
         </template>
         <template #column-ticketFk="{ row }">
-            <span class="link">
+            <span class="link" @click.stop>
                 {{ row.ticketFk }}
                 <TicketDescriptorProxy :id="row.ticketFk" />
             </span>
diff --git a/src/pages/Claim/Card/__tests__/ClaimDescriptorMenu.spec.js b/src/pages/Claim/Card/__tests__/ClaimDescriptorMenu.spec.js
index b208f1704..2142f41f2 100644
--- a/src/pages/Claim/Card/__tests__/ClaimDescriptorMenu.spec.js
+++ b/src/pages/Claim/Card/__tests__/ClaimDescriptorMenu.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
 
 describe('ClaimDescriptorMenu', () => {
diff --git a/src/pages/Claim/Card/__tests__/ClaimLines.spec.js b/src/pages/Claim/Card/__tests__/ClaimLines.spec.js
index ffbd6bf06..1ed5cccab 100644
--- a/src/pages/Claim/Card/__tests__/ClaimLines.spec.js
+++ b/src/pages/Claim/Card/__tests__/ClaimLines.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, beforeEach, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import ClaimLines from '/src/pages/Claim/Card/ClaimLines.vue';
 
 describe('ClaimLines', () => {
diff --git a/src/pages/Claim/Card/__tests__/ClaimLinesImport.spec.js b/src/pages/Claim/Card/__tests__/ClaimLinesImport.spec.js
index 1c4f367d4..cec4b1681 100644
--- a/src/pages/Claim/Card/__tests__/ClaimLinesImport.spec.js
+++ b/src/pages/Claim/Card/__tests__/ClaimLinesImport.spec.js
@@ -1,5 +1,6 @@
-import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { vi, describe, expect, it, beforeAll, beforeEach, afterEach } from 'vitest';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import ClaimLinesImport from 'pages/Claim/Card/ClaimLinesImport.vue';
 
 describe('ClaimLinesImport', () => {
diff --git a/src/pages/Claim/Card/__tests__/ClaimPhoto.spec.js b/src/pages/Claim/Card/__tests__/ClaimPhoto.spec.js
index 8949e18a9..bf3548af3 100644
--- a/src/pages/Claim/Card/__tests__/ClaimPhoto.spec.js
+++ b/src/pages/Claim/Card/__tests__/ClaimPhoto.spec.js
@@ -1,7 +1,7 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import ClaimPhoto from 'pages/Claim/Card/ClaimPhoto.vue';
-
 describe('ClaimPhoto', () => {
     let vm;
 
diff --git a/src/pages/Claim/ClaimFilter.vue b/src/pages/Claim/ClaimFilter.vue
index 0fe7fc588..45eb89382 100644
--- a/src/pages/Claim/ClaimFilter.vue
+++ b/src/pages/Claim/ClaimFilter.vue
@@ -33,7 +33,7 @@ const props = defineProps({
                     :label="t('claim.customerId')"
                     v-model="params.clientFk"
                     lazy-rules
-                    is-outlined
+                    filled
                 >
                     <template #prepend> <QIcon name="badge" size="xs" /></template>
                 </VnInput>
@@ -41,18 +41,16 @@ const props = defineProps({
                     :label="t('Client Name')"
                     v-model="params.clientName"
                     lazy-rules
-                    is-outlined
+                    filled
                 />
                 <VnSelect
-                    :label="t('Salesperson')"
-                    v-model="params.salesPersonFk"
-                    url="Workers/activeWithInheritedRole"
-                    :filter="{ where: { role: 'salesPerson' } }"
-                    :use-like="false"
-                    option-filter="firstName"
                     dense
-                    outlined
-                    rounded
+                    filled
+                    :label="t('globals.params.departmentFk')"
+                    v-model="params.departmentFk"
+                    option-value="id"
+                    option-label="name"
+                    url="Departments"
                 />
                 <VnSelect
                     :label="t('claim.attendedBy')"
@@ -62,8 +60,7 @@ const props = defineProps({
                     :use-like="false"
                     option-filter="firstName"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnSelect
                     :label="t('claim.state')"
@@ -71,14 +68,12 @@ const props = defineProps({
                     :options="states"
                     option-label="description"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnInputDate
                     v-model="params.created"
                     :label="t('claim.created')"
-                    outlined
-                    rounded
+                    filled
                     dense
                 />
                 <VnSelect
@@ -87,8 +82,7 @@ const props = defineProps({
                     url="Items/withName"
                     :use-like="false"
                     sort-by="id DESC"
-                    outlined
-                    rounded
+                    filled
                     dense
                 />
                 <VnSelect
@@ -99,15 +93,13 @@ const props = defineProps({
                     :use-like="false"
                     option-filter="firstName"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnSelect
                     :label="t('claim.zone')"
                     v-model="params.zoneFk"
                     url="Zones"
-                    outlined
-                    rounded
+                    filled
                     dense
                 />
                 <QCheckbox
@@ -123,10 +115,10 @@ const props = defineProps({
 <i18n>
 en:
     params:
+        departmentFk: Department
         search: Contains
         clientFk: Customer
         clientName: Customer
-        salesPersonFk: Salesperson
         attenderFk: Attender
         claimResponsibleFk: Responsible
         claimStateFk: State
@@ -136,10 +128,10 @@ en:
         zoneFk: Zone
 es:
     params:
+        departmentFk: Departamento
         search: Contiene
         clientFk: Cliente
         clientName: Cliente
-        salesPersonFk: Comercial
         attenderFk: Asistente
         claimResponsibleFk: Responsable
         claimStateFk: Estado
@@ -148,6 +140,5 @@ es:
         itemFk: Artículo
         zoneFk: Zona
     Client Name: Nombre del cliente
-    Salesperson: Comercial
     Item: Artículo
 </i18n>
diff --git a/src/pages/Claim/ClaimList.vue b/src/pages/Claim/ClaimList.vue
index 41d0c5598..e0d9928f9 100644
--- a/src/pages/Claim/ClaimList.vue
+++ b/src/pages/Claim/ClaimList.vue
@@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
 import { toDate } from 'filters/index';
 import ClaimFilter from './ClaimFilter.vue';
 import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import VnUserLink from 'src/components/ui/VnUserLink.vue';
 import ClaimSummary from './Card/ClaimSummary.vue';
 import { useSummaryDialog } from 'src/composables/useSummaryDialog';
@@ -48,6 +49,20 @@ const columns = computed(() => [
         },
         columnClass: 'expand',
     },
+    {
+        align: 'left',
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
+        component: 'select',
+        attrs: {
+            url: 'Departments',
+        },
+        create: true,
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
+    },
     {
         align: 'left',
         label: t('claim.attendedBy'),
@@ -119,7 +134,7 @@ const columns = computed(() => [
 
 const STATE_COLOR = {
     pending: 'bg-warning',
-    managed: 'bg-info',
+    loses: 'bg-negative',
     resolved: 'bg-positive',
 };
 </script>
@@ -152,6 +167,12 @@ const STATE_COLOR = {
                         <CustomerDescriptorProxy :id="row.clientFk" />
                     </span>
                 </template>
+                <template #column-departmentFk="{ row }">
+                    <span class="link" @click.stop>
+                        {{ row.departmentName || '-' }}
+                        <DepartmentDescriptorProxy :id="row?.departmentFk" />
+                    </span>
+                </template>
                 <template #column-attendedBy="{ row }">
                     <span @click.stop>
                         <VnUserLink :name="row.workerName" :worker-id="row.workerFk" />
diff --git a/src/pages/Customer/Card/CustomerBalance.vue b/src/pages/Customer/Card/CustomerBalance.vue
index 11db92eab..4855fadc0 100644
--- a/src/pages/Customer/Card/CustomerBalance.vue
+++ b/src/pages/Customer/Card/CustomerBalance.vue
@@ -20,11 +20,12 @@ import VnFilter from 'components/VnTable/VnFilter.vue';
 
 import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
 import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
+import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 
 const { openConfirmationModal } = useVnConfirm();
 const { sendEmail, openReport } = usePrintService();
 const { t } = useI18n();
-const { hasAny } = useAcl();
+const { hasAcl } = useAcl();
 
 const quasar = useQuasar();
 const route = useRoute();
@@ -89,15 +90,7 @@ const columns = computed(() => [
     {
         align: 'left',
         label: t('Employee'),
-        columnField: {
-            component: 'userLink',
-            attrs: ({ row }) => {
-                return {
-                    workerId: row.workerFk,
-                    name: row.userName,
-                };
-            },
-        },
+        name: 'workerFk',
         cardVisible: true,
     },
     {
@@ -131,7 +124,6 @@ const columns = computed(() => [
         align: 'left',
         name: 'balance',
         label: t('Balance'),
-        format: ({ balance }) => toCurrency(balance),
         cardVisible: true,
     },
     {
@@ -146,12 +138,14 @@ const columns = computed(() => [
         actions: [
             {
                 title: t('globals.downloadPdf'),
+                isPrimary: true,
                 icon: 'cloud_download',
                 show: (row) => row.isInvoice,
                 action: (row) => showBalancePdf(row),
             },
             {
                 title: t('Send compensation'),
+                isPrimary: true,
                 icon: 'outgoing_mail',
                 show: (row) => !!row.isCompensation,
                 action: ({ id }) =>
@@ -256,6 +250,12 @@ const showBalancePdf = ({ id }) => {
         <template #column-balance="{ rowIndex }">
             {{ toCurrency(balances[rowIndex]?.balance) }}
         </template>
+        <template #column-workerFk="{ row }">
+            <span class="link" @click.stop>
+                {{ row.userName }}
+                <WorkerDescriptorProxy :id="row.workerFk" />
+            </span>
+        </template>
         <template #column-description="{ row }">
             <span class="link" v-if="row.isInvoice" @click.stop>
                 {{ t('bill', { ref: row.description }) }}
@@ -276,9 +276,7 @@ const showBalancePdf = ({ id }) => {
             >
                 <VnInput
                     v-model="scope.value"
-                    :disable="
-                        !hasAny([{ model: 'Receipt', props: '*', accessType: 'WRITE' }])
-                    "
+                    :disable="!hasAcl('Receipt', '*', 'WRITE')"
                     @keypress.enter="scope.set"
                     autofocus
                 />
diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue
index 36ec4763e..9c9d1b50b 100644
--- a/src/pages/Customer/Card/CustomerBasicData.vue
+++ b/src/pages/Customer/Card/CustomerBasicData.vue
@@ -8,7 +8,6 @@ import FormModel from 'components/FormModel.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
-import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
 import { getDifferences, getUpdatedValues } from 'src/filters';
 
 const route = useRoute();
@@ -37,7 +36,7 @@ const exprBuilder = (param, value) => {
 function onBeforeSave(formData, originalData) {
     return getUpdatedValues(
         Object.keys(getDifferences(formData, originalData)),
-        formData
+        formData,
     );
 }
 </script>
@@ -119,16 +118,11 @@ function onBeforeSave(formData, originalData) {
                 />
             </VnRow>
             <VnRow>
-                <VnSelectWorker
-                    :label="t('customer.summary.salesPerson')"
-                    v-model="data.salesPersonFk"
-                    :params="{
-                        departmentCodes: ['VT', 'shopping'],
-                    }"
-                    :has-avatar="true"
-                    :rules="validate('client.salesPersonFk')"
-                    :expr-builder="exprBuilder"
-                    emit-value
+                <VnSelect
+                    :label="t('globals.department')"
+                    v-model="data.departmentFk"
+                    url="Departments"
+                    :fields="['id', 'name']"
                 />
                 <VnSelect
                     v-model="data.contactChannelFk"
@@ -160,7 +154,7 @@ function onBeforeSave(formData, originalData) {
                         <QIcon name="info" class="cursor-pointer">
                             <QTooltip>{{
                                 t(
-                                    'In case of a company succession, specify the grantor company'
+                                    'In case of a company succession, specify the grantor company',
                                 )
                             }}</QTooltip>
                         </QIcon>
diff --git a/src/pages/Customer/Card/CustomerCard.vue b/src/pages/Customer/Card/CustomerCard.vue
index 75fcb98fa..8c70646c1 100644
--- a/src/pages/Customer/Card/CustomerCard.vue
+++ b/src/pages/Customer/Card/CustomerCard.vue
@@ -1,10 +1,10 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import CustomerDescriptor from './CustomerDescriptor.vue';
 </script>
 
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Customer"
         :url="`Clients/${$route.params.id}/getCard`"
         :descriptor="CustomerDescriptor"
diff --git a/src/pages/Customer/Card/CustomerDescriptor.vue b/src/pages/Customer/Card/CustomerDescriptor.vue
index e3156dd6d..c7461f890 100644
--- a/src/pages/Customer/Card/CustomerDescriptor.vue
+++ b/src/pages/Customer/Card/CustomerDescriptor.vue
@@ -3,14 +3,14 @@ import { onMounted, ref, computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 
-import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
+import { toCurrency, toDate } from 'src/filters';
 
 import useCardDescription from 'src/composables/useCardDescription';
 
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
-import VnUserLink from 'src/components/ui/VnUserLink.vue';
 import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import { useState } from 'src/composables/useState';
 const state = useState();
 
@@ -54,7 +54,7 @@ const debtWarning = computed(() => {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         :url="`Clients/${entityId}/getCard`"
         :summary="$props.summary"
         data-key="Customer"
@@ -84,14 +84,10 @@ const debtWarning = computed(() => {
                 :value="toCurrency(entity.debt)"
                 :info="t('customer.summary.riskInfo')"
             />
-            <VnLv :label="t('customer.summary.salesPerson')">
+            <VnLv :label="t('globals.department')">
                 <template #value>
-                    <VnUserLink
-                        v-if="entity.salesPersonUser"
-                        :name="entity.salesPersonUser.name"
-                        :worker-id="entity.salesPersonFk"
-                    />
-                    <span v-else>{{ dashIfEmpty(entity.salesPersonUser) }}</span>
+                    <span class="link" v-text="entity.department?.name" />
+                    <DepartmentDescriptorProxy :id="entity.department?.id" />
                 </template>
             </VnLv>
             <VnLv
@@ -109,15 +105,6 @@ const debtWarning = computed(() => {
                 >
                     <QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
                 </QIcon>
-
-                <QIcon
-                    v-if="entity?.substitutionAllowed"
-                    name="help"
-                    size="xs"
-                    color="primary"
-                >
-                    <QTooltip>{{ t('Allowed substitution') }}</QTooltip>
-                </QIcon>
                 <QIcon
                     v-if="!entity.account?.active"
                     color="primary"
@@ -236,7 +223,7 @@ const debtWarning = computed(() => {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 
 <i18n>
diff --git a/src/pages/Customer/Card/CustomerDescriptorMenu.vue b/src/pages/Customer/Card/CustomerDescriptorMenu.vue
index aea45721c..fb78eab69 100644
--- a/src/pages/Customer/Card/CustomerDescriptorMenu.vue
+++ b/src/pages/Customer/Card/CustomerDescriptorMenu.vue
@@ -61,16 +61,6 @@ const openCreateForm = (type) => {
         .join('&');
     useOpenURL(`/#/${type}/list?${params}`);
 };
-const updateSubstitutionAllowed = async () => {
-    try {
-        await axios.patch(`Clients/${route.params.id}`, {
-            substitutionAllowed: !$props.customer.substitutionAllowed,
-        });
-        notify('globals.notificationSent', 'positive');
-    } catch (error) {
-        notify(error.message, 'positive');
-    }
-};
 </script>
 
 <template>
@@ -79,13 +69,6 @@ const updateSubstitutionAllowed = async () => {
             {{ t('globals.pageTitles.createTicket') }}
         </QItemSection>
     </QItem>
-    <QItem v-ripple clickable>
-        <QItemSection @click="updateSubstitutionAllowed()">{{
-            $props.customer.substitutionAllowed
-                ? t('Disable substitution')
-                : t('Allow substitution')
-        }}</QItemSection>
-    </QItem>
     <QItem v-ripple clickable>
         <QItemSection @click="showSmsDialog()">{{ t('Send SMS') }}</QItemSection>
     </QItem>
diff --git a/src/pages/Customer/Card/CustomerFileManagement.vue b/src/pages/Customer/Card/CustomerFileManagement.vue
index b565db6e7..419719251 100644
--- a/src/pages/Customer/Card/CustomerFileManagement.vue
+++ b/src/pages/Customer/Card/CustomerFileManagement.vue
@@ -86,12 +86,12 @@ const tableColumnComponents = {
     },
     file: {
         component: QBtn,
-        props: () => ({ flat: true, color: 'blue' }),
+        props: () => ({ flat: true }),
         event: ({ row }) => downloadFile(row.dmsFk),
     },
     employee: {
         component: QBtn,
-        props: () => ({ flat: true, color: 'blue' }),
+        props: () => ({ flat: true }),
         event: () => {},
     },
     created: {
@@ -214,8 +214,17 @@ const toCustomerFileManagementCreate = () => {
                             v-bind="tableColumnComponents[props.col.name].props(props)"
                         >
                             <template v-if="props.col.name !== 'original'">
-                                {{ props.value }}
+                                <span
+                                    :class="{
+                                        link:
+                                            props.col.name === 'employee' ||
+                                            props.col.name === 'file',
+                                    }"
+                                >
+                                    {{ props.value }}
+                                </span>
                             </template>
+
                             <WorkerDescriptorProxy
                                 :id="props.row.dms.workerFk"
                                 v-if="props.col.name === 'employee'"
diff --git a/src/pages/Customer/Card/CustomerFiscalData.vue b/src/pages/Customer/Card/CustomerFiscalData.vue
index 93909eb9c..baa728868 100644
--- a/src/pages/Customer/Card/CustomerFiscalData.vue
+++ b/src/pages/Customer/Card/CustomerFiscalData.vue
@@ -79,7 +79,7 @@ async function acceptPropagate({ isEqualizated }) {
         observe-form-changes
         @on-data-saved="checkEtChanges"
     >
-        <template #form="{ data, validate }">
+        <template #form="{ data, validate, validations }">
             <VnRow>
                 <VnInput
                     :label="t('Social name')"
@@ -112,6 +112,7 @@ async function acceptPropagate({ isEqualizated }) {
                     v-model="data.sageTaxTypeFk"
                     data-cy="sageTaxTypeFk"
                     :required="data.isTaxDataChecked"
+                    :rules="[(val) => validations.required(data.isTaxDataChecked, val)]"
                 />
                 <VnSelect
                     :label="t('Sage transaction type')"
@@ -122,6 +123,9 @@ async function acceptPropagate({ isEqualizated }) {
                     data-cy="sageTransactionTypeFk"
                     v-model="data.sageTransactionTypeFk"
                     :required="data.isTaxDataChecked"
+                    :rules="[
+                        (val) => validations.required(data.sageTransactionTypeFk, val),
+                    ]"
                 >
                     <template #option="scope">
                         <QItem v-bind="scope.itemProps">
diff --git a/src/pages/Customer/Card/CustomerMandates.vue b/src/pages/Customer/Card/CustomerMandates.vue
index 66cb44bc2..2511f5730 100644
--- a/src/pages/Customer/Card/CustomerMandates.vue
+++ b/src/pages/Customer/Card/CustomerMandates.vue
@@ -16,9 +16,7 @@ const filter = {
         { relation: 'mandateType', scope: { fields: ['id', 'code'] } },
         { relation: 'company', scope: { fields: ['id', 'code'] } },
     ],
-    where: { clientFk: route.params.id },
     order: ['created DESC'],
-    limit: 20,
 };
 
 const columns = computed(() => [
@@ -32,7 +30,7 @@ const columns = computed(() => [
     {
         align: 'left',
         cardVisible: true,
-        format: ({ company }) => company.code,
+        format: ({ company }) => company?.code,
         label: t('globals.company'),
         name: 'company',
     },
@@ -65,7 +63,8 @@ const columns = computed(() => [
         <VnTable
             data-key="Mandates"
             url="Mandates"
-            :filter="filter"
+            :user-filter="filter"
+            :filter="{ where: { clientFk: route.params.id } }"
             auto-load
             :columns="columns"
             class="full-width q-mt-md"
diff --git a/src/pages/Customer/Card/CustomerSummary.vue b/src/pages/Customer/Card/CustomerSummary.vue
index c98bf1ffb..9d30f0c6d 100644
--- a/src/pages/Customer/Card/CustomerSummary.vue
+++ b/src/pages/Customer/Card/CustomerSummary.vue
@@ -2,7 +2,6 @@
 import { computed, ref } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import VnUserLink from 'src/components/ui/VnUserLink.vue';
 
 import { toCurrency, toPercentage, toDate, dashOrCurrency } from 'src/filters';
 import CardSummary from 'components/ui/CardSummary.vue';
@@ -13,6 +12,8 @@ import CustomerSummaryTable from 'src/pages/Customer/components/CustomerSummaryT
 import VnTitle from 'src/components/common/VnTitle.vue';
 import VnRow from 'src/components/ui/VnRow.vue';
 import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
+
 const route = useRoute();
 const { t } = useI18n();
 const grafanaUrl = 'https://grafana.verdnatura.es';
@@ -83,39 +84,37 @@ const sumRisk = ({ clientRisks }) => {
                 <VnLv :label="t('customer.summary.customerId')" :value="entity.id" />
                 <VnLv :label="t('globals.name')" :value="entity.name" />
                 <VnLv :label="t('customer.summary.contact')" :value="entity.contact" />
-                <VnLv :value="entity.phone">
-                    <template #label>
-                        {{ t('customer.extendedList.tableVisibleColumns.phone') }}
+                <VnLv :label="t('customer.extendedList.tableVisibleColumns.phone')">
+                    <template #value>
                         <VnLinkPhone :phone-number="entity.phone" />
                     </template>
                 </VnLv>
-                <VnLv :value="entity.mobile">
-                    <template #label>
-                        {{ t('customer.summary.mobile') }}
-                        <VnLinkPhone :phone-number="entity.mobile" />
+                <VnLv :label="t('customer.summary.mobile')">
+                    <template #value>
                         <VnLinkPhone
+                            sip
                             say-simple
                             :phone-number="entity.mobile"
                             :channel="entity.country?.saySimpleCountry?.channel"
-                            class="q-ml-xs"
                         />
                     </template>
                 </VnLv>
-                <VnLv :value="entity.email" copy
-                    ><template #label>
-                        {{ t('globals.params.email') }}
-                        <VnLinkMail email="entity.email"></VnLinkMail> </template
-                ></VnLv>
                 <VnLv
-                    :label="t('customer.summary.salesPerson')"
-                    :value="entity?.salesPersonUser?.name"
+                    :label="t('globals.params.email')"
+                    :value="entity.email"
+                    class="ellipsis"
+                    copy
                 >
                     <template #value>
-                        <VnUserLink
-                            :name="entity.salesPersonUser?.name"
-                            :worker-id="entity.salesPersonFk"
-                        /> </template
-                ></VnLv>
+                        <VnLinkMail :email="entity.email" />
+                    </template>
+                </VnLv>
+                <VnLv :label="t('globals.department')">
+                    <template #value>
+                        <span class="link" v-text="entity.department?.name" />
+                        <DepartmentDescriptorProxy :id="entity?.department?.id" />
+                    </template>
+                </VnLv>
                 <VnLv
                     :label="t('customer.summary.contactChannel')"
                     :value="entity?.contactChannel?.name"
@@ -182,7 +181,7 @@ const sumRisk = ({ clientRisks }) => {
             <QCard class="vn-one">
                 <VnTitle
                     :url="`#/customer/${entityId}/billing-data`"
-                    :text="t('customer.summary.billingData')"
+                    :text="t('customer.summary.payMethodFk')"
                 />
                 <VnLv
                     :label="t('customer.summary.payMethod')"
@@ -290,7 +289,7 @@ const sumRisk = ({ clientRisks }) => {
                 <VnLv
                     v-if="entity.creditInsurance"
                     :label="t('customer.summary.securedCredit')"
-                    :value="toCurrency(entity.creditInsurance)"
+                    :value="`${toCurrency(entity.creditInsurance)} (${entity.classifications[0]?.insurances[0]?.grade || ''})`"
                     :info="t('customer.summary.securedCreditInfo')"
                 />
 
diff --git a/src/pages/Customer/CustomerCreate.vue b/src/pages/Customer/CustomerCreate.vue
deleted file mode 100644
index 79da63283..000000000
--- a/src/pages/Customer/CustomerCreate.vue
+++ /dev/null
@@ -1,146 +0,0 @@
-<script setup>
-import { reactive, ref } from 'vue';
-import { useI18n } from 'vue-i18n';
-
-import FetchData from 'components/FetchData.vue';
-import FormModel from 'components/FormModel.vue';
-import VnRow from 'components/ui/VnRow.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
-import VnLocation from 'src/components/common/VnLocation.vue';
-import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
-
-const { t } = useI18n();
-
-const initialData = reactive({
-    active: true,
-    isEqualizated: false,
-});
-
-const workersOptions = ref([]);
-const businessTypesOptions = ref([]);
-
-function handleLocation(data, location) {
-    const { town, code, provinceFk, countryFk } = location ?? {};
-    data.postcode = code;
-    data.city = town;
-    data.provinceFk = provinceFk;
-    data.countryFk = countryFk;
-}
-</script>
-
-<template>
-    <FetchData
-        @on-fetch="(data) => (workersOptions = data)"
-        auto-load
-        url="Workers/search?departmentCodes"
-    />
-    <FetchData
-        @on-fetch="(data) => (businessTypesOptions = data)"
-        auto-load
-        url="BusinessTypes"
-    />
-    <QPage>
-        <VnSubToolbar />
-        <FormModel
-            :form-initial-data="initialData"
-            model="client"
-            url-create="Clients/createWithUser"
-        >
-            <template #form="{ data, validate }">
-                <VnRow>
-                    <QInput :label="t('Comercial name')" v-model="data.name" />
-                    <VnSelect
-                        :label="t('Salesperson')"
-                        :options="workersOptions"
-                        hide-selected
-                        option-label="name"
-                        option-value="id"
-                        v-model="data.salesPersonFk"
-                    />
-                </VnRow>
-                <VnRow>
-                    <VnSelect
-                        :label="t('Business type')"
-                        :options="businessTypesOptions"
-                        hide-selected
-                        option-label="description"
-                        option-value="code"
-                        v-model="data.businessTypeFk"
-                    />
-                    <QInput v-model="data.fi" :label="t('Tax number')" />
-                </VnRow>
-                <VnRow>
-                    <QInput
-                        :label="t('Business name')"
-                        :rules="validate('client.socialName')"
-                        v-model="data.socialName"
-                    />
-                </VnRow>
-                <VnRow>
-                    <QInput
-                        :label="t('Street')"
-                        :rules="validate('client.street')"
-                        v-model="data.street"
-                    />
-                </VnRow>
-                <VnRow>
-                    <VnLocation
-                        :rules="validate('Worker.postcode')"
-                        :acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
-                        v-model="data.location"
-                        @update:model-value="(location) => handleLocation(data, location)"
-                    >
-                    </VnLocation>
-                </VnRow>
-
-                <VnRow>
-                    <QInput v-model="data.userName" :label="t('Web user')" />
-                    <QInput
-                        :label="t('Email')"
-                        :rules="validate('client.email')"
-                        clearable
-                        type="email"
-                        v-model="data.email"
-                    >
-                        <template #append>
-                            <QIcon name="info" class="cursor-info">
-                                <QTooltip max-width="400px">{{
-                                    t('customer.basicData.youCanSaveMultipleEmails')
-                                }}</QTooltip>
-                            </QIcon>
-                        </template>
-                    </QInput>
-                </VnRow>
-                <QCheckbox
-                    :label="t('Is equalizated')"
-                    v-model="initialData.isEqualizated"
-                />
-            </template>
-        </FormModel>
-    </QPage>
-</template>
-
-<style lang="scss" scoped>
-.card {
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
-    grid-gap: 20px;
-}
-</style>
-
-<i18n>
-es:
-    Comercial name: Nombre comercial
-    Salesperson: Comercial
-    Business type: Tipo de negocio
-    Tax number: NIF / CIF
-    Business name: Razón social
-    Street: Dirección fiscal
-    Postcode: Código postal
-    City: Población
-    Province: Provincia
-    Country: País
-    Web user: Usuario web
-    Email: Email
-    Is equalizated: Recargo de equivalencia
-</i18n>
diff --git a/src/pages/Customer/CustomerFilter.vue b/src/pages/Customer/CustomerFilter.vue
index 1c5a08304..c30b11528 100644
--- a/src/pages/Customer/CustomerFilter.vue
+++ b/src/pages/Customer/CustomerFilter.vue
@@ -3,7 +3,6 @@ import { useI18n } from 'vue-i18n';
 import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
 import VnSelect from 'components/common/VnSelect.vue';
 import VnInput from 'src/components/common/VnInput.vue';
-import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
 
 const { t } = useI18n();
 defineProps({
@@ -42,7 +41,7 @@ const exprBuilder = (param, value) => {
         <template #body="{ params, searchFn }">
             <QItem class="q-my-sm">
                 <QItemSection>
-                    <VnInput :label="t('FI')" v-model="params.fi" is-outlined>
+                    <VnInput :label="t('FI')" v-model="params.fi" filled>
                         <template #prepend>
                             <QIcon name="badge" size="xs" />
                         </template>
@@ -51,7 +50,7 @@ const exprBuilder = (param, value) => {
             </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection>
-                    <VnInput :label="t('Name')" v-model="params.name" is-outlined />
+                    <VnInput :label="t('Name')" v-model="params.name" filled />
                 </QItemSection>
             </QItem>
             <QItem class="q-mb-sm">
@@ -59,28 +58,21 @@ const exprBuilder = (param, value) => {
                     <VnInput
                         :label="t('customer.summary.socialName')"
                         v-model="params.socialName"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection>
-                    <VnSelectWorker
-                        :label="t('Salesperson')"
-                        v-model="params.salesPersonFk"
-                        :params="{
-                            departmentCodes: ['VT'],
-                        }"
-                        :expr-builder="exprBuilder"
-                        @update:model-value="searchFn()"
-                        emit-value
-                        map-options
-                        use-input
-                        hide-selected
+                    <VnSelect
                         dense
-                        outlined
-                        rounded
-                        :input-debounce="0"
+                        filled
+                        :label="t('globals.params.departmentFk')"
+                        v-model="params.departmentFk"
+                        option-value="id"
+                        option-label="name"
+                        url="Departments"
+                        no-one="true"
                     />
                 </QItemSection>
             </QItem>
@@ -97,8 +89,7 @@ const exprBuilder = (param, value) => {
                         map-options
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                         auto-load
                         :input-debounce="0"
                     />
@@ -106,12 +97,12 @@ const exprBuilder = (param, value) => {
             </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection>
-                    <VnInput :label="t('City')" v-model="params.city" is-outlined />
+                    <VnInput :label="t('City')" v-model="params.city" filled />
                 </QItemSection>
             </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection>
-                    <VnInput :label="t('Phone')" v-model="params.phone" is-outlined>
+                    <VnInput :label="t('Phone')" v-model="params.phone" filled>
                         <template #prepend>
                             <QIcon name="phone" size="xs" />
                         </template>
@@ -120,7 +111,7 @@ const exprBuilder = (param, value) => {
             </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection>
-                    <VnInput :label="t('Email')" v-model="params.email" is-outlined>
+                    <VnInput :label="t('Email')" v-model="params.email" filled>
                         <template #prepend>
                             <QIcon name="email" size="sm" />
                         </template>
@@ -140,19 +131,14 @@ const exprBuilder = (param, value) => {
                         map-options
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                         auto-load
                         sortBy="name ASC"
                 /></QItemSection>
             </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection>
-                    <VnInput
-                        :label="t('Postcode')"
-                        v-model="params.postcode"
-                        is-outlined
-                    />
+                    <VnInput :label="t('Postcode')" v-model="params.postcode" filled />
                 </QItemSection>
             </QItem>
         </template>
@@ -164,12 +150,12 @@ en:
     params:
         search: Contains
         fi: FI
-        salesPersonFk: Salesperson
         provinceFk: Province
         isActive: Is active
         city: City
         phone: Phone
         email: Email
+        departmentFk: Department
         isToBeMailed: Mailed
         isEqualizated: Equailized
         businessTypeFk: Business type
@@ -182,6 +168,7 @@ en:
         postcode: Postcode
 es:
     params:
+        departmentFk: Departamento
         search: Contiene
         fi: NIF
         isActive: Activo
@@ -191,7 +178,6 @@ es:
         sageTaxTypeFk: Tipo de impuesto Sage
         sageTransactionTypeFk: Tipo de impuesto Sage
         payMethodFk: Forma de pago
-        salesPersonFk: Comercial
         provinceFk: Provincia
         city: Ciudad
         phone: Teléfono
@@ -201,7 +187,6 @@ es:
         name: Nombre
         postcode: CP
     FI: NIF
-    Salesperson: Comercial
     Province: Provincia
     City: Ciudad
     Phone: Teléfono
diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue
index 0bfca7910..b721a6ad9 100644
--- a/src/pages/Customer/CustomerList.vue
+++ b/src/pages/Customer/CustomerList.vue
@@ -10,7 +10,6 @@ import CustomerFilter from './CustomerFilter.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import VnLocation from 'src/components/common/VnLocation.vue';
 import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
-import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
 import VnSection from 'src/components/common/VnSection.vue';
 
 const { t } = useI18n();
@@ -73,30 +72,17 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        name: 'salesPersonFk',
-        label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
         component: 'select',
         attrs: {
-            url: 'Workers/activeWithInheritedRole',
-            fields: ['id', 'name', 'firstName'],
-            where: { role: 'salesPerson' },
-            optionFilter: 'firstName',
+            url: 'Departments',
         },
-        columnFilter: {
-            component: 'select',
-            attrs: {
-                url: 'Workers/activeWithInheritedRole',
-                fields: ['id', 'name', 'firstName'],
-                where: { role: 'salesPerson' },
-                optionLabel: 'firstName',
-                optionValue: 'id',
-            },
-        },
-        create: false,
+        create: true,
         columnField: {
             component: null,
         },
-        format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson),
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
     {
         align: 'left',
@@ -155,6 +141,9 @@ const columns = computed(() => [
             inWhere: true,
         },
         columnClass: 'expand',
+        attrs: {
+            uppercase: true,
+        },
     },
     {
         align: 'left',
@@ -446,36 +435,6 @@ function handleLocation(data, location) {
                 redirect="customer"
             >
                 <template #more-create-dialog="{ data }">
-                    <VnSelectWorker
-                        :label="t('customer.summary.salesPerson')"
-                        v-model="data.salesPersonFk"
-                        :params="{
-                            departmentCodes: ['VT', 'shopping'],
-                        }"
-                        :has-avatar="true"
-                        :id-value="data.salesPersonFk"
-                        emit-value
-                        auto-load
-                    >
-                        <template #prepend>
-                            <VnAvatar
-                                :worker-id="data.salesPersonFk"
-                                color="primary"
-                                :title="title"
-                            />
-                        </template>
-                        <template #option="scope">
-                            <QItem v-bind="scope.itemProps">
-                                <QItemSection>
-                                    <QItemLabel>{{ scope.opt?.name }}</QItemLabel>
-                                    <QItemLabel caption
-                                        >{{ scope.opt?.nickname }},
-                                        {{ scope.opt?.code }}</QItemLabel
-                                    >
-                                </QItemSection>
-                            </QItem>
-                        </template>
-                    </VnSelectWorker>
                     <VnLocation
                         :acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
                         v-model="data.location"
diff --git a/src/pages/Customer/Defaulter/CustomerDefaulter.vue b/src/pages/Customer/Defaulter/CustomerDefaulter.vue
index dc4ac9162..296ad1eb4 100644
--- a/src/pages/Customer/Defaulter/CustomerDefaulter.vue
+++ b/src/pages/Customer/Defaulter/CustomerDefaulter.vue
@@ -32,28 +32,6 @@ const columns = computed(() => [
             },
         },
     },
-    {
-        align: 'left',
-        name: 'isWorker',
-        label: t('Is worker'),
-    },
-    {
-        align: 'left',
-        name: 'salesPersonFk',
-        label: t('Salesperson'),
-        columnFilter: {
-            component: 'select',
-            attrs: {
-                url: 'Workers/activeWithInheritedRole',
-                fields: ['id', 'name'],
-                where: { role: 'salesPerson' },
-                useLike: false,
-                optionValue: 'id',
-                optionLabel: 'name',
-                optionFilter: 'firstName',
-            },
-        },
-    },
     {
         align: 'left',
         name: 'departmentFk',
@@ -153,6 +131,11 @@ const columns = computed(() => [
         label: t('Has recovery'),
         name: 'hasRecovery',
     },
+    {
+        align: 'left',
+        name: 'isWorker',
+        label: t('customer.params.isWorker'),
+    },
 ]);
 
 const viewAddObservation = (rowsSelected) => {
@@ -167,7 +150,6 @@ const viewAddObservation = (rowsSelected) => {
 
 function exprBuilder(param, value) {
     switch (param) {
-        case 'salesPersonFk':
         case 'creditInsurance':
         case 'countryFk':
             return { [`c.${param}`]: value };
@@ -176,7 +158,7 @@ function exprBuilder(param, value) {
         case 'workerFk':
             return { [`co.${param}`]: value };
         case 'departmentFk':
-            return { [`wd.${param}`]: value };
+            return { [`c.${param}`]: value };
         case 'amount':
         case 'clientFk':
             return { [`d.${param}`]: value };
@@ -241,12 +223,6 @@ function exprBuilder(param, value) {
         <template #column-observation="{ row }">
             <VnInput type="textarea" v-model="row.observation" readonly dense rows="2" />
         </template>
-        <template #column-salesPersonFk="{ row }">
-            <span class="link" @click.stop>
-                {{ row.salesPersonName }}
-                <WorkerDescriptorProxy :id="row.salesPersonFk" />
-            </span>
-        </template>
         <template #column-departmentFk="{ row }">
             <span class="link" @click.stop>
                 {{ row.departmentName }}
@@ -265,8 +241,6 @@ function exprBuilder(param, value) {
 es:
     Add observation:  Añadir observación
     Client: Cliente
-    Is worker: Es trabajador
-    Salesperson: Comercial
     Department: Departamento
     Country: País
     P. Method: F. Pago
@@ -281,5 +255,5 @@ es:
     Credit I.: Crédito A.
     Credit insurance: Crédito asegurado
     From: Desde
-    Has recovery: Tiene recobro
+    Has recovery: Recobro
 </i18n>
diff --git a/src/pages/Customer/Defaulter/CustomerDefaulterFilter.vue b/src/pages/Customer/Defaulter/CustomerDefaulterFilter.vue
index ce86c6435..f7d4163d1 100644
--- a/src/pages/Customer/Defaulter/CustomerDefaulterFilter.vue
+++ b/src/pages/Customer/Defaulter/CustomerDefaulterFilter.vue
@@ -15,19 +15,12 @@ const props = defineProps({
     },
 });
 
-const salespersons = ref();
 const countries = ref();
 const authors = ref();
 const departments = ref();
 </script>
 
 <template>
-    <FetchData
-        :filter="{ where: { role: 'salesPerson' } }"
-        @on-fetch="(data) => (salespersons = data)"
-        auto-load
-        url="Workers/activeWithInheritedRole"
-    />
     <FetchData @on-fetch="(data) => (countries = data)" auto-load url="Countries" />
     <FetchData
         @on-fetch="(data) => (authors = data)"
@@ -52,8 +45,7 @@ const departments = ref();
                     dense
                     option-label="name"
                     option-value="id"
-                    outlined
-                    rounded
+                    filled
                     emit-value
                     hide-selected
                     map-options
@@ -62,29 +54,6 @@ const departments = ref();
                     @update:model-value="searchFn()"
                 />
             </QItem>
-            <QItem class="q-mb-sm">
-                <QItemSection v-if="salespersons">
-                    <VnSelect
-                        :input-debounce="0"
-                        :label="t('Salesperson')"
-                        :options="salespersons"
-                        dense
-                        emit-value
-                        hide-selected
-                        map-options
-                        option-label="name"
-                        option-value="id"
-                        outlined
-                        rounded
-                        use-input
-                        v-model="params.salesPersonFk"
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-                <QItemSection v-else>
-                    <QSkeleton class="full-width" type="QInput" />
-                </QItemSection>
-            </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection v-if="departments">
                     <VnSelect
@@ -97,8 +66,7 @@ const departments = ref();
                         map-options
                         option-label="name"
                         option-value="id"
-                        outlined
-                        rounded
+                        filled
                         use-input
                         v-model="params.departmentFk"
                         @update:model-value="searchFn()"
@@ -121,8 +89,7 @@ const departments = ref();
                         map-options
                         option-label="name"
                         option-value="id"
-                        outlined
-                        rounded
+                        filled
                         use-input
                         v-model="params.countryFk"
                         @update:model-value="searchFn()"
@@ -138,7 +105,7 @@ const departments = ref();
                     <VnInput
                         :label="t('P. Method')"
                         clearable
-                        is-outlined
+                        filled
                         v-model="params.paymentMethod"
                     />
                 </QItemSection>
@@ -149,7 +116,7 @@ const departments = ref();
                     <VnInput
                         :label="t('Balance D.')"
                         clearable
-                        is-outlined
+                        filled
                         v-model="params.balance"
                     />
                 </QItemSection>
@@ -167,8 +134,7 @@ const departments = ref();
                         map-options
                         option-label="name"
                         option-value="id"
-                        outlined
-                        rounded
+                        filled
                         use-input
                         v-model="params.workerFk"
                         @update:model-value="searchFn()"
@@ -184,7 +150,7 @@ const departments = ref();
                     <VnInputDate
                         :label="t('L. O. Date')"
                         clearable
-                        is-outlined
+                        filled
                         v-model="params.date"
                     />
                 </QItemSection>
@@ -195,7 +161,7 @@ const departments = ref();
                     <VnInput
                         :label="t('Credit I.')"
                         clearable
-                        is-outlined
+                        filled
                         v-model="params.credit"
                     />
                 </QItemSection>
@@ -205,7 +171,7 @@ const departments = ref();
                 <QItemSection>
                     <VnInputDate
                         :label="t('From')"
-                        is-outlined
+                        filled
                         v-model="params.defaulterSinced"
                     />
                 </QItemSection>
@@ -219,7 +185,6 @@ const departments = ref();
 en:
     params:
         clientFk: Client
-        salesPersonFk: Salesperson
         countryFk: Country
         paymentMethod: P. Method
         balance: Balance D.
@@ -227,10 +192,11 @@ en:
         date: L. O. Date
         credit: Credit I.
         defaulterSinced: From
+        departmentFk: Department
 es:
     params:
+        departmentFk: Departamento
         clientFk: Cliente
-        salesPersonFk: Comercial
         countryFk: País
         paymentMethod: F. Pago
         balance: Saldo V.
@@ -239,7 +205,6 @@ es:
         credit: Crédito A.
         defaulterSinced: Desde
     Client: Cliente
-    Salesperson: Comercial
     Departments: Departamentos
     Country: País
     P. Method: F. Pago
diff --git a/src/pages/Customer/Notifications/CustomerNotifications.vue b/src/pages/Customer/Notifications/CustomerNotifications.vue
index ce18739b4..cbbd6d205 100644
--- a/src/pages/Customer/Notifications/CustomerNotifications.vue
+++ b/src/pages/Customer/Notifications/CustomerNotifications.vue
@@ -69,17 +69,16 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
-        name: 'salesPersonFk',
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
         component: 'select',
         attrs: {
-            url: 'Workers/activeWithInheritedRole',
-            fields: ['id', 'name'],
-            where: { role: 'salesPerson' },
-            optionFilter: 'firstName',
-            useLike: false,
+            url: 'Departments',
         },
-        visible: false,
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
 ]);
 </script>
@@ -96,7 +95,7 @@ const columns = computed(() => [
     </VnSubToolbar>
     <VnTable
         :data-key="dataKey"
-        url="Clients"
+        url="Clients/filter"
         :table="{
             'row-key': 'id',
             selection: 'multiple',
@@ -127,8 +126,8 @@ const columns = computed(() => [
 es:
     Identifier: Identificador
     Social name: Razón social
-    Salesperson: Comercial
     Phone: Teléfono
+    Postcode: Código postal
     City: Población
     Email: Email
     Campaign consumption: Consumo campaña
diff --git a/src/pages/Customer/Payments/CustomerPaymentsFilter.vue b/src/pages/Customer/Payments/CustomerPaymentsFilter.vue
index 8982cba5a..ec20237b4 100644
--- a/src/pages/Customer/Payments/CustomerPaymentsFilter.vue
+++ b/src/pages/Customer/Payments/CustomerPaymentsFilter.vue
@@ -25,7 +25,7 @@ const props = defineProps({
         <template #body="{ params }">
             <QItem>
                 <QItemSection>
-                    <VnInput :label="t('Order ID')" v-model="params.orderFk" is-outlined>
+                    <VnInput :label="t('Order ID')" v-model="params.orderFk" filled>
                         <template #prepend>
                             <QIcon name="vn:basket" size="xs" />
                         </template>
@@ -34,11 +34,7 @@ const props = defineProps({
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        :label="t('Customer ID')"
-                        v-model="params.clientFk"
-                        is-outlined
-                    >
+                    <VnInput :label="t('Customer ID')" v-model="params.clientFk" filled>
                         <template #prepend>
                             <QIcon name="vn:client" size="xs" />
                         </template>
@@ -47,19 +43,15 @@ const props = defineProps({
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInputNumber
-                        :label="t('Amount')"
-                        v-model="params.amount"
-                        is-outlined
-                    />
+                    <VnInputNumber :label="t('Amount')" v-model="params.amount" filled />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInputDate v-model="params.from" :label="t('From')" is-outlined />
+                    <VnInputDate v-model="params.from" :label="t('From')" filled />
                 </QItemSection>
                 <QItemSection>
-                    <VnInputDate v-model="params.to" :label="t('To')" is-outlined />
+                    <VnInputDate v-model="params.to" :label="t('To')" filled />
                 </QItemSection>
             </QItem>
         </template>
diff --git a/src/pages/Customer/Payments/__tests__/CustomerPayments.spec.js b/src/pages/Customer/Payments/__tests__/CustomerPayments.spec.js
index 0b1457ece..238545050 100644
--- a/src/pages/Customer/Payments/__tests__/CustomerPayments.spec.js
+++ b/src/pages/Customer/Payments/__tests__/CustomerPayments.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import CustomerPayments from 'src/pages/Customer/Payments/CustomerPayments.vue';
 
 describe('CustomerPayments', () => {
diff --git a/src/pages/Customer/components/CustomerAddressEdit.vue b/src/pages/Customer/components/CustomerAddressEdit.vue
index f852c160a..bc76f5985 100644
--- a/src/pages/Customer/components/CustomerAddressEdit.vue
+++ b/src/pages/Customer/components/CustomerAddressEdit.vue
@@ -93,10 +93,26 @@ const updateAddressTicket = async () => {
 };
 
 const updateObservations = async (payload) => {
-    await axios.post('AddressObservations/crud', payload);
+    await axios.post('AddressObservations/crud', cleanPayload(payload));
     notes.value = [];
     deletes.value = [];
 };
+
+function cleanPayload(payload) {
+    ['creates', 'deletes', 'updates'].forEach((prop) => {
+        if (prop === 'creates' || prop === 'updates') {
+            payload[prop] = payload[prop].filter(
+                (item) => item.description !== '' && item.observationTypeFk !== '',
+            );
+        } else {
+            payload[prop] = payload[prop].filter(
+                (item) => item !== null && item !== undefined,
+            );
+        }
+    });
+    return payload;
+}
+
 async function updateAll({ data, payload }) {
     await updateObservations(payload);
     await updateAddress(data);
diff --git a/src/pages/Customer/components/CustomerNewPayment.vue b/src/pages/Customer/components/CustomerNewPayment.vue
index 6ecccc544..fb3804d55 100644
--- a/src/pages/Customer/components/CustomerNewPayment.vue
+++ b/src/pages/Customer/components/CustomerNewPayment.vue
@@ -3,18 +3,20 @@ import { onBeforeMount, reactive, ref } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
 import axios from 'axios';
-import { getClientRisk } from '../composables/getClientRisk';
 import { useDialogPluginComponent } from 'quasar';
 
+import { getClientRisk } from '../composables/getClientRisk';
 import { usePrintService } from 'composables/usePrintService';
 import useNotify from 'src/composables/useNotify.js';
+
+import FormModelPopup from 'components/FormModelPopup.vue';
 import FetchData from 'components/FetchData.vue';
-import FormModel from 'components/FormModel.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import VnInputDate from 'components/common/VnInputDate.vue';
 import VnInputNumber from 'components/common/VnInputNumber.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnInput from 'src/components/common/VnInput.vue';
+import VnAccountNumber from 'src/components/common/VnAccountNumber.vue';
 
 const { t } = useI18n();
 const route = useRoute();
@@ -48,7 +50,7 @@ const maxAmount = ref();
 const accountingType = ref({});
 const isCash = ref(false);
 const formModelRef = ref(false);
-
+const amountToReturn = ref();
 const filterBanks = {
     fields: ['id', 'bank', 'accountingTypeFk'],
     include: { relation: 'accountingType' },
@@ -74,26 +76,24 @@ onBeforeMount(() => {
     urlCreate.value = `Clients/${route.params.id}/createReceipt`;
 });
 
-function setPaymentType(accounting) {
+function setPaymentType(data, accounting) {
+    data.bankFk = accounting.id;
     if (!accounting) return;
     accountingType.value = accounting.accountingType;
-    initialData.description = [];
-    initialData.payed = Date.vnNew();
+    data.description = [];
+    data.payed = Date.vnNew();
     isCash.value = accountingType.value.code == 'cash';
     viewReceipt.value = isCash.value;
     if (accountingType.value.daysInFuture)
-        initialData.payed.setDate(
-            initialData.payed.getDate() + accountingType.value.daysInFuture,
-        );
+        data.payed.setDate(data.payed.getDate() + accountingType.value.daysInFuture);
     maxAmount.value = accountingType.value && accountingType.value.maxAmount;
-    if (accountingType.value.code == 'compensation')
-        return (initialData.description = '');
+    if (accountingType.value.code == 'compensation') return (data.description = '');
 
     let descriptions = [];
     if (accountingType.value.receiptDescription)
         descriptions.push(accountingType.value.receiptDescription);
-    if (initialData.description) descriptions.push(initialData.description);
-    initialData.description = descriptions.join(', ');
+    if (data.description > 0) descriptions.push(data.description);
+    data.description = descriptions.join(', ');
 }
 
 const calculateFromAmount = (event) => {
@@ -102,7 +102,7 @@ const calculateFromAmount = (event) => {
 };
 
 const calculateFromDeliveredAmount = (event) => {
-    initialData.amountToReturn = parseFloat(event) - initialData.amountPaid;
+    amountToReturn.value = event - initialData.amountPaid;
 };
 
 function onBeforeSave(data) {
@@ -113,7 +113,6 @@ function onBeforeSave(data) {
     if (isCash.value && shouldSendEmail.value && !data.email)
         return notify(t('There is no assigned email for this client'), 'negative');
 
-    data.bankFk = data.bankFk?.id;
     return data;
 }
 
@@ -124,17 +123,16 @@ async function onDataSaved(formData, { id }) {
                 recipient: formData.email,
             });
 
-        if (viewReceipt.value) openReport(`Receipts/${id}/receipt-pdf`);
+        if (viewReceipt.value) openReport(`Receipts/${id}/receipt-pdf`, {}, '_blank');
     } finally {
         if ($props.promise) $props.promise();
         if (closeButton.value) closeButton.value.click();
     }
 }
 
-async function accountShortToStandard({ target: { value } }) {
+async function getSupplierClientReferences(value) {
     if (!value) return (initialData.description = '');
-    initialData.compensationAccount = value.replace('.', '0'.repeat(11 - value.length));
-    const params = { bankAccount: initialData.compensationAccount };
+    const params = { bankAccount: value };
     const { data } = await axios(`Clients/getClientOrSupplierReference`, { params });
     if (!data.clientId) {
         initialData.description = t('Supplier Compensation Reference', {
@@ -181,42 +179,19 @@ async function getAmountPaid() {
             auto-load
             url="Clients/findOne"
         />
-        <FormModel
+        <FormModelPopup
             ref="formModelRef"
             :form-initial-data="initialData"
-            :observe-form-changes="false"
             :url-create="urlCreate"
             :mapper="onBeforeSave"
             @on-data-saved="onDataSaved"
-            prevent-submit
+            :prevent-submit="true"
         >
-            <template #form="{ data, validate }">
-                <span ref="closeButton" class="row justify-end close-icon" v-close-popup>
-                    <QIcon name="close" size="sm" />
-                </span>
-
+            <template #form-inputs="{ data, validate }">
                 <h5 class="q-mt-none">{{ t('New payment') }}</h5>
-
-                <VnRow>
-                    <VnInputDate
-                        :label="t('Date')"
-                        :required="true"
-                        v-model="data.payed"
-                    />
-                    <VnSelect
-                        :label="t('Company')"
-                        :options="companyOptions"
-                        :required="true"
-                        :rules="validate('entry.companyFk')"
-                        hide-selected
-                        option-label="code"
-                        option-value="id"
-                        v-model="data.companyFk"
-                        @update:model-value="getAmountPaid()"
-                    />
-                </VnRow>
                 <VnRow>
                     <VnSelect
+                        autofocus
                         :label="t('Bank')"
                         v-model="data.bankFk"
                         url="Accountings"
@@ -225,9 +200,10 @@ async function getAmountPaid() {
                         sort-by="id"
                         :limit="0"
                         @update:model-value="
-                            (value, options) => setPaymentType(value, options)
+                            (value, options) => setPaymentType(data, value, options)
                         "
                         :emit-value="false"
+                        data-cy="paymentBank"
                     >
                         <template #option="scope">
                             <QItem v-bind="scope.itemProps">
@@ -245,18 +221,37 @@ async function getAmountPaid() {
                         @update:model-value="calculateFromAmount($event)"
                         clearable
                         v-model.number="data.amountPaid"
+                        data-cy="paymentAmount"
                     />
                 </VnRow>
-                <div v-if="data.bankFk?.accountingType?.code == 'compensation'">
+                <VnRow>
+                    <VnInputDate
+                        :label="t('Date')"
+                        v-model="data.payed"
+                        :required="true"
+                    />
+                    <VnSelect
+                        :label="t('Company')"
+                        :options="companyOptions"
+                        :required="true"
+                        :rules="validate('entry.companyFk')"
+                        hide-selected
+                        option-label="code"
+                        option-value="id"
+                        v-model="data.companyFk"
+                        @update:model-value="getAmountPaid()"
+                    />
+                </VnRow>
+                <div v-if="accountingType.code == 'compensation'">
                     <div class="text-h6">
                         {{ t('Compensation') }}
                     </div>
                     <VnRow>
-                        <VnInputNumber
+                        <VnAccountNumber
                             :label="t('Compensation account')"
                             clearable
                             v-model="data.compensationAccount"
-                            @blur="accountShortToStandard"
+                            @blur="getSupplierClientReferences(data.compensationAccount)"
                         />
                     </VnRow>
                 </div>
@@ -266,8 +261,7 @@ async function getAmountPaid() {
                     clearable
                     v-model="data.description"
                 />
-
-                <div v-if="data.bankFk?.accountingType?.code == 'cash'">
+                <div v-if="accountingType.code == 'cash'">
                     <div class="text-h6">{{ t('Cash') }}</div>
                     <VnRow>
                         <VnInputNumber
@@ -279,7 +273,7 @@ async function getAmountPaid() {
                         <VnInputNumber
                             :label="t('Amount to return')"
                             disable
-                            v-model="data.amountToReturn"
+                            v-model="amountToReturn"
                         />
                     </VnRow>
                     <VnRow>
@@ -287,27 +281,8 @@ async function getAmountPaid() {
                         <QCheckbox v-model="shouldSendEmail" :label="t('Send email')" />
                     </VnRow>
                 </div>
-                <div class="q-mt-lg row justify-end">
-                    <QBtn
-                        :disabled="formModelRef.isLoading"
-                        :label="t('globals.cancel')"
-                        :loading="formModelRef.isLoading"
-                        class="q-ml-sm"
-                        color="primary"
-                        flat
-                        type="reset"
-                        v-close-popup
-                    />
-                    <QBtn
-                        :disabled="formModelRef.isLoading"
-                        :label="t('globals.save')"
-                        :loading="formModelRef.isLoading"
-                        color="primary"
-                        @click="formModelRef.save()"
-                    />
-                </div>
             </template>
-        </FormModel>
+        </FormModelPopup>
     </QDialog>
 </template>
 
diff --git a/src/pages/Customer/components/CustomerSummaryTable.vue b/src/pages/Customer/components/CustomerSummaryTable.vue
index 09c7e714c..feb137065 100644
--- a/src/pages/Customer/components/CustomerSummaryTable.vue
+++ b/src/pages/Customer/components/CustomerSummaryTable.vue
@@ -191,7 +191,7 @@ const getItemPackagingType = (ticketSales) => {
         :without-header="true"
         auto-load
         :row-click="rowClick"
-        order="shipped DESC, id"
+        order="shipped DESC, id DESC"
         :disable-option="{ card: true, table: true }"
         class="full-width"
         :disable-infinite-scroll="true"
diff --git a/src/pages/Customer/locale/en.yml b/src/pages/Customer/locale/en.yml
index b6d495335..6724a5a7b 100644
--- a/src/pages/Customer/locale/en.yml
+++ b/src/pages/Customer/locale/en.yml
@@ -20,7 +20,7 @@ customer:
         name: Name
         contact: Contact
         mobile: Mobile
-        salesPerson: Sales person
+        team: Team
         contactChannel: Contact channel
         socialName: Social name
         fiscalId: Fiscal ID
@@ -78,7 +78,6 @@ customer:
             id: Identifier
             socialName: Social name
             fi: Tax number
-            salesPersonFk: Salesperson
             creditInsurance: Credit insurance
             phone: Phone
             street: Street
diff --git a/src/pages/Customer/locale/es.yml b/src/pages/Customer/locale/es.yml
index f50d049da..4a266e07a 100644
--- a/src/pages/Customer/locale/es.yml
+++ b/src/pages/Customer/locale/es.yml
@@ -20,7 +20,7 @@ customer:
         name: Nombre
         contact: Contacto
         mobile: Móvil
-        salesPerson: Comercial
+        team: Equipo
         contactChannel: Canal de contacto
         socialName: Razón social
         fiscalId: NIF/CIF
@@ -78,7 +78,6 @@ customer:
             id: Identificador
             socialName: Razón social
             fi: NIF / CIF
-            salesPersonFk: Comercial
             creditInsurance: Crédito asegurado
             phone: Teléfono
             street: Dirección fiscal
diff --git a/src/pages/Entry/Card/EntryBasicData.vue b/src/pages/Entry/Card/EntryBasicData.vue
index 6462ed24a..f6d15a977 100644
--- a/src/pages/Entry/Card/EntryBasicData.vue
+++ b/src/pages/Entry/Card/EntryBasicData.vue
@@ -13,6 +13,9 @@ import VnSelect from 'src/components/common/VnSelect.vue';
 import VnInputNumber from 'src/components/common/VnInputNumber.vue';
 import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
 import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
+import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
+import VnDmsInput from 'src/components/common/VnDmsInput.vue';
 
 const route = useRoute();
 const { t } = useI18n();
@@ -23,6 +26,7 @@ const user = state.getUser().fn();
 
 const companiesOptions = ref([]);
 const currenciesOptions = ref([]);
+const entryRef = ref({});
 
 onMounted(() => {
     checkEntryLock(route.params.id, user.id);
@@ -47,13 +51,14 @@ onMounted(() => {
         auto-load
     />
     <FormModel
-        :url-update="`Entries/${route.params.id}`"
+        ref="entryRef"
         model="Entry"
-        auto-load
+        :url-update="`Entries/${route.params.id}`"
         :clear-store-on-unmount="false"
+        auto-load
     >
         <template #form="{ data }">
-            <VnRow>
+            <VnRow class="q-py-sm">
                 <VnSelectTravelExtended
                     :data="data"
                     v-model="data.travelFk"
@@ -65,15 +70,22 @@ onMounted(() => {
                     :required="true"
                 />
             </VnRow>
-            <VnRow>
-                <VnInput v-model="data.reference" :label="t('globals.reference')" />
-                <VnInputNumber
-                    v-model="data.invoiceAmount"
-                    :label="t('entry.summary.invoiceAmount')"
-                    :positive="false"
+            <VnRow class="q-py-sm">
+                <VnInput
+                    v-model="data.reference"
+                    :label="t('entry.list.tableVisibleColumns.reference')"
+                />
+                <VnSelect
+                    v-model="data.typeFk"
+                    url="entryTypes"
+                    :fields="['code', 'description']"
+                    option-value="code"
+                    optionLabel="description"
+                    sortBy="description"
+                    :label="t('entry.list.tableVisibleColumns.entryTypeDescription')"
                 />
             </VnRow>
-            <VnRow>
+            <VnRow class="q-py-sm">
                 <VnInput
                     v-model="data.invoiceNumber"
                     :label="t('entry.summary.invoiceNumber')"
@@ -84,12 +96,13 @@ onMounted(() => {
                     :options="companiesOptions"
                     option-value="id"
                     option-label="code"
+                    sort-by="code"
                     map-options
                     hide-selected
                     :required="true"
                 />
             </VnRow>
-            <VnRow>
+            <VnRow class="q-py-sm">
                 <VnInputNumber
                     :label="t('entry.summary.commission')"
                     v-model="data.commission"
@@ -102,15 +115,15 @@ onMounted(() => {
                     :options="currenciesOptions"
                     option-value="id"
                     option-label="code"
+                    sort-by="code"
                 />
             </VnRow>
-            <VnRow>
+            <VnRow class="q-py-sm">
                 <VnInputNumber
                     v-model="data.initialTemperature"
                     name="initialTemperature"
                     :label="t('entry.basicData.initialTemperature')"
                     :step="0.5"
-                    :decimal-places="2"
                     :positive="false"
                 />
                 <VnInputNumber
@@ -118,12 +131,21 @@ onMounted(() => {
                     name="finalTemperature"
                     :label="t('entry.basicData.finalTemperature')"
                     :step="0.5"
-                    :decimal-places="2"
                     :positive="false"
                 />
             </VnRow>
-            <VnRow>
-                <QInput
+            <VnRow class="q-py-sm">
+                <VnInputNumber
+                    v-model="data.invoiceAmount"
+                    :label="t('entry.list.tableVisibleColumns.invoiceAmount')"
+                    :positive="false"
+                    @update:model-value="data.buyerFk = user.id"
+                />
+                <VnSelectWorker v-model="data.buyerFk" hide-selected />
+                <VnDmsInput :data="data" :formRef="entryRef" :disable="false" />
+            </VnRow>
+            <VnRow class="q-py-sm">
+                <VnInputNumber
                     :label="t('entry.basicData.observation')"
                     type="textarea"
                     v-model="data.observation"
@@ -132,14 +154,20 @@ onMounted(() => {
                     fill-input
                 />
             </VnRow>
-            <VnRow>
-                <QCheckbox v-model="data.isOrdered" :label="t('entry.summary.ordered')" />
-                <QCheckbox v-model="data.isConfirmed" :label="t('globals.confirmed')" />
-                <QCheckbox
-                    v-model="data.isExcludedFromAvailable"
-                    :label="t('entry.summary.excludedFromAvailable')"
+            <VnRow class="q-py-sm">
+                <VnCheckbox
+                    v-model="data.isOrdered"
+                    :label="t('entry.list.tableVisibleColumns.isOrdered')"
                 />
-                <QCheckbox
+                <VnCheckbox
+                    v-model="data.isConfirmed"
+                    :label="t('entry.list.tableVisibleColumns.isConfirmed')"
+                />
+                <VnCheckbox
+                    v-model="data.isExcludedFromAvailable"
+                    :label="t('entry.list.tableVisibleColumns.isExcludedFromAvailable')"
+                />
+                <VnCheckbox
                     :disable="!isAdministrative()"
                     v-model="data.isBooked"
                     :label="t('entry.basicData.booked')"
diff --git a/src/pages/Entry/Card/EntryBuys.vue b/src/pages/Entry/Card/EntryBuys.vue
index 684ed5f59..b4c71ff2a 100644
--- a/src/pages/Entry/Card/EntryBuys.vue
+++ b/src/pages/Entry/Card/EntryBuys.vue
@@ -2,7 +2,7 @@
 import { useStateStore } from 'stores/useStateStore';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import { onMounted, ref } from 'vue';
+import { onMounted, ref, computed } from 'vue';
 
 import { useState } from 'src/composables/useState';
 
@@ -16,6 +16,10 @@ import ItemDescriptor from 'src/pages/Item/Card/ItemDescriptor.vue';
 import axios from 'axios';
 import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
 import { checkEntryLock } from 'src/composables/checkEntryLock';
+import VnRow from 'src/components/ui/VnRow.vue';
+import VnInput from 'src/components/common/VnInput.vue';
+import VnInputNumber from 'src/components/common/VnInputNumber.vue';
+import { beforeSave } from 'src/composables/updateMinPriceBeforeSave';
 
 const $props = defineProps({
     id: {
@@ -42,6 +46,8 @@ const entityId = ref($props.id ?? route.params.id);
 const entryBuysRef = ref();
 const footerFetchDataRef = ref();
 const footer = ref({});
+const dialogRef = ref(false);
+const newEntryRef = ref(null);
 const columns = [
     {
         align: 'center',
@@ -57,31 +63,6 @@ const columns = [
         createOrder: 12,
         width: '25px',
     },
-    {
-        label: t('Buyer'),
-        name: 'workerFk',
-        component: 'select',
-        attrs: {
-            url: 'TicketRequests/getItemTypeWorker',
-            fields: ['id', 'nickname'],
-            optionLabel: 'nickname',
-            sortBy: 'nickname ASC',
-            optionValue: 'id',
-        },
-        visible: false,
-    },
-    {
-        label: t('Family'),
-        name: 'itemTypeFk',
-        component: 'select',
-        attrs: {
-            url: 'itemTypes',
-            fields: ['id', 'name'],
-            optionLabel: 'name',
-            optionValue: 'id',
-        },
-        visible: false,
-    },
     {
         name: 'id',
         isId: true,
@@ -111,16 +92,10 @@ const columns = [
         },
     },
     {
-        align: 'center',
+        align: 'left',
         label: t('Article'),
+        component: 'input',
         name: 'name',
-        component: 'select',
-        attrs: {
-            url: 'Items',
-            fields: ['id', 'name'],
-            optionLabel: 'name',
-            optionValue: 'id',
-        },
         width: '85px',
         isEditable: false,
     },
@@ -212,7 +187,6 @@ const columns = [
         },
     },
     {
-        align: 'center',
         labelAbbreviation: 'GM',
         label: t('Grouping selector'),
         toolTip: t('Grouping selector'),
@@ -240,7 +214,6 @@ const columns = [
         },
     },
     {
-        align: 'center',
         labelAbbreviation: 'G',
         label: 'Grouping',
         toolTip: 'Grouping',
@@ -281,6 +254,7 @@ const columns = [
         component: 'number',
         attrs: {
             positive: false,
+            decimalPlaces: 3,
         },
         cellEvent: {
             'update:modelValue': async (value, oldValue, row) => {
@@ -294,7 +268,7 @@ const columns = [
         align: 'center',
         label: t('Amount'),
         name: 'amount',
-        width: '45px',
+        width: '75px',
         component: 'number',
         attrs: {
             positive: false,
@@ -310,7 +284,9 @@ const columns = [
         toolTip: t('Package'),
         name: 'price2',
         component: 'number',
-        createDisable: true,
+        createAttrs: {
+            disable: true,
+        },
         width: '35px',
         create: true,
         format: (row) => parseFloat(row['price2']).toFixed(2),
@@ -320,7 +296,9 @@ const columns = [
         label: t('Box'),
         name: 'price3',
         component: 'number',
-        createDisable: true,
+        createAttrs: {
+            disable: true,
+        },
         cellEvent: {
             'update:modelValue': async (value, oldValue, row) => {
                 row['price2'] = row['price2'] * (value / oldValue);
@@ -340,13 +318,6 @@ const columns = [
             toggleIndeterminate: false,
         },
         component: 'checkbox',
-        cellEvent: {
-            'update:modelValue': async (value, oldValue, row) => {
-                await axios.patch(`Items/${row['itemFk']}`, {
-                    hasMinPrice: value,
-                });
-            },
-        },
         width: '25px',
     },
     {
@@ -356,13 +327,6 @@ const columns = [
         toolTip: t('Minimum price'),
         name: 'minPrice',
         component: 'number',
-        cellEvent: {
-            'update:modelValue': async (value, oldValue, row) => {
-                await axios.patch(`Items/${row['itemFk']}`, {
-                    minPrice: value,
-                });
-            },
-        },
         width: '35px',
         style: (row) => {
             if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
@@ -425,6 +389,23 @@ const columns = [
         },
     },
 ];
+const buyerFk = ref(null);
+const itemTypeFk = ref(null);
+const inkFk = ref(null);
+const tag1 = ref(null);
+const tag2 = ref(null);
+const tag1Filter = ref(null);
+const tag2Filter = ref(null);
+const filter = computed(() => {
+    const where = {};
+    where.workerFk = buyerFk.value;
+    where.itemTypeFk = itemTypeFk.value;
+    where.inkFk = inkFk.value;
+    where.tag1 = tag1.value;
+    where.tag2 = tag2.value;
+
+    return { where };
+});
 
 function getQuantityStyle(row) {
     if (row?.quantity !== row?.stickers * row?.packing)
@@ -435,56 +416,6 @@ function getAmountStyle(row) {
     return { color: 'var(--vn-label-color)' };
 }
 
-async function beforeSave(data, getChanges) {
-    try {
-        const changes = data.updates;
-        if (!changes) return data;
-        const patchPromises = [];
-
-        for (const change of changes) {
-            let patchData = {};
-
-            if ('hasMinPrice' in change.data) {
-                patchData.hasMinPrice = change.data?.hasMinPrice;
-                delete change.data.hasMinPrice;
-            }
-            if ('minPrice' in change.data) {
-                patchData.minPrice = change.data?.minPrice;
-                delete change.data.minPrice;
-            }
-
-            if (Object.keys(patchData).length > 0) {
-                const promise = axios
-                    .get('Buys/findOne', {
-                        params: {
-                            filter: {
-                                fields: ['itemFk'],
-                                where: { id: change.where.id },
-                            },
-                        },
-                    })
-                    .then((buy) => {
-                        return axios.patch(`Items/${buy.data.itemFk}`, patchData);
-                    })
-                    .catch((error) => {
-                        console.error('Error processing change: ', change, error);
-                    });
-
-                patchPromises.push(promise);
-            }
-        }
-
-        await Promise.all(patchPromises);
-
-        data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
-
-        return data;
-    } catch (error) {
-        console.error('Error in beforeSave:', error);
-        throw error;
-    }
-}
-
 function invertQuantitySign(rows, sign) {
     for (const row of rows) {
         if (sign > 0) row.quantity = Math.abs(row.quantity);
@@ -521,6 +452,23 @@ async function setBuyUltimate(itemFk, data) {
     });
 }
 
+async function transferBuys(rows, newEntry) {
+    if (!newEntry) return;
+
+    const promises = rows.map((row) => {
+        return axios.patch('Buys', { id: row.id, entryFk: newEntry });
+    });
+
+    await Promise.all(promises);
+
+    await axios.post(`Entries/${newEntry}/recalcEntryPrices`);
+    await axios.post(`Entries/${entityId.value}/recalcEntryPrices`);
+
+    entryBuysRef.value.reload();
+    newEntryRef.value = null;
+    dialogRef.value = false;
+}
+
 onMounted(() => {
     stateStore.rightDrawer = false;
     if ($props.editableMode) checkEntryLock(entityId.value, user.id);
@@ -595,6 +543,47 @@ onMounted(() => {
                     </QItem>
                 </QList>
             </QBtnDropdown>
+            <QBtn
+                icon="move_group"
+                color="primary"
+                :title="t('Transfer buys')"
+                data-cy="transferBuys"
+                flat
+                @click="dialogRef = true"
+                :disable="!selectedRows.length"
+            />
+            <QDialog v-model="dialogRef">
+                <QCard>
+                    <QCardSection>
+                        <span>{{ t('Transfer buys') }}</span>
+                    </QCardSection>
+                    <QCardSection>
+                        <VnInputNumber
+                            v-model="newEntryRef"
+                            :label="t('Entry')"
+                            type="number"
+                            data-cy="entryDestinyInput"
+                        />
+                    </QCardSection>
+                    <QCardSection>
+                        <QCardActions>
+                            <QBtn
+                                label="Cancel"
+                                flat
+                                color="primary"
+                                @click="dialogRef = false"
+                            />
+                            <QBtn
+                                label="Transfer"
+                                data-cy="transferBuysBtn"
+                                flat
+                                color="primary"
+                                @click="transferBuys(selectedRows, newEntryRef)"
+                            />
+                        </QCardActions>
+                    </QCardSection>
+                </QCard>
+            </QDialog>
         </QBtnGroup>
     </Teleport>
     <FetchData
@@ -610,6 +599,7 @@ onMounted(() => {
         :url="`Entries/${entityId}/getBuyList`"
         search-url="EntryBuys"
         save-url="Buys/crud"
+        :filter="editableMode ? filter : {}"
         :disable-option="{ card: true }"
         v-model:selected="selectedRows"
         @on-fetch="() => footerFetchDataRef.fetch()"
@@ -643,7 +633,7 @@ onMounted(() => {
             },
             columnGridStyle: {
                 'max-width': '50%',
-                'margin-right': '30px',
+                'margin-right': '5%',
                 flex: 1,
             },
             previousStyle: {
@@ -655,10 +645,10 @@ onMounted(() => {
         :is-editable="editableMode"
         :without-header="!editableMode"
         :with-filters="editableMode"
-        :right-search="editableMode"
+        :right-search="false"
         :row-click="false"
         :columns="columns"
-        :beforeSaveFn="beforeSave"
+        :beforeSaveFn="(data, getChanges) => beforeSave(data, getChanges, 'Buys')"
         class="buyList"
         :table-height="$props.tableHeight ?? '84vh'"
         auto-load
@@ -666,6 +656,47 @@ onMounted(() => {
         data-cy="entry-buys"
         overlay
     >
+        <template #top-left>
+            <VnRow>
+                <VnSelect
+                    :label="t('Buyer')"
+                    v-model="buyerFk"
+                    url="TicketRequests/getItemTypeWorker"
+                    :fields="['id', 'nickname']"
+                    option-label="nickname"
+                    sort-by="nickname ASC"
+                    :use-like="false"
+                />
+                <VnSelect
+                    :label="t('Family')"
+                    v-model="itemTypeFk"
+                    url="ItemTypes"
+                    :fields="['id', 'name']"
+                    option-label="name"
+                    sort-by="name ASC"
+                />
+                <VnSelect
+                    :label="t('Color')"
+                    v-model="inkFk"
+                    url="Inks"
+                    :fields="['id', 'name']"
+                    option-label="name"
+                    sort-by="name ASC"
+                />
+                <VnInput
+                    v-model="tag1Filter"
+                    :label="t('Tag')"
+                    @keyup.enter="tag1 = tag1Filter"
+                    @remove="tag1 = null"
+                />
+                <VnInput
+                    v-model="tag2Filter"
+                    :label="t('Tag')"
+                    @keyup.enter="tag2 = tag2Filter"
+                    @remove="tag2 = null"
+                />
+            </VnRow>
+        </template>
         <template #column-hex="{ row }">
             <VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />
         </template>
@@ -696,7 +727,7 @@ onMounted(() => {
             </div>
         </template>
         <template #column-footer-weight>
-            {{ footer?.weight }}
+            <span class="q-pr-xs">{{ footer?.weight }}</span>
         </template>
         <template #column-footer-quantity>
             <span :style="getQuantityStyle(footer)" data-cy="footer-quantity">
@@ -704,11 +735,10 @@ onMounted(() => {
             </span>
         </template>
         <template #column-footer-amount>
-            <span :style="getAmountStyle(footer)" data-cy="footer-amount">
-                {{ footer?.amount }}
-            </span>
+            <span data-cy="footer-amount">{{ footer?.amount }} / </span>
+            <span style="color: var(--q-positive)">{{ footer?.checkedAmount }}</span>
         </template>
-        <template #column-create-itemFk="{ data }">
+        <template #column-create-itemFk="{ data, validations }">
             <VnSelect
                 url="Items/search"
                 v-model="data.itemFk"
@@ -722,7 +752,8 @@ onMounted(() => {
                         await setBuyUltimate(value, data);
                     }
                 "
-                :required="true"
+                required
+                :rules="[(val) => validations.required(true, val)]"
                 data-cy="itemFk-create-popup"
                 sort-by="nickname DESC"
             >
@@ -767,6 +798,8 @@ onMounted(() => {
 </template>
 <i18n>
 es:
+    Buyer: Comprador
+    Family: Familia
     Article: Artículo
     Siz.: Med.
     Size: Medida
@@ -798,6 +831,8 @@ es:
     Create buy: Crear compra
     Invert quantity value: Invertir valor de cantidad
     Check buy amount: Marcar como correcta la cantidad de compra
+    Transfer buys: Transferir compras
+    Entry: Entrada
 </i18n>
 <style lang="scss" scoped>
 .centered-container {
diff --git a/src/pages/Entry/Card/EntryCard.vue b/src/pages/Entry/Card/EntryCard.vue
index be82289f4..e9d07889f 100644
--- a/src/pages/Entry/Card/EntryCard.vue
+++ b/src/pages/Entry/Card/EntryCard.vue
@@ -1,13 +1,13 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import EntryDescriptor from './EntryDescriptor.vue';
 import filter from './EntryFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Entry"
         url="Entries"
         :descriptor="EntryDescriptor"
-        :filter="filter"
+        :filter="{ ...filter, where: { id: $route.params.id } }"
     />
 </template>
diff --git a/src/pages/Entry/Card/EntryDescriptor.vue b/src/pages/Entry/Card/EntryDescriptor.vue
index 69b300cb2..2f9cfe0ff 100644
--- a/src/pages/Entry/Card/EntryDescriptor.vue
+++ b/src/pages/Entry/Card/EntryDescriptor.vue
@@ -6,7 +6,7 @@ import { toDate } from 'src/filters';
 import { getUrl } from 'src/composables/getUrl';
 import { useQuasar } from 'quasar';
 import { usePrintService } from 'composables/usePrintService';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
 import axios from 'axios';
@@ -92,7 +92,7 @@ const getEntryRedirectionFilter = (entry) => {
 };
 
 function showEntryReport() {
-    openReport(`Entries/${entityId.value}/entry-order-pdf`);
+    openReport(`Entries/${entityId.value}/entry-order-pdf`, {}, true);
 }
 
 function showNotification(type, message) {
@@ -145,10 +145,9 @@ async function deleteEntry() {
 </script>
 
 <template>
-    <CardDescriptor
-        ref="entryDescriptorRef"
+    <EntityDescriptor
         :url="`Entries/${entityId}`"
-        :userFilter="entryFilter"
+        :filter="entryFilter"
         title="supplier.nickname"
         data-key="Entry"
         width="lg-width"
@@ -265,7 +264,7 @@ async function deleteEntry() {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <i18n>
 es:
diff --git a/src/pages/Entry/Card/EntryNotes.vue b/src/pages/Entry/Card/EntryNotes.vue
index 459c3b069..4159ed5ca 100644
--- a/src/pages/Entry/Card/EntryNotes.vue
+++ b/src/pages/Entry/Card/EntryNotes.vue
@@ -2,153 +2,82 @@
 import { ref, computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-
-import FetchData from 'components/FetchData.vue';
-import CrudModel from 'components/CrudModel.vue';
-import VnInput from 'src/components/common/VnInput.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
+import VnTable from 'src/components/VnTable/VnTable.vue';
 
 const { params } = useRoute();
 const { t } = useI18n();
-
+const selectedRows = ref([]);
 const entryObservationsRef = ref(null);
-const entryObservationsOptions = ref([]);
-const selected = ref([]);
-
-const sortEntryObservationOptions = (data) => {
-    entryObservationsOptions.value = [...data].sort((a, b) =>
-        a.description.localeCompare(b.description),
-    );
-};
-
+const entityId = ref(params.id);
 const columns = computed(() => [
     {
-        name: 'observationType',
-        label: t('entry.notes.observationType'),
-        field: (row) => row.observationTypeFk,
-        sortable: true,
-        options: entryObservationsOptions.value,
-        required: true,
-        model: 'observationTypeFk',
-        optionValue: 'id',
-        optionLabel: 'description',
-        tabIndex: 1,
-        align: 'left',
+        name: 'id',
+        isId: true,
+        visible: false,
+        isEditable: false,
+        columnFilter: false,
     },
     {
+        name: 'observationTypeFk',
+        label: t('entry.notes.observationType'),
+        component: 'select',
+        columnFilter: { inWhere: true },
+        attrs: {
+            inWhere: true,
+            url: 'ObservationTypes',
+            fields: ['id', 'description'],
+            optionValue: 'id',
+            optionLabel: 'description',
+            sortBy: 'description',
+        },
+        width: '30px',
+        create: true,
+    },
+    {
+        align: 'left',
         name: 'description',
         label: t('globals.description'),
-        field: (row) => row.description,
-        tabIndex: 2,
-        align: 'left',
+        component: 'input',
+        columnFilter: false,
+        attrs: { autogrow: true },
+        create: true,
     },
 ]);
+
+const filter = computed(() => ({
+    fields: ['id', 'entryFk', 'observationTypeFk', 'description'],
+    include: ['observationType'],
+    where: { entryFk: entityId },
+}));
 </script>
 <template>
-    <FetchData
-        url="ObservationTypes"
-        @on-fetch="(data) => sortEntryObservationOptions(data)"
+    <VnTable
+        ref="entryObservationsRef"
+        data-key="EntryObservations"
+        :columns="columns"
+        url="EntryObservations"
+        :user-filter="filter"
+        order="id ASC"
+        :disable-option="{ card: true }"
+        :is-editable="true"
+        :right-search="true"
+        v-model:selected="selectedRows"
+        :create="{
+            urlCreate: 'EntryObservations',
+            title: t('Create note'),
+            onDataSaved: () => {
+                entryObservationsRef.reload();
+            },
+            formInitialData: { entryFk: entityId },
+        }"
+        :table="{
+            'row-key': 'id',
+            selection: 'multiple',
+        }"
         auto-load
     />
-    <CrudModel
-        data-key="EntryAccount"
-        url="EntryObservations"
-        model="EntryAccount"
-        :filter="{
-            fields: ['id', 'entryFk', 'observationTypeFk', 'description'],
-            where: { entryFk: params.id },
-        }"
-        ref="entryObservationsRef"
-        :data-required="{ entryFk: params.id }"
-        v-model:selected="selected"
-        auto-load
-    >
-        <template #body="{ rows, validate }">
-            <QTable
-                v-model:selected="selected"
-                :columns="columns"
-                :rows="rows"
-                :pagination="{ rowsPerPage: 0 }"
-                row-key="$index"
-                selection="multiple"
-                hide-pagination
-                :grid="$q.screen.lt.md"
-                table-header-class="text-left"
-            >
-                <template #body-cell-observationType="{ row, col }">
-                    <QTd>
-                        <VnSelect
-                            v-model="row[col.model]"
-                            :options="col.options"
-                            :option-value="col.optionValue"
-                            :option-label="col.optionLabel"
-                            :autofocus="col.tabIndex == 1"
-                            input-debounce="0"
-                            hide-selected
-                            :required="true"
-                        />
-                    </QTd>
-                </template>
-                <template #body-cell-description="{ row, col }">
-                    <QTd>
-                        <VnInput
-                            :label="t('globals.description')"
-                            v-model="row[col.name]"
-                            :rules="validate('EntryObservation.description')"
-                        />
-                    </QTd>
-                </template>
-                <template #item="props">
-                    <div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
-                        <QCard bordered flat>
-                            <QCardSection>
-                                <QCheckbox v-model="props.selected" dense />
-                            </QCardSection>
-                            <QSeparator />
-                            <QList dense>
-                                <QItem>
-                                    <QItemSection>
-                                        <VnSelect
-                                            v-model="props.row.observationTypeFk"
-                                            :options="entryObservationsOptions"
-                                            option-value="id"
-                                            option-label="description"
-                                            input-debounce="0"
-                                            hide-selected
-                                            :required="true"
-                                        />
-                                    </QItemSection>
-                                </QItem>
-                                <QItem>
-                                    <QItemSection>
-                                        <VnInput
-                                            :label="t('globals.description')"
-                                            v-model="props.row.description"
-                                            :rules="
-                                                validate('EntryObservation.description')
-                                            "
-                                        />
-                                    </QItemSection>
-                                </QItem>
-                            </QList>
-                        </QCard>
-                    </div>
-                </template>
-            </QTable>
-        </template>
-    </CrudModel>
-    <QPageSticky position="bottom-right" :offset="[25, 25]">
-        <QBtn
-            fab
-            color="primary"
-            icon="add"
-            v-shortcut="'+'"
-            @click="entryObservationsRef.insert()"
-        />
-    </QPageSticky>
 </template>
 <i18n>
     es:
-        Add note: Añadir nota
-        Remove note: Quitar nota
+        Create note: Crear nota
 </i18n>
diff --git a/src/pages/Entry/Card/EntrySummary.vue b/src/pages/Entry/Card/EntrySummary.vue
index c40e2ba46..d5ebcde18 100644
--- a/src/pages/Entry/Card/EntrySummary.vue
+++ b/src/pages/Entry/Card/EntrySummary.vue
@@ -70,8 +70,8 @@ onMounted(async () => {
                     :url="`#/entry/${entityId}/basic-data`"
                     :text="t('globals.summary.basicData')"
                 />
-                <div class="card-group">
-                    <div class="card-content">
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
                         <VnLv
                             :label="t('entry.summary.commission')"
                             :value="entry?.commission"
@@ -84,21 +84,24 @@ onMounted(async () => {
                             :label="t('globals.company')"
                             :value="entry?.company?.code"
                         />
-                        <VnLv :label="t('globals.reference')" :value="entry?.reference" />
+                        <VnLv
+                            :label="t('entry.list.tableVisibleColumns.reference')"
+                            :value="entry?.reference"
+                        />
                         <VnLv
                             :label="t('entry.summary.invoiceNumber')"
                             :value="entry?.invoiceNumber"
                         />
                     </div>
-                    <div class="card-content">
+                    <div class="vn-card-content">
                         <VnCheckbox
-                            :label="t('entry.summary.ordered')"
+                            :label="t('entry.list.tableVisibleColumns.isOrdered')"
                             v-model="entry.isOrdered"
                             :disable="true"
                             size="xs"
                         />
                         <VnCheckbox
-                            :label="t('globals.confirmed')"
+                            :label="t('entry.list.tableVisibleColumns.isConfirmed')"
                             v-model="entry.isConfirmed"
                             :disable="true"
                             size="xs"
@@ -110,7 +113,11 @@ onMounted(async () => {
                             size="xs"
                         />
                         <VnCheckbox
-                            :label="t('entry.summary.excludedFromAvailable')"
+                            :label="
+                                t(
+                                    'entry.list.tableVisibleColumns.isExcludedFromAvailable',
+                                )
+                            "
                             v-model="entry.isExcludedFromAvailable"
                             :disable="true"
                             size="xs"
@@ -123,8 +130,8 @@ onMounted(async () => {
                     :url="`#/travel/${entry.travel.id}/summary`"
                     :text="t('Travel')"
                 />
-                <div class="card-group">
-                    <div class="card-content">
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
                         <VnLv :label="t('entry.summary.travelReference')">
                             <template #value>
                                 <span class="link">
@@ -154,7 +161,8 @@ onMounted(async () => {
                             :value="entry.travel.warehouseIn?.name"
                         />
                     </div>
-                    <div class="card-content">
+                    <div class="vn-card-content">
+                        <VnLv :label="t('travel.awbFk')" :value="entry.travel.awbFk" />
                         <VnCheckbox
                             :label="t('entry.summary.travelDelivered')"
                             v-model="entry.travel.isDelivered"
@@ -185,31 +193,6 @@ onMounted(async () => {
         </template>
     </CardSummary>
 </template>
-<style lang="scss" scoped>
-.card-group {
-    display: flex;
-    flex-direction: column;
-}
-
-.card-content {
-    display: flex;
-    flex-direction: column;
-    text-overflow: ellipsis;
-    > div {
-        max-height: 24px;
-    }
-}
-
-@media (min-width: 1010px) {
-    .card-group {
-        flex-direction: row;
-    }
-    .card-content {
-        flex: 1;
-        margin-right: 16px;
-    }
-}
-</style>
 <i18n>
 es:
     Travel: Envío
diff --git a/src/pages/Entry/EntryFilter.vue b/src/pages/Entry/EntryFilter.vue
index c283e4a0b..19f4bca86 100644
--- a/src/pages/Entry/EntryFilter.vue
+++ b/src/pages/Entry/EntryFilter.vue
@@ -85,7 +85,7 @@ const entryFilterPanel = ref();
                 </QItemSection>
                 <QItemSection>
                     <QCheckbox
-                        :label="t('entry.list.tableVisibleColumns.isConfirmed')"
+                        label="LE"
                         v-model="params.isConfirmed"
                         toggle-indeterminate
                     >
@@ -101,13 +101,14 @@ const entryFilterPanel = ref();
                         :label="t('params.landed')"
                         v-model="params.landed"
                         @update:model-value="searchFn()"
-                        is-outlined
+                        filled
+                        data-cy="landed"
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput v-model="params.id" label="Id" is-outlined />
+                    <VnInput v-model="params.id" label="Id" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -117,15 +118,7 @@ const entryFilterPanel = ref();
                         @update:model-value="searchFn()"
                         hide-selected
                         dense
-                        outlined
-                        rounded
-                    />
-                </QItemSection>
-                <QItemSection>
-                    <VnInput
-                        v-model="params.invoiceNumber"
-                        :label="t('params.invoiceNumber')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -134,7 +127,7 @@ const entryFilterPanel = ref();
                     <VnInput
                         v-model="params.reference"
                         :label="t('entry.list.tableVisibleColumns.reference')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -149,8 +142,7 @@ const entryFilterPanel = ref();
                         :fields="['id', 'name']"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -159,7 +151,7 @@ const entryFilterPanel = ref();
                     <VnInput
                         v-model="params.evaNotes"
                         :label="t('params.evaNotes')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -171,10 +163,10 @@ const entryFilterPanel = ref();
                         @update:model-value="searchFn()"
                         url="Warehouses"
                         :fields="['id', 'name']"
+                        sort-by="name ASC"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -186,10 +178,10 @@ const entryFilterPanel = ref();
                         @update:model-value="searchFn()"
                         url="Warehouses"
                         :fields="['id', 'name']"
+                        sort-by="name ASC"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                         <template #option="scope">
                             <QItem v-bind="scope.itemProps">
@@ -211,7 +203,7 @@ const entryFilterPanel = ref();
                     <VnInput
                         v-model="params.invoiceNumber"
                         :label="t('params.invoiceNumber')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -228,8 +220,7 @@ const entryFilterPanel = ref();
                         option-label="description"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -238,7 +229,7 @@ const entryFilterPanel = ref();
                     <VnInput
                         v-model="params.evaNotes"
                         :label="t('params.evaNotes')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -267,7 +258,7 @@ en:
         hasToShowDeletedEntries: Show deleted entries
 es:
     params:
-        isExcludedFromAvailable: Inventario
+        isExcludedFromAvailable: Excluida
         isOrdered: Pedida
         isConfirmed: Confirmado
         isReceived: Recibida
diff --git a/src/pages/Entry/EntryLatestBuys.vue b/src/pages/Entry/EntryLatestBuys.vue
deleted file mode 100644
index 73fdcbbbf..000000000
--- a/src/pages/Entry/EntryLatestBuys.vue
+++ /dev/null
@@ -1,264 +0,0 @@
-<script setup>
-import { onMounted, onUnmounted, ref } from 'vue';
-import { useI18n } from 'vue-i18n';
-import { useStateStore } from 'stores/useStateStore';
-import { toDate } from 'src/filters';
-
-import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
-import RightMenu from 'src/components/common/RightMenu.vue';
-import EntryLatestBuysFilter from './EntryLatestBuysFilter.vue';
-import VnTable from 'components/VnTable/VnTable.vue';
-import VnImg from 'src/components/ui/VnImg.vue';
-
-const stateStore = useStateStore();
-const { t } = useI18n();
-const tableRef = ref();
-const columns = [
-    {
-        align: 'center',
-        label: t('entry.latestBuys.tableVisibleColumns.image'),
-        name: 'itemFk',
-        columnField: {
-            component: VnImg,
-            attrs: ({ row }) => {
-                return {
-                    id: row.id,
-                    size: '50x50',
-                };
-            },
-        },
-        columnFilter: false,
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.itemFk'),
-        name: 'itemFk',
-        isTitle: true,
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.summary.packing'),
-        name: 'packing',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.summary.grouping'),
-        name: 'grouping',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('globals.quantity'),
-        name: 'quantity',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('globals.description'),
-        name: 'description',
-    },
-    {
-        align: 'left',
-        label: t('globals.size'),
-        name: 'size',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('globals.tags'),
-        name: 'tags',
-    },
-    {
-        align: 'left',
-        label: t('globals.type'),
-        name: 'type',
-    },
-    {
-        align: 'left',
-        label: t('globals.intrastat'),
-        name: 'intrastat',
-    },
-    {
-        align: 'left',
-        label: t('globals.origin'),
-        name: 'origin',
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.weightByPiece'),
-        name: 'weightByPiece',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.isActive'),
-        name: 'isActive',
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.family'),
-        name: 'family',
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.entryFk'),
-        name: 'entryFk',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.summary.buyingValue'),
-        name: 'buyingValue',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.freightValue'),
-        name: 'freightValue',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.comissionValue'),
-        name: 'comissionValue',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.packageValue'),
-        name: 'packageValue',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.isIgnored'),
-        name: 'isIgnored',
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.price2'),
-        name: 'price2',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.price3'),
-        name: 'price3',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.minPrice'),
-        name: 'minPrice',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.ektFk'),
-        name: 'ektFk',
-    },
-    {
-        align: 'left',
-        label: t('globals.weight'),
-        name: 'weight',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.buys.packagingFk'),
-        name: 'packagingFk',
-        columnFilter: {
-            component: 'number',
-            inWhere: true,
-        },
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.packingOut'),
-        name: 'packingOut',
-    },
-    {
-        align: 'left',
-        label: t('entry.latestBuys.tableVisibleColumns.landing'),
-        name: 'landing',
-        component: 'date',
-        columnField: {
-            component: null,
-        },
-        format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landing)),
-    },
-];
-
-onMounted(async () => {
-    stateStore.rightDrawer = true;
-});
-
-onUnmounted(() => (stateStore.rightDrawer = false));
-</script>
-
-<template>
-    <RightMenu>
-        <template #right-panel>
-            <EntryLatestBuysFilter data-key="LatestBuys" />
-        </template>
-    </RightMenu>
-    <VnSubToolbar />
-    <VnTable
-        ref="tableRef"
-        data-key="LatestBuys"
-        url="Buys/latestBuysFilter"
-        order="id DESC"
-        :columns="columns"
-        redirect="entry"
-        :row-click="({ entryFk }) => tableRef.redirect(entryFk)"
-        auto-load
-        :right-search="false"
-    />
-</template>
diff --git a/src/pages/Entry/EntryLatestBuysFilter.vue b/src/pages/Entry/EntryLatestBuysFilter.vue
deleted file mode 100644
index 658ba3847..000000000
--- a/src/pages/Entry/EntryLatestBuysFilter.vue
+++ /dev/null
@@ -1,161 +0,0 @@
-<script setup>
-import { ref } from 'vue';
-import { useI18n } from 'vue-i18n';
-import VnInputDate from 'src/components/common/VnInputDate.vue';
-import VnInput from 'components/common/VnInput.vue';
-import VnSelect from 'components/common/VnSelect.vue';
-import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
-import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
-
-const { t } = useI18n();
-
-defineProps({
-    dataKey: {
-        type: String,
-        required: true,
-    },
-});
-
-const tagValues = ref([]);
-</script>
-
-<template>
-    <ItemsFilterPanel :data-key="dataKey" :custom-tags="['tags']">
-        <template #body="{ params, searchFn }">
-            <QItem class="q-my-md">
-                <QItemSection>
-                    <VnSelect
-                        :label="t('components.itemsFilterPanel.salesPersonFk')"
-                        v-model="params.salesPersonFk"
-                        url="TicketRequests/getItemTypeWorker"
-                        option-label="nickname"
-                        :fields="['id', 'nickname']"
-                        sort-by="nickname ASC"
-                        dense
-                        outlined
-                        rounded
-                        use-input
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-            </QItem>
-            <QItem class="q-my-md">
-                <QItemSection>
-                    <VnSelectSupplier
-                        v-model="params.supplierFk"
-                        url="Suppliers"
-                        :fields="['id', 'name', 'nickname']"
-                        sort-by="name ASC"
-                        dense
-                        outlined
-                        rounded
-                    />
-                </QItemSection>
-            </QItem>
-            <QItem class="q-my-md">
-                <QItemSection>
-                    <VnInputDate
-                        :label="t('components.itemsFilterPanel.started')"
-                        v-model="params.from"
-                        is-outlined
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-            </QItem>
-            <QItem class="q-my-md">
-                <QItemSection>
-                    <VnInputDate
-                        :label="t('components.itemsFilterPanel.ended')"
-                        v-model="params.to"
-                        is-outlined
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-            </QItem>
-            <QItem>
-                <QItemSection>
-                    <QCheckbox
-                        :label="t('components.itemsFilterPanel.active')"
-                        v-model="params.active"
-                        toggle-indeterminate
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-                <QItemSection>
-                    <QCheckbox
-                        :label="t('globals.visible')"
-                        v-model="params.visible"
-                        toggle-indeterminate
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-            </QItem>
-            <QItem>
-                <QItemSection>
-                    <QCheckbox
-                        :label="t('components.itemsFilterPanel.floramondo')"
-                        v-model="params.floramondo"
-                        toggle-indeterminate
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-            </QItem>
-
-            <QItem
-                v-for="(value, index) in tagValues"
-                :key="value"
-                class="q-mt-md filter-value"
-            >
-                <QItemSection class="col">
-                    <VnSelect
-                        :label="t('params.tag')"
-                        v-model="value.selectedTag"
-                        :options="tagOptions"
-                        option-label="name"
-                        dense
-                        outlined
-                        rounded
-                        :emit-value="false"
-                        use-input
-                        :is-clearable="false"
-                        @update:model-value="getSelectedTagValues(value)"
-                    />
-                </QItemSection>
-                <QItemSection class="col">
-                    <VnSelect
-                        v-if="!value?.selectedTag?.isFree && value.valueOptions"
-                        :label="t('params.value')"
-                        v-model="value.value"
-                        :options="value.valueOptions || []"
-                        option-value="value"
-                        option-label="value"
-                        dense
-                        outlined
-                        rounded
-                        emit-value
-                        use-input
-                        :disable="!value"
-                        :is-clearable="false"
-                        class="filter-input"
-                        @update:model-value="applyTags(params, searchFn)"
-                    />
-                    <VnInput
-                        v-else
-                        v-model="value.value"
-                        :label="t('params.value')"
-                        :disable="!value"
-                        is-outlined
-                        class="filter-input"
-                        :is-clearable="false"
-                        @keyup.enter="applyTags(params, searchFn)"
-                    />
-                </QItemSection>
-                <QIcon
-                    name="delete"
-                    class="filter-icon"
-                    @click="removeTag(index, params, searchFn)"
-                />
-            </QItem>
-        </template>
-    </ItemsFilterPanel>
-</template>
diff --git a/src/pages/Entry/EntryList.vue b/src/pages/Entry/EntryList.vue
index f66151cc9..e42380fa3 100644
--- a/src/pages/Entry/EntryList.vue
+++ b/src/pages/Entry/EntryList.vue
@@ -107,9 +107,8 @@ const columns = computed(() => [
         attrs: {
             url: 'suppliers',
             fields: ['id', 'name'],
-            where: { order: 'name DESC' },
+            sortBy: 'name ASC',
         },
-        format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName),
         width: '110px',
     },
     {
@@ -145,6 +144,7 @@ const columns = computed(() => [
         attrs: {
             url: 'agencyModes',
             fields: ['id', 'name'],
+            sortBy: 'name ASC',
         },
         columnField: {
             component: null,
@@ -158,7 +158,6 @@ const columns = computed(() => [
         component: 'input',
     },
     {
-        align: 'left',
         label: t('entry.list.tableVisibleColumns.warehouseOutFk'),
         name: 'warehouseOutFk',
         cardVisible: true,
@@ -166,6 +165,7 @@ const columns = computed(() => [
         attrs: {
             url: 'warehouses',
             fields: ['id', 'name'],
+            sortBy: 'name ASC',
         },
         columnField: {
             component: null,
@@ -174,7 +174,6 @@ const columns = computed(() => [
         width: '65px',
     },
     {
-        align: 'left',
         label: t('entry.list.tableVisibleColumns.warehouseInFk'),
         name: 'warehouseInFk',
         cardVisible: true,
@@ -182,6 +181,7 @@ const columns = computed(() => [
         attrs: {
             url: 'warehouses',
             fields: ['id', 'name'],
+            sortBy: 'name ASC',
         },
         columnField: {
             component: null,
@@ -190,7 +190,6 @@ const columns = computed(() => [
         width: '65px',
     },
     {
-        align: 'left',
         labelAbbreviation: t('Type'),
         label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
         toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'),
@@ -201,6 +200,7 @@ const columns = computed(() => [
             fields: ['code', 'description'],
             optionValue: 'code',
             optionLabel: 'description',
+            sortBy: 'description',
         },
         width: '65px',
         format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription),
@@ -248,7 +248,6 @@ function getBadgeAttrs(row) {
 
     let timeDiff = today - timeTicket;
 
-    if (timeDiff > 0) return { color: 'info', 'text-color': 'black' };
     if (timeDiff < 0) return { color: 'warning', 'text-color': 'black' };
     switch (row.entryTypeCode) {
         case 'regularization':
@@ -274,6 +273,7 @@ function getBadgeAttrs(row) {
         default:
             break;
     }
+    if (timeDiff > 0) return { color: 'info', 'text-color': 'black' };
     return { color: 'transparent' };
 }
 
@@ -283,7 +283,11 @@ onBeforeMount(async () => {
 </script>
 
 <template>
-    <VnSection :data-key="dataKey" prefix="entry">
+    <VnSection
+        :data-key="dataKey"
+        prefix="entry"
+        :array-data-props="{ url: 'Entries/filter' }"
+    >
         <template #advanced-menu>
             <EntryFilter :data-key="dataKey" />
         </template>
diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue
index 41f78617c..9e97e2ad5 100644
--- a/src/pages/Entry/EntryStockBought.vue
+++ b/src/pages/Entry/EntryStockBought.vue
@@ -1,24 +1,23 @@
 <script setup>
 import { ref, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { useState } from 'src/composables/useState';
-import { useQuasar } from 'quasar';
+import { useQuasar, date } from 'quasar';
 
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import FetchData from 'components/FetchData.vue';
 import FormModelPopup from 'components/FormModelPopup.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import VnRow from 'components/ui/VnRow.vue';
-import RightMenu from 'src/components/common/RightMenu.vue';
-import EntryStockBoughtFilter from './EntryStockBoughtFilter.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue';
+import TravelDescriptorProxy from '../Travel/Card/TravelDescriptorProxy.vue';
+import { useFilterParams } from 'src/composables/useFilterParams';
+import axios from 'axios';
 
 const { t } = useI18n();
 const quasar = useQuasar();
-const state = useState();
-const user = state.getUser();
+const filterDate = ref(useFilterParams('StockBoughts').params);
 const footer = ref({ bought: 0, reserve: 0 });
 const columns = computed(() => [
     {
@@ -46,7 +45,7 @@ const columns = computed(() => [
             optionValue: 'id',
         },
         columnFilter: false,
-        width: '50px',
+        width: '60%',
     },
     {
         align: 'center',
@@ -56,20 +55,20 @@ const columns = computed(() => [
         create: true,
         component: 'number',
         summation: true,
-        width: '50px',
         format: ({ reserve }, dashIfEmpty) => dashIfEmpty(round(reserve)),
+        width: '20%',
     },
     {
-        align: 'center',
+        align: 'right',
         label: t('entryStockBought.bought'),
         name: 'bought',
         summation: true,
         cardVisible: true,
         style: ({ reserve, bought }) => boughtStyle(bought, reserve),
         columnFilter: false,
+        width: '20%',
     },
     {
-        align: 'left',
         label: t('entryStockBought.date'),
         name: 'dated',
         component: 'date',
@@ -77,7 +76,7 @@ const columns = computed(() => [
         create: true,
     },
     {
-        align: 'left',
+        align: 'center',
         name: 'tableActions',
         actions: [
             {
@@ -90,7 +89,7 @@ const columns = computed(() => [
                         component: EntryStockBoughtDetail,
                         componentProps: {
                             workerFk: row.workerFk,
-                            dated: userParams.value.dated,
+                            dated: filterDate.value.dated,
                         },
                     });
                 },
@@ -98,39 +97,30 @@ const columns = computed(() => [
         ],
     },
 ]);
-
 const fetchDataRef = ref();
 const travelDialogRef = ref(false);
 const tableRef = ref();
 const travel = ref(null);
-const userParams = ref({
-    dated: Date.vnNew().toJSON(),
-});
-
-const filter = ref({
-    fields: ['id', 'm3', 'warehouseInFk'],
+const filter = computed(() => ({
+    fields: ['id', 'm3', 'ref', 'warehouseInFk'],
     include: [
         {
             relation: 'warehouseIn',
             scope: {
-                fields: ['code'],
+                fields: ['code', 'name'],
             },
         },
     ],
     where: {
-        shipped: (userParams.value.dated
-            ? new Date(userParams.value.dated)
-            : Date.vnNew()
-        ).setHours(0, 0, 0, 0),
+        shipped: date.adjustDate(filterDate.value.dated, {
+            hour: 0,
+            minute: 0,
+            second: 0,
+            milliseconds: 0,
+        }),
         m3: { neq: null },
     },
-});
-
-const setUserParams = async ({ dated }) => {
-    const shipped = (dated ? new Date(dated) : Date.vnNew()).setHours(0, 0, 0, 0);
-    filter.value.where.shipped = shipped;
-    fetchDataRef.value?.fetch();
-};
+}));
 
 function openDialog() {
     travelDialogRef.value = true;
@@ -151,6 +141,31 @@ function round(value) {
 function boughtStyle(bought, reserve) {
     return reserve < bought ? { color: 'var(--q-negative)' } : '';
 }
+
+async function beforeSave(data, getChanges) {
+    const changes = data.creates;
+    if (!changes) return data;
+    const patchPromises = [];
+
+    for (const change of changes) {
+        if (change?.isReal === false && change?.reserve > 0) {
+            const postData = {
+                workerFk: change.workerFk,
+                reserve: change.reserve,
+                dated: filterDate.value.dated,
+            };
+            const promise = axios.post('StockBoughts', postData).catch((error) => {
+                console.error('Error processing change: ', change, error);
+            });
+
+            patchPromises.push(promise);
+        }
+    }
+
+    await Promise.all(patchPromises);
+    data.creates = [];
+    return data;
+}
 </script>
 <template>
     <VnSubToolbar>
@@ -158,18 +173,17 @@ function boughtStyle(bought, reserve) {
             <FetchData
                 ref="fetchDataRef"
                 url="Travels"
-                auto-load
                 :filter="filter"
                 @on-fetch="
                     (data) => {
                         travel = data.find(
-                            (data) => data.warehouseIn?.code.toLowerCase() === 'vnh',
+                            (data) => data.warehouseIn?.code?.toLowerCase() === 'vnh',
                         );
                     }
                 "
             />
             <VnRow class="travel">
-                <div v-if="travel">
+                <div v-show="travel">
                     <span style="color: var(--vn-label-color)">
                         {{ t('entryStockBought.purchaseSpaces') }}:
                     </span>
@@ -180,7 +194,7 @@ function boughtStyle(bought, reserve) {
                         v-if="travel?.m3"
                         style="max-width: 20%"
                         flat
-                        icon="edit"
+                        icon="search"
                         @click="openDialog()"
                         :title="t('entryStockBought.editTravel')"
                         color="primary"
@@ -190,62 +204,47 @@ function boughtStyle(bought, reserve) {
             </VnRow>
         </template>
     </VnSubToolbar>
-    <QDialog v-model="travelDialogRef" :maximized="true" :class="['vn-row', 'wrap']">
+    <QDialog v-model="travelDialogRef" :class="['vn-row', 'wrap']">
         <FormModelPopup
             :url-update="`Travels/${travel?.id}`"
             model="travel"
             :title="t('Travel m3')"
-            :form-initial-data="{ id: travel?.id, m3: travel?.m3 }"
+            :form-initial-data="travel"
             @on-data-saved="fetchDataRef.fetch()"
         >
             <template #form-inputs="{ data }">
-                <VnInput
-                    v-model="data.id"
-                    :label="t('id')"
-                    type="number"
-                    disable
-                    readonly
-                />
+                <span class="link">
+                    {{ data.ref }}
+                    <TravelDescriptorProxy :id="data.id" />
+                </span>
                 <VnInput v-model="data.m3" :label="t('m3')" type="number" />
             </template>
         </FormModelPopup>
     </QDialog>
-    <RightMenu>
-        <template #right-panel>
-            <EntryStockBoughtFilter
-                data-key="StockBoughts"
-                @set-user-params="setUserParams"
-            />
-        </template>
-    </RightMenu>
     <div class="table-container">
         <div class="column items-center">
             <VnTable
                 ref="tableRef"
                 data-key="StockBoughts"
                 url="StockBoughts/getStockBought"
+                :beforeSaveFn="beforeSave"
                 save-url="StockBoughts/crud"
                 search-url="StockBoughts"
-                order="reserve DESC"
-                :right-search="false"
+                order="bought DESC"
                 :is-editable="true"
-                @on-fetch="(data) => setFooter(data)"
-                :create="{
-                    urlCreate: 'StockBoughts',
-                    title: t('entryStockBought.reserveSomeSpace'),
-                    onDataSaved: () => tableRef.reload(),
-                    formInitialData: {
-                        workerFk: user.id,
-                        dated: Date.vnNow(),
-                    },
-                }"
+                @on-fetch="
+                    async (data) => {
+                        setFooter(data);
+                        await fetchDataRef.fetch();
+                    }
+                "
                 :columns="columns"
-                :user-params="userParams"
                 :footer="true"
                 table-height="80vh"
-                auto-load
                 :column-search="false"
                 :without-header="true"
+                :user-params="{ dated: Date.vnNew() }"
+                auto-load
             >
                 <template #column-workerFk="{ row }">
                     <span class="link" @click.stop>
@@ -254,12 +253,15 @@ function boughtStyle(bought, reserve) {
                     </span>
                 </template>
                 <template #column-footer-reserve>
-                    <span>
+                    <span class="q-pr-xs">
                         {{ round(footer.reserve) }}
                     </span>
                 </template>
                 <template #column-footer-bought>
-                    <span :style="boughtStyle(footer?.bought, footer?.reserve)">
+                    <span
+                        :style="boughtStyle(footer?.bought, footer?.reserve)"
+                        class="q-pr-xs"
+                    >
                         {{ round(footer.bought) }}
                     </span>
                 </template>
@@ -277,10 +279,7 @@ function boughtStyle(bought, reserve) {
 }
 .column {
     min-width: 35%;
-    margin-top: 5%;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
+    margin-top: 1%;
 }
 .text-negative {
     color: $negative !important;
diff --git a/src/pages/Entry/EntryStockBoughtFilter.vue b/src/pages/Entry/EntryStockBoughtFilter.vue
deleted file mode 100644
index 136881f17..000000000
--- a/src/pages/Entry/EntryStockBoughtFilter.vue
+++ /dev/null
@@ -1,70 +0,0 @@
-<script setup>
-import { useI18n } from 'vue-i18n';
-import { onMounted } from 'vue';
-import { useStateStore } from 'stores/useStateStore';
-
-import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
-import VnInputDate from 'src/components/common/VnInputDate.vue';
-
-const { t } = useI18n();
-const props = defineProps({
-    dataKey: {
-        type: String,
-        required: true,
-    },
-});
-const stateStore = useStateStore();
-const emit = defineEmits(['set-user-params']);
-const setUserParams = (params) => {
-    emit('set-user-params', params);
-};
-onMounted(async () => {
-    stateStore.rightDrawer = true;
-});
-</script>
-
-<template>
-    <VnFilterPanel
-        :data-key="props.dataKey"
-        :search-button="true"
-        search-url="StockBoughts"
-        @set-user-params="setUserParams"
-    >
-        <template #tags="{ tag, formatFn }">
-            <div class="q-gutter-x-xs">
-                <strong>{{ t(`params.${tag.label}`) }}: </strong>
-                <span>{{ formatFn(tag.value) }}</span>
-            </div>
-        </template>
-        <template #body="{ params, searchFn }">
-            <QItem class="q-my-sm">
-                <QItemSection>
-                    <VnInputDate
-                        id="date"
-                        v-model="params.dated"
-                        @update:model-value="
-                            (value) => {
-                                params.dated = value;
-                                setUserParams(params);
-                                searchFn();
-                            }
-                        "
-                        :label="t('Date')"
-                        is-outlined
-                    />
-                </QItemSection>
-            </QItem>
-        </template>
-    </VnFilterPanel>
-</template>
-<i18n>
-    en:
-        params:
-            dated: Date
-            workerFk: Worker
-    es:
-        Date: Fecha
-        params:
-            dated: Fecha
-            workerFk: Trabajador
-</i18n>
diff --git a/src/pages/Entry/MyEntries.vue b/src/pages/Entry/EntrySupplier.vue
similarity index 67%
rename from src/pages/Entry/MyEntries.vue
rename to src/pages/Entry/EntrySupplier.vue
index 3f7566ae0..d8b17007f 100644
--- a/src/pages/Entry/MyEntries.vue
+++ b/src/pages/Entry/EntrySupplier.vue
@@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import { toDate } from 'src/filters/index';
 import { useQuasar } from 'quasar';
-import EntryBuysTableDialog from './EntryBuysTableDialog.vue';
+import EntrySupplierlDetail from './EntrySupplierlDetail.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 
 const { t } = useI18n();
@@ -18,18 +18,28 @@ const columns = computed(() => [
     {
         align: 'left',
         name: 'id',
-        label: t('myEntries.id'),
+        label: t('entrySupplier.id'),
         columnFilter: false,
+        isId: true,
+        chip: {
+            condition: () => true,
+        },
+    },
+    {
+        align: 'left',
+        name: 'supplierName',
+        label: t('entrySupplier.supplierName'),
+        cardVisible: true,
         isTitle: true,
     },
     {
         visible: false,
         align: 'right',
-        label: t('myEntries.shipped'),
+        label: t('entrySupplier.shipped'),
         name: 'shipped',
         columnFilter: {
             name: 'fromShipped',
-            label: t('myEntries.fromShipped'),
+            label: t('entrySupplier.fromShipped'),
             component: 'date',
         },
         format: ({ shipped }) => toDate(shipped),
@@ -37,26 +47,26 @@ const columns = computed(() => [
     {
         visible: false,
         align: 'left',
-        label: t('myEntries.shipped'),
+        label: t('entrySupplier.shipped'),
         name: 'shipped',
         columnFilter: {
             name: 'toShipped',
-            label: t('myEntries.toShipped'),
+            label: t('entrySupplier.toShipped'),
             component: 'date',
         },
         format: ({ shipped }) => toDate(shipped),
         cardVisible: true,
     },
     {
-        align: 'right',
-        label: t('myEntries.shipped'),
+        align: 'left',
+        label: t('entrySupplier.shipped'),
         name: 'shipped',
         columnFilter: false,
         format: ({ shipped }) => toDate(shipped),
     },
     {
-        align: 'right',
-        label: t('myEntries.landed'),
+        align: 'left',
+        label: t('entrySupplier.landed'),
         name: 'landed',
         columnFilter: false,
         format: ({ landed }) => toDate(landed),
@@ -64,15 +74,13 @@ const columns = computed(() => [
 
     {
         align: 'right',
-        label: t('myEntries.wareHouseIn'),
+        label: t('entrySupplier.wareHouseIn'),
         name: 'warehouseInFk',
-        format: (row) => {
-            row.warehouseInName;
-        },
+        format: ({ warehouseInName }) => warehouseInName,
         cardVisible: true,
         columnFilter: {
             name: 'warehouseInFk',
-            label: t('myEntries.warehouseInFk'),
+            label: t('entrySupplier.warehouseInFk'),
             component: 'select',
             attrs: {
                 url: 'warehouses',
@@ -86,13 +94,13 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        label: t('myEntries.daysOnward'),
+        label: t('entrySupplier.daysOnward'),
         name: 'daysOnward',
         visible: false,
     },
     {
         align: 'left',
-        label: t('myEntries.daysAgo'),
+        label: t('entrySupplier.daysAgo'),
         name: 'daysAgo',
         visible: false,
     },
@@ -101,8 +109,8 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('myEntries.printLabels'),
-                icon: 'move_item',
+                title: t('entrySupplier.printLabels'),
+                icon: 'search',
                 isPrimary: true,
                 action: (row) => printBuys(row.id),
             },
@@ -112,7 +120,7 @@ const columns = computed(() => [
 
 const printBuys = (rowId) => {
     quasar.dialog({
-        component: EntryBuysTableDialog,
+        component: EntrySupplierlDetail,
         componentProps: {
             id: rowId,
         },
@@ -121,19 +129,18 @@ const printBuys = (rowId) => {
 </script>
 <template>
     <VnSearchbar
-        data-key="myEntriesList"
+        data-key="entrySupplierList"
         url="Entries/filter"
-        :label="t('myEntries.search')"
-        :info="t('myEntries.searchInfo')"
+        :label="t('entrySupplier.search')"
+        :info="t('entrySupplier.searchInfo')"
     />
     <VnTable
-        data-key="myEntriesList"
+        data-key="entrySupplierList"
         url="Entries/filter"
         :columns="columns"
         :user-params="params"
         default-mode="card"
         order="shipped DESC"
         auto-load
-        chip-locale="myEntries"
     />
 </template>
diff --git a/src/pages/Entry/EntryBuysTableDialog.vue b/src/pages/Entry/EntrySupplierlDetail.vue
similarity index 87%
rename from src/pages/Entry/EntryBuysTableDialog.vue
rename to src/pages/Entry/EntrySupplierlDetail.vue
index 7a6c4ac43..01f6012c5 100644
--- a/src/pages/Entry/EntryBuysTableDialog.vue
+++ b/src/pages/Entry/EntrySupplierlDetail.vue
@@ -30,7 +30,7 @@ const entriesTableColumns = computed(() => [
         align: 'left',
         name: 'itemFk',
         field: 'itemFk',
-        label: t('entry.latestBuys.tableVisibleColumns.itemFk'),
+        label: t('entrySupplier.itemId'),
     },
     {
         align: 'left',
@@ -65,7 +65,15 @@ const entriesTableColumns = computed(() => [
 ]);
 
 function downloadCSV(rows) {
-    const headers = ['id', 'itemFk', 'name', 'stickers', 'packing', 'grouping', 'comment'];
+    const headers = [
+        'id',
+        'itemFk',
+        'name',
+        'stickers',
+        'packing',
+        'grouping',
+        'comment',
+    ];
 
     const csvRows = rows.map((row) => {
         const buy = row;
@@ -119,17 +127,18 @@ function downloadCSV(rows) {
                         >
                             <template #top-left>
                                 <QBtn
-                                    :label="t('myEntries.downloadCsv')"
+                                    :label="t('entrySupplier.downloadCsv')"
                                     color="primary"
                                     icon="csv"
                                     @click="downloadCSV(rows)"
                                     unelevated
+                                    data-cy="downloadCsvBtn"
                                 />
                             </template>
                             <template #top-right>
                                 <QBtn
                                     class="q-mr-lg"
-                                    :label="t('myEntries.printLabels')"
+                                    :label="t('entrySupplier.printLabels')"
                                     color="primary"
                                     icon="print"
                                     @click="
@@ -148,13 +157,18 @@ function downloadCSV(rows) {
                                         v-if="props.row.stickers > 0"
                                         @click="
                                             openReport(
-                                                `Entries/${props.row.id}/buy-label-supplier`
+                                                `Entries/${props.row.id}/buy-label-supplier`,
+                                                {},
+                                                true,
                                             )
                                         "
                                         unelevated
+                                        color="primary"
+                                        flat
+                                        data-cy="seeLabelBtn"
                                     >
                                         <QTooltip>{{
-                                            t('myEntries.viewLabel')
+                                            t('entrySupplier.viewLabel')
                                         }}</QTooltip>
                                     </QBtn>
                                 </QTr>
diff --git a/src/pages/Entry/EntryWasteRecalc.vue b/src/pages/Entry/EntryWasteRecalc.vue
index 6ae200ed7..2fcd0f843 100644
--- a/src/pages/Entry/EntryWasteRecalc.vue
+++ b/src/pages/Entry/EntryWasteRecalc.vue
@@ -38,7 +38,7 @@ const recalc = async () => {
 
 <template>
     <div class="q-pa-lg row justify-center">
-        <QCard class="bg-light" style="width: 300px">
+        <QCard class="bg-light" style="width: 300px" data-cy="wasteRecalc">
             <QCardSection>
                 <VnInputDate
                     class="q-mb-lg"
@@ -46,6 +46,7 @@ const recalc = async () => {
                     :label="$t('globals.from')"
                     rounded
                     dense
+                    data-cy="dateFrom"
                 />
                 <VnInputDate
                     class="q-mb-lg"
@@ -55,6 +56,7 @@ const recalc = async () => {
                     :disable="!dateFrom"
                     rounded
                     dense
+                    data-cy="dateTo"
                 />
                 <QBtn
                     color="primary"
@@ -63,6 +65,7 @@ const recalc = async () => {
                     :loading="isLoading"
                     :disable="isLoading || !(dateFrom && dateTo)"
                     @click="recalc()"
+                    data-cy="recalc"
                 />
             </QCardSection>
         </QCard>
diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml
index 88b16cb03..0bc92a5ea 100644
--- a/src/pages/Entry/locale/en.yml
+++ b/src/pages/Entry/locale/en.yml
@@ -6,7 +6,7 @@ entry:
     list:
         newEntry: New entry
         tableVisibleColumns:
-            isExcludedFromAvailable: Exclude from inventory
+            isExcludedFromAvailable: Excluded from available
             isOrdered: Ordered
             isConfirmed: Ready to label
             isReceived: Received
@@ -33,7 +33,7 @@ entry:
         invoiceAmount: Invoice amount
         ordered: Ordered
         booked: Booked
-        excludedFromAvailable: Inventory
+        excludedFromAvailable: Excluded
         travelReference: Reference
         travelAgency: Agency
         travelShipped: Shipped
@@ -55,7 +55,7 @@ entry:
         commission: Commission
         observation: Observation
         booked: Booked
-        excludedFromAvailable: Inventory
+        excludedFromAvailable: Excluded
         initialTemperature: Ini °C
         finalTemperature: Fin °C
     buys:
@@ -65,27 +65,10 @@ entry:
         printedStickers: Printed stickers
     notes:
         observationType: Observation type
-    latestBuys:
-        tableVisibleColumns:
-            image: Picture
-            itemFk: Item ID
-            weightByPiece: Weight/Piece
-            isActive: Active
-            family: Family
-            entryFk: Entry
-            freightValue: Freight value
-            comissionValue: Commission value
-            packageValue: Package value
-            isIgnored: Is ignored
-            price2: Grouping
-            price3: Packing
-            minPrice: Min
-            ektFk: Ekt
-            packingOut: Package out
-            landing: Landing
-            isExcludedFromAvailable: Es inventory
     params:
-        isExcludedFromAvailable: Exclude from inventory
+        entryFk: Entry
+        observationTypeFk: Observation type
+        isExcludedFromAvailable: Excluded from available
         isOrdered: Ordered
         isConfirmed: Ready to label
         isReceived: Received
@@ -127,13 +110,17 @@ entry:
         company_name: Company name
         itemTypeFk: Item type
         workerFk: Worker id
+        daysAgo: Days ago
+        toShipped: T. shipped
+        fromShipped: F. shipped
+        supplierName: Supplier
     search: Search entries
     searchInfo: You can search by entry reference
     descriptorMenu:
         showEntryReport: Show entry report
 entryFilter:
     params:
-        isExcludedFromAvailable: Exclude from inventory
+        isExcludedFromAvailable: Excluded from available
         invoiceNumber: Invoice number
         travelFk: Travel
         companyFk: Company
@@ -155,7 +142,7 @@ entryFilter:
         warehouseOutFk: Origin
         warehouseInFk: Destiny
         entryTypeCode: Entry type
-myEntries:
+entrySupplier:
     id: ID
     landed: Landed
     shipped: Shipped
@@ -170,6 +157,8 @@ myEntries:
     downloadCsv: Download CSV
     search: Search entries
     searchInfo: You can search by entry reference
+    supplierName: Supplier
+    itemId: Item id
 entryStockBought:
     travel: Travel
     editTravel: Edit travel
diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml
index 3025d64cb..2c80299bc 100644
--- a/src/pages/Entry/locale/es.yml
+++ b/src/pages/Entry/locale/es.yml
@@ -6,7 +6,7 @@ entry:
     list:
         newEntry: Nueva entrada
         tableVisibleColumns:
-            isExcludedFromAvailable: Excluir del inventario
+            isExcludedFromAvailable: Excluir del disponible
             isOrdered: Pedida
             isConfirmed: Lista para etiquetar
             isReceived: Recibida
@@ -25,7 +25,7 @@ entry:
             entryTypeDescription: Tipo entrada
             invoiceAmount: Importe
             dated: Fecha
-        inventoryEntry: Es inventario
+            inventoryEntry: Es inventario
     summary:
         commission: Comisión
         currency: Moneda
@@ -33,7 +33,8 @@ entry:
         invoiceAmount: Importe
         ordered: Pedida
         booked: Contabilizada
-        excludedFromAvailable: Inventario
+        excludedFromAvailable: Excluir del disponible
+        isConfirmed: Lista para etiquetar
         travelReference: Referencia
         travelAgency: Agencia
         travelShipped: F. envio
@@ -56,7 +57,7 @@ entry:
         observation: Observación
         commission: Comisión
         booked: Contabilizada
-        excludedFromAvailable: Inventario
+        excludedFromAvailable: Excluir del disponible
         initialTemperature: Ini °C
         finalTemperature: Fin °C
     buys:
@@ -66,30 +67,12 @@ entry:
         printedStickers: Etiquetas impresas
     notes:
         observationType: Tipo de observación
-    latestBuys:
-        tableVisibleColumns:
-            image: Foto
-            itemFk: Id Artículo
-            weightByPiece: Peso (gramos)/tallo
-            isActive: Activo
-            family: Familia
-            entryFk: Entrada
-            freightValue: Porte
-            comissionValue: Comisión
-            packageValue: Embalaje
-            isIgnored: Ignorado
-            price2: Grouping
-            price3: Packing
-            minPrice: Min
-            ektFk: Ekt
-            packingOut: Embalaje envíos
-            landing: Llegada
-            isExcludedFromAvailable: Es inventario
-
     search: Buscar entradas
     searchInfo: Puedes buscar por referencia de entrada
     params:
-        isExcludedFromAvailable: Excluir del inventario
+        entryFk: Entrada
+        observationTypeFk: Tipo de observación
+        isExcludedFromAvailable: Excluir del disponible
         isOrdered: Pedida
         isConfirmed: Lista para etiquetar
         isReceived: Recibida
@@ -131,11 +114,15 @@ entry:
         company_name: Nombre empresa
         itemTypeFk: Familia
         workerFk: Comprador
+        daysAgo: Días atras
+        toShipped: F. salida(hasta)
+        fromShipped: F. salida(desde)
+        supplierName: Proveedor
 entryFilter:
     params:
-        isExcludedFromAvailable: Inventario
+        isExcludedFromAvailable: Excluir del disponible
         isOrdered: Pedida
-        isConfirmed: Confirmado
+        isConfirmed: Lista para etiquetar
         isReceived: Recibida
         isRaid: Raid
         landed: Fecha
@@ -149,7 +136,7 @@ entryFilter:
         warehouseInFk: Destino
         entryTypeCode: Tipo de entrada
         hasToShowDeletedEntries: Mostrar entradas eliminadas
-myEntries:
+entrySupplier:
     id: ID
     landed: F. llegada
     shipped: F. salida
@@ -164,10 +151,12 @@ myEntries:
     downloadCsv: Descargar CSV
     search: Buscar entradas
     searchInfo: Puedes buscar por referencia de la entrada
+    supplierName: Proveedor
+    itemId: Id artículo
 entryStockBought:
     travel: Envío
     editTravel: Editar envío
-    purchaseSpaces: Espacios de compra
+    purchaseSpaces: Camiones reservados
     buyer: Comprador
     reserve: Reservado
     bought: Comprado
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index 905ddebb2..c3b678678 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -121,42 +121,49 @@ function deleteFile(dmsFk) {
                     hide-selected
                     :is-clearable="false"
                     :required="true"
+                    data-cy="invoiceInBasicDataSupplier"
                 />
                 <VnInput
                     clearable
                     clear-icon="close"
                     :label="t('invoiceIn.supplierRef')"
                     v-model="data.supplierRef"
+                    data-cy="invoiceInBasicDataSupplierRef"
                 />
             </VnRow>
             <VnRow>
-                <VnInputDate :label="t('Expedition date')" v-model="data.issued" />
+                <VnInputDate
+                    :label="t('Expedition date')"
+                    v-model="data.issued"
+                    data-cy="invoiceInBasicDataIssued"
+                />
                 <VnInputDate
                     :label="t('Operation date')"
                     v-model="data.operated"
                     autofocus
+                    data-cy="invoiceInBasicDataOperated"
                 />
             </VnRow>
             <VnRow>
-                <VnInputDate :label="t('Entry date')" v-model="data.bookEntried" />
-                <VnInputDate :label="t('Accounted date')" v-model="data.booked" />
+                <VnInputDate
+                    :label="t('Entry date')"
+                    v-model="data.bookEntried"
+                    data-cy="invoiceInBasicDatabookEntried"
+                />
+                <VnInputDate
+                    :label="t('Accounted date')"
+                    v-model="data.booked"
+                    data-cy="invoiceInBasicDataBooked"
+                />
             </VnRow>
             <VnRow>
                 <VnSelect
-                    :label="t('Undeductible VAT')"
-                    v-model="data.deductibleExpenseFk"
-                    :options="expenses"
+                    :label="t('invoiceIn.summary.sage')"
+                    v-model="data.withholdingSageFk"
+                    :options="sageWithholdings"
                     option-value="id"
-                    option-label="id"
-                    :filter-options="['id', 'name']"
-                    data-cy="UnDeductibleVatSelect"
-                >
-                    <template #option="scope">
-                        <QItem v-bind="scope.itemProps">
-                            {{ `${scope.opt.id}: ${scope.opt.name}` }}
-                        </QItem>
-                    </template>
-                </VnSelect>
+                    option-label="withholding"
+                />
 
                 <div class="row no-wrap">
                     <VnInput
@@ -182,6 +189,7 @@ function deleteFile(dmsFk) {
                             padding="xs"
                             round
                             @click="downloadFile(data.dmsFk)"
+                            data-cy="invoiceInBasicDataDmsDownload"
                         />
                         <QBtn
                             :class="{
@@ -197,6 +205,7 @@ function deleteFile(dmsFk) {
                                     documentDialogRef.dms = data.dms;
                                 }
                             "
+                            data-cy="invoiceInBasicDataDmsEdit"
                         >
                             <QTooltip>{{ t('Edit document') }}</QTooltip>
                         </QBtn>
@@ -210,6 +219,7 @@ function deleteFile(dmsFk) {
                             padding="xs"
                             round
                             @click="deleteFile(data.dmsFk)"
+                            data-cy="invoiceInBasicDataDmsDelete"
                         />
                     </div>
                     <QBtn
@@ -224,7 +234,7 @@ function deleteFile(dmsFk) {
                                 delete documentDialogRef.dms;
                             }
                         "
-                        data-cy="dms-create"
+                        data-cy="invoiceInBasicDataDmsAdd"
                     >
                         <QTooltip>{{ t('Create document') }}</QTooltip>
                     </QBtn>
@@ -237,9 +247,9 @@ function deleteFile(dmsFk) {
                     :label="t('Currency')"
                     v-model="data.currencyFk"
                     :options="currencies"
-                    option-value="id"
                     option-label="code"
                     sort-by="id"
+                    data-cy="invoiceInBasicDataCurrencyFk"
                 />
 
                 <VnSelect
@@ -249,17 +259,8 @@ function deleteFile(dmsFk) {
                     :label="t('Company')"
                     v-model="data.companyFk"
                     :options="companies"
-                    option-value="id"
                     option-label="code"
-                />
-            </VnRow>
-            <VnRow>
-                <VnSelect
-                    :label="t('invoiceIn.summary.sage')"
-                    v-model="data.withholdingSageFk"
-                    :options="sageWithholdings"
-                    option-value="id"
-                    option-label="withholding"
+                    data-cy="invoiceInBasicDataCompanyFk"
                 />
             </VnRow>
         </template>
@@ -313,7 +314,6 @@ function deleteFile(dmsFk) {
         supplierFk: Proveedor
         Expedition date: Fecha expedición
         Operation date: Fecha operación
-        Undeductible VAT: Iva no deducible
         Document: Documento
         Download file: Descargar archivo
         Entry date: Fecha asiento
diff --git a/src/pages/InvoiceIn/Card/InvoiceInCard.vue b/src/pages/InvoiceIn/Card/InvoiceInCard.vue
index 34cc26437..a1bae87a6 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInCard.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInCard.vue
@@ -1,5 +1,5 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import InvoiceInDescriptor from './InvoiceInDescriptor.vue';
 import { onBeforeRouteUpdate } from 'vue-router';
 import { setRectificative } from '../composables/setRectificative';
@@ -9,7 +9,7 @@ onBeforeRouteUpdate(async (to) => await setRectificative(to));
 </script>
 
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="InvoiceIn"
         url="InvoiceIns"
         :descriptor="InvoiceInDescriptor"
diff --git a/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue b/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue
index 1d0a8d078..775a2a72b 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue
@@ -1,22 +1,16 @@
 <script setup>
 import { ref, computed, capitalize } from 'vue';
-import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { useArrayData } from 'src/composables/useArrayData';
 import CrudModel from 'src/components/CrudModel.vue';
 import FetchData from 'src/components/FetchData.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 
-const route = useRoute();
 const { t } = useI18n();
 
 const arrayData = useArrayData();
 const invoiceIn = computed(() => arrayData.store.data);
 const invoiceInCorrectionRef = ref();
-const filter = {
-    include: { relation: 'invoiceIn' },
-    where: { correctingFk: route.params.id },
-};
 const columns = computed(() => [
     {
         name: 'origin',
@@ -92,7 +86,8 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
         v-if="invoiceIn"
         data-key="InvoiceInCorrection"
         url="InvoiceInCorrections"
-        :filter="filter"
+        :user-filter="{ include: { relation: 'invoiceIn' } }"
+        :filter="{ where: { correctingFk: $route.params.id } }"
         auto-load
         primary-key="correctingFk"
         :default-remove="false"
@@ -115,6 +110,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
                             :option-label="col.optionLabel"
                             :disable="row.invoiceIn.isBooked"
                             :filter-options="['description']"
+                            data-cy="invoiceInCorrective_type"
                         >
                             <template #option="{ opt, itemProps }">
                                 <QItem v-bind="itemProps">
@@ -137,6 +133,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
                             :rules="[requiredFieldRule]"
                             :filter-options="['code', 'description']"
                             :disable="row.invoiceIn.isBooked"
+                            data-cy="invoiceInCorrective_class"
                         >
                             <template #option="{ opt, itemProps }">
                                 <QItem v-bind="itemProps">
@@ -161,6 +158,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
                             :option-label="col.optionLabel"
                             :rules="[requiredFieldRule]"
                             :disable="row.invoiceIn.isBooked"
+                            data-cy="invoiceInCorrective_reason"
                         />
                     </QTd>
                 </template>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
index 3843f5bf7..c5d79b045 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
@@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n';
 import axios from 'axios';
 import { toCurrency, toDate } from 'src/filters';
 import VnLv from 'src/components/ui/VnLv.vue';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
 import filter from './InvoiceInFilter.js';
 import InvoiceInDescriptorMenu from './InvoiceInDescriptorMenu.vue';
@@ -17,20 +17,16 @@ const { t } = useI18n();
 const cardDescriptorRef = ref();
 const entityId = computed(() => $props.id || +currentRoute.value.params.id);
 const totalAmount = ref();
-const config = ref();
-const cplusRectificationTypes = ref([]);
-const siiTypeInvoiceIns = ref([]);
-const invoiceCorrectionTypes = ref([]);
 const invoiceInCorrection = reactive({ correcting: [], corrected: null });
 const routes = reactive({
     getSupplier: (id) => {
         return { name: 'SupplierCard', params: { id } };
     },
-    getTickets: (id) => {
+    getInvoices: (id) => {
         return {
             name: 'InvoiceInList',
             query: {
-                params: JSON.stringify({ supplierFk: id }),
+                table: JSON.stringify({ supplierFk: id }),
             },
         };
     },
@@ -39,7 +35,7 @@ const routes = reactive({
             return {
                 name: 'InvoiceInList',
                 query: {
-                    params: JSON.stringify({ correctedFk: entityId.value }),
+                    table: JSON.stringify({ correctedFk: entityId.value }),
                 },
             };
         }
@@ -88,7 +84,7 @@ async function setInvoiceCorrection(id) {
 }
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         ref="cardDescriptorRef"
         data-key="InvoiceIn"
         :url="`InvoiceIns/${entityId}`"
@@ -108,7 +104,7 @@ async function setInvoiceCorrection(id) {
             <VnLv :label="t('invoiceIn.list.amount')" :value="toCurrency(totalAmount)" />
             <VnLv :label="t('invoiceIn.list.supplier')">
                 <template #value>
-                    <span class="link">
+                    <span class="link" data-cy="invoiceInDescriptor_supplier">
                         {{ entity?.supplier?.nickname }}
                         <SupplierDescriptorProxy :id="entity?.supplierFk" />
                     </span>
@@ -135,11 +131,11 @@ async function setInvoiceCorrection(id) {
                 </QBtn>
                 <QBtn
                     size="md"
-                    icon="vn:ticket"
+                    icon="vn:invoice-in"
                     color="primary"
-                    :to="routes.getTickets(entity.supplierFk)"
+                    :to="routes.getInvoices(entity.supplierFk)"
                 >
-                    <QTooltip>{{ t('globals.ticketList') }}</QTooltip>
+                    <QTooltip>{{ t('invoiceIn.descriptor.invoices') }}</QTooltip>
                 </QBtn>
                 <QBtn
                     v-if="
@@ -163,7 +159,7 @@ async function setInvoiceCorrection(id) {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <style lang="scss" scoped>
 .q-dialog {
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
index 8b039ec27..058f17d31 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, computed, toRefs, reactive } from 'vue';
+import { ref, computed, toRefs, reactive, onBeforeMount } from 'vue';
 import { useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { useQuasar } from 'quasar';
@@ -111,10 +111,9 @@ async function cloneInvoice() {
 }
 
 const isAgricultural = () => {
-    if (!config.value) return false;
     return (
-        invoiceIn.value?.supplier?.sageFarmerWithholdingFk ===
-        config?.value[0]?.sageWithholdingFk
+        invoiceIn.value?.supplier?.sageWithholdingFk ==
+        config.value?.sageFarmerWithholdingFk
     );
 };
 function showPdfInvoice() {
@@ -153,162 +152,183 @@ const createInvoiceInCorrection = async () => {
     );
     push({ path: `/invoice-in/${correctingId}/summary` });
 };
+
+onBeforeMount(async () => {
+    config.value = (
+        await axios.get('invoiceinConfigs/findOne', {
+            params: { fields: ['sageFarmerWithholdingFk'] },
+        })
+    ).data;
+});
 </script>
-
 <template>
-    <FetchData
-        url="InvoiceCorrectionTypes"
-        @on-fetch="(data) => (invoiceCorrectionTypes = data)"
-        auto-load
-    />
-    <FetchData
-        url="CplusRectificationTypes"
-        @on-fetch="(data) => (cplusRectificationTypes = data)"
-        auto-load
-    />
-    <FetchData
-        url="SiiTypeInvoiceIns"
-        :where="{ code: { like: 'R%' } }"
-        @on-fetch="(data) => (siiTypeInvoiceIns = data)"
-        auto-load
-    />
-    <FetchData
-        url="InvoiceInConfigs"
-        :where="{ fields: ['sageWithholdingFk'] }"
-        auto-load
-        @on-fetch="(data) => (config = data)"
-    />
-    <InvoiceInToBook>
-        <template #content="{ book }">
-            <QItem
-                v-if="!invoice?.isBooked && canEditProp('toBook')"
-                v-ripple
-                clickable
-                @click="book(entityId)"
+    <template v-if="config">
+        <FetchData
+            url="InvoiceCorrectionTypes"
+            @on-fetch="(data) => (invoiceCorrectionTypes = data)"
+            auto-load
+        />
+        <FetchData
+            url="CplusRectificationTypes"
+            @on-fetch="(data) => (cplusRectificationTypes = data)"
+            auto-load
+        />
+        <FetchData
+            url="SiiTypeInvoiceIns"
+            :where="{ code: { like: 'R%' } }"
+            @on-fetch="(data) => (siiTypeInvoiceIns = data)"
+            auto-load
+        />
+        <InvoiceInToBook>
+            <template #content="{ book }">
+                <QItem
+                    v-if="!invoice?.isBooked && canEditProp('toBook')"
+                    v-ripple
+                    clickable
+                    @click="book(entityId)"
+                >
+                    <QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
+                </QItem>
+            </template>
+        </InvoiceInToBook>
+        <QItem
+            v-if="invoice?.isBooked && canEditProp('toUnbook')"
+            v-ripple
+            clickable
+            @click="triggerMenu('unbook')"
+        >
+            <QItemSection>
+                {{ t('invoiceIn.descriptorMenu.unbook') }}
+            </QItemSection>
+        </QItem>
+        <QItem
+            v-if="canEditProp('deleteById')"
+            v-ripple
+            clickable
+            @click="triggerMenu('delete')"
+        >
+            <QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
+        </QItem>
+        <QItem
+            v-if="canEditProp('clone')"
+            v-ripple
+            clickable
+            @click="triggerMenu('clone')"
+        >
+            <QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
+        </QItem>
+        <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
+            <QItemSection>{{
+                t('invoiceIn.descriptorMenu.showAgriculturalPdf')
+            }}</QItemSection>
+        </QItem>
+        <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
+            <QItemSection
+                >{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
             >
-                <QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
-            </QItem>
-        </template>
-    </InvoiceInToBook>
-    <QItem
-        v-if="invoice?.isBooked && canEditProp('toUnbook')"
-        v-ripple
-        clickable
-        @click="triggerMenu('unbook')"
-    >
-        <QItemSection>
-            {{ t('invoiceIn.descriptorMenu.unbook') }}
-        </QItemSection>
-    </QItem>
-    <QItem
-        v-if="canEditProp('deleteById')"
-        v-ripple
-        clickable
-        @click="triggerMenu('delete')"
-    >
-        <QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
-    </QItem>
-    <QItem v-if="canEditProp('clone')" v-ripple clickable @click="triggerMenu('clone')">
-        <QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
-    </QItem>
-    <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
-        <QItemSection>{{
-            t('invoiceIn.descriptorMenu.showAgriculturalPdf')
-        }}</QItemSection>
-    </QItem>
-    <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
-        <QItemSection
-            >{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
+        </QItem>
+        <QItem
+            v-if="!invoiceInCorrection.corrected"
+            v-ripple
+            clickable
+            @click="triggerMenu('correct')"
+            data-cy="createCorrectiveItem"
         >
-    </QItem>
-    <QItem
-        v-if="!invoiceInCorrection.corrected"
-        v-ripple
-        clickable
-        @click="triggerMenu('correct')"
-        data-cy="createCorrectiveItem"
-    >
-        <QItemSection
-            >{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
+            <QItemSection
+                >{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
+            >
+        </QItem>
+        <QItem
+            v-if="invoice.dmsFk"
+            v-ripple
+            clickable
+            @click="downloadFile(invoice.dmsFk)"
         >
-    </QItem>
-    <QItem v-if="invoice.dmsFk" v-ripple clickable @click="downloadFile(invoice.dmsFk)">
-        <QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
-    </QItem>
-    <QDialog ref="correctionDialogRef">
-        <QCard>
-            <QCardSection>
-                <QItem class="q-px-none">
-                    <span class="text-primary text-h6 full-width">
-                        {{ t('Create rectificative invoice') }}
-                    </span>
-                    <QBtn icon="close" flat round dense v-close-popup />
-                </QItem>
-            </QCardSection>
-            <QCardSection>
-                <QItem>
-                    <QItemSection>
-                        <QInput
-                            :label="t('Original invoice')"
-                            v-model="entityId"
-                            readonly
-                        />
-                        <VnSelect
-                            :label="`${useCapitalize(t('globals.class'))}`"
-                            v-model="correctionFormData.invoiceClass"
-                            :options="siiTypeInvoiceIns"
-                            option-value="id"
-                            option-label="code"
-                            :required="true"
-                        />
-                    </QItemSection>
-                    <QItemSection>
-                        <VnSelect
-                            :label="`${useCapitalize(t('globals.type'))}`"
-                            v-model="correctionFormData.invoiceType"
-                            :options="cplusRectificationTypes"
-                            option-value="id"
-                            option-label="description"
-                            :required="true"
-                        >
-                            <template #option="{ itemProps, opt }">
-                                <QItem v-bind="itemProps">
-                                    <QItemSection>
-                                        <QItemLabel
-                                            >{{ opt.id }} -
-                                            {{ opt.description }}</QItemLabel
-                                        >
-                                    </QItemSection>
-                                </QItem>
-                                <div></div>
-                            </template>
-                        </VnSelect>
+            <QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
+        </QItem>
+        <QDialog ref="correctionDialogRef">
+            <QCard data-cy="correctiveInvoiceDialog">
+                <QCardSection>
+                    <QItem class="q-px-none">
+                        <span class="text-primary text-h6 full-width">
+                            {{ t('Create rectificative invoice') }}
+                        </span>
+                        <QBtn icon="close" flat round dense v-close-popup />
+                    </QItem>
+                </QCardSection>
+                <QCardSection>
+                    <QItem>
+                        <QItemSection>
+                            <QInput
+                                :label="t('Original invoice')"
+                                v-model="entityId"
+                                readonly
+                            />
+                            <VnSelect
+                                :label="`${useCapitalize(t('globals.class'))}`"
+                                v-model="correctionFormData.invoiceClass"
+                                :options="siiTypeInvoiceIns"
+                                option-value="id"
+                                option-label="code"
+                                :required="true"
+                                data-cy="invoiceInDescriptorMenu_class"
+                            />
+                        </QItemSection>
+                        <QItemSection>
+                            <VnSelect
+                                :label="`${useCapitalize(t('globals.type'))}`"
+                                v-model="correctionFormData.invoiceType"
+                                :options="cplusRectificationTypes"
+                                option-value="id"
+                                option-label="description"
+                                :required="true"
+                                data-cy="invoiceInDescriptorMenu_type"
+                            >
+                                <template #option="{ itemProps, opt }">
+                                    <QItem v-bind="itemProps">
+                                        <QItemSection>
+                                            <QItemLabel
+                                                >{{ opt.id }} -
+                                                {{ opt.description }}</QItemLabel
+                                            >
+                                        </QItemSection>
+                                    </QItem>
+                                    <div></div>
+                                </template>
+                            </VnSelect>
 
-                        <VnSelect
-                            :label="`${useCapitalize(t('globals.reason'))}`"
-                            v-model="correctionFormData.invoiceReason"
-                            :options="invoiceCorrectionTypes"
-                            option-value="id"
-                            option-label="description"
-                            :required="true"
-                        />
-                    </QItemSection>
-                </QItem>
-            </QCardSection>
-            <QCardActions class="justify-end q-mr-sm">
-                <QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
-                <QBtn
-                    :label="t('globals.save')"
-                    color="primary"
-                    v-close-popup
-                    @click="createInvoiceInCorrection"
-                    :disable="isNotFilled"
-                />
-            </QCardActions>
-        </QCard>
-    </QDialog>
+                            <VnSelect
+                                :label="`${useCapitalize(t('globals.reason'))}`"
+                                v-model="correctionFormData.invoiceReason"
+                                :options="invoiceCorrectionTypes"
+                                option-value="id"
+                                option-label="description"
+                                :required="true"
+                                data-cy="invoiceInDescriptorMenu_reason"
+                            />
+                        </QItemSection>
+                    </QItem>
+                </QCardSection>
+                <QCardActions class="justify-end q-mr-sm">
+                    <QBtn
+                        flat
+                        :label="t('globals.close')"
+                        color="primary"
+                        v-close-popup
+                    />
+                    <QBtn
+                        :label="t('globals.save')"
+                        color="primary"
+                        v-close-popup
+                        @click="createInvoiceInCorrection"
+                        :disable="isNotFilled"
+                        data-cy="saveCorrectiveInvoice"
+                    />
+                </QCardActions>
+            </QCard>
+        </QDialog>
+    </template>
 </template>
-
 <i18n>
 en:
     isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
index 20cc1cc71..59bebcae2 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
@@ -25,7 +25,8 @@ const invoiceInFormRef = ref();
 const invoiceId = +route.params.id;
 const filter = { where: { invoiceInFk: invoiceId } };
 const areRows = ref(false);
-const totals = ref();
+const totalTaxableBase = ref();
+const noMatch = computed(() => totalAmount.value != totalTaxableBase.value);
 const columns = computed(() => [
     {
         name: 'duedate',
@@ -74,9 +75,12 @@ async function insert() {
     notify(t('globals.dataSaved'), 'positive');
 }
 
-onBeforeMount(async () => {
-    totals.value = (await axios.get(`InvoiceIns/${invoiceId}/getTotals`)).data;
-});
+async function setTaxableBase() {
+    const { data } = await axios.get(`InvoiceIns/${invoiceId}/getTotals`);
+    totalTaxableBase.value = data.totalTaxableBase;
+}
+
+onBeforeMount(async () => await setTaxableBase());
 </script>
 <template>
     <CrudModel
@@ -89,13 +93,14 @@ onBeforeMount(async () => {
         :data-required="{ invoiceInFk: invoiceId }"
         v-model:selected="rowsSelected"
         @on-fetch="(data) => (areRows = !!data.length)"
+        @save-changes="setTaxableBase"
     >
         <template #body="{ rows }">
             <QTable
                 v-model:selected="rowsSelected"
                 selection="multiple"
-                :columns="columns"
-                :rows="rows"
+                :columns
+                :rows
                 row-key="$index"
                 :grid="$q.screen.lt.sm"
             >
@@ -151,7 +156,18 @@ onBeforeMount(async () => {
                         <QTd />
                         <QTd />
                         <QTd>
-                            {{ toCurrency(totalAmount) }}
+                            <QChip
+                                dense
+                                :color="noMatch ? 'negative' : 'transparent'"
+                                class="q-pa-xs"
+                                :title="
+                                    noMatch
+                                        ? t('invoiceIn.noMatch', { totalTaxableBase })
+                                        : ''
+                                "
+                            >
+                                {{ toCurrency(totalAmount) }}
+                            </QChip>
                         </QTd>
                         <QTd>
                             <template v-if="isNotEuro(invoiceIn.currency.code)">
@@ -237,7 +253,7 @@ onBeforeMount(async () => {
                     if (!areRows) insert();
                     else
                         invoiceInFormRef.insert({
-                            amount: (totals.totalTaxableBase - totalAmount).toFixed(2),
+                            amount: (totalTaxableBase - totalAmount).toFixed(2),
                             invoiceInFk: invoiceId,
                         });
                 }
@@ -249,6 +265,10 @@ onBeforeMount(async () => {
 .bg {
     background-color: var(--vn-light-gray);
 }
+
+.q-chip {
+    color: var(--vn-text-color);
+}
 </style>
 <i18n>
     es:
diff --git a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
index 18602f043..74936f00a 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
@@ -40,6 +40,13 @@ const vatColumns = ref([
         sortable: true,
         align: 'left',
     },
+    {
+        name: 'isDeductible',
+        label: 'invoiceIn.isDeductible',
+        field: (row) => row.isDeductible,
+        sortable: true,
+        align: 'center',
+    },
     {
         name: 'vat',
         label: 'invoiceIn.summary.sageVat',
@@ -198,6 +205,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
                         color="orange-11"
                         text-color="black"
                         @click="book(entityId)"
+                        data-cy="invoiceInSummary_book"
                     />
                 </template>
             </InvoiceIntoBook>
@@ -206,113 +214,109 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
             <InvoiceInDescriptorMenu :invoice="entity" />
         </template>
         <template #body="{ entity }">
-            <!--Basic Data-->
-            <QCard class="vn-one">
-                <QCardSection class="q-pa-none">
-                    <VnTitle
-                        :url="getLink('basic-data')"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                </QCardSection>
-                <VnLv
-                    :label="t('invoiceIn.list.supplier')"
-                    :value="entity.supplier?.name"
-                >
-                    <template #value>
-                        <span class="link">
-                            {{ entity.supplier?.name }}
-                            <SupplierDescriptorProxy :id="entity.supplierFk" />
-                        </span>
-                    </template>
-                </VnLv>
-                <VnLv :label="t('invoiceIn.supplierRef')" :value="entity.supplierRef" />
-                <VnLv
-                    :label="t('invoiceIn.summary.currency')"
-                    :value="entity.currency?.code"
+            <QCard class="max-width">
+                <VnTitle
+                    :url="getLink('basic-data')"
+                    :text="t('globals.pageTitles.basicData')"
                 />
-                <VnLv :label="t('invoiceIn.serial')" :value="`${entity.serial}`" />
-                <VnLv
-                    :label="t('globals.country')"
-                    :value="entity.supplier?.country?.code"
-                />
-            </QCard>
-            <QCard class="vn-one">
-                <QCardSection class="q-pa-none">
-                    <VnTitle
-                        :url="getLink('basic-data')"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                </QCardSection>
-                <VnLv
-                    :ellipsis-value="false"
-                    :label="t('invoiceIn.summary.issued')"
-                    :value="toDate(entity.issued)"
-                />
-                <VnLv
-                    :label="t('invoiceIn.summary.operated')"
-                    :value="toDate(entity.operated)"
-                />
-                <VnLv
-                    :label="t('invoiceIn.summary.bookEntried')"
-                    :value="toDate(entity.bookEntried)"
-                />
-                <VnLv
-                    :label="t('invoiceIn.summary.bookedDate')"
-                    :value="toDate(entity.booked)"
-                />
-                <VnLv :label="t('globals.isVies')" :value="entity.supplier?.isVies" />
-            </QCard>
-            <QCard class="vn-one">
-                <QCardSection class="q-pa-none">
-                    <VnTitle
-                        :url="getLink('basic-data')"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                </QCardSection>
-                <VnLv
-                    :label="t('invoiceIn.summary.sage')"
-                    :value="entity.sageWithholding?.withholding"
-                />
-                <VnLv
-                    :label="t('invoiceIn.summary.vat')"
-                    :value="entity.expenseDeductible?.name"
-                />
-                <VnLv
-                    :label="t('invoiceIn.card.company')"
-                    :value="entity.company?.code"
-                />
-                <VnLv :label="t('invoiceIn.isBooked')" :value="invoiceIn?.isBooked" />
-            </QCard>
-            <QCard class="vn-one">
-                <QCardSection class="q-pa-none">
-                    <VnTitle
-                        :url="getLink('basic-data')"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                </QCardSection>
-                <QCardSection class="q-pa-none">
-                    <VnLv
-                        :label="t('invoiceIn.summary.taxableBase')"
-                        :value="toCurrency(entity.totals.totalTaxableBase)"
-                    />
-                    <VnLv label="Total" :value="toCurrency(entity.totals.totalVat)" />
-                    <VnLv :label="t('invoiceIn.summary.dueTotal')">
-                        <template #value>
-                            <QChip
-                                dense
-                                class="q-pa-xs"
-                                :color="amountsNotMatch ? 'negative' : 'transparent'"
-                                :title="
-                                    amountsNotMatch
-                                        ? t('invoiceIn.summary.noMatch')
-                                        : t('invoiceIn.summary.dueTotal')
-                                "
-                            >
-                                {{ toCurrency(entity.totals.totalDueDay) }}
-                            </QChip>
-                        </template>
-                    </VnLv>
-                </QCardSection>
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('invoiceIn.list.supplier')"
+                            :value="entity.supplier?.name"
+                        >
+                            <template #value>
+                                <span class="link" data-cy="invoiceInSummary_supplier">
+                                    {{ entity.supplier?.name }}
+                                    <SupplierDescriptorProxy :id="entity.supplierFk" />
+                                </span>
+                            </template>
+                        </VnLv>
+                        <VnLv
+                            :label="t('invoiceIn.supplierRef')"
+                            :value="entity.supplierRef"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.summary.currency')"
+                            :value="entity.currency?.code"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.serial')"
+                            :value="`${entity.serial}`"
+                        />
+                        <VnLv
+                            :label="t('globals.country')"
+                            :value="entity.supplier?.country?.code"
+                        />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv
+                            :ellipsis-value="false"
+                            :label="t('invoiceIn.summary.issued')"
+                            :value="toDate(entity.issued)"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.summary.operated')"
+                            :value="toDate(entity.operated)"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.summary.bookEntried')"
+                            :value="toDate(entity.bookEntried)"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.summary.bookedDate')"
+                            :value="toDate(entity.booked)"
+                        />
+                        <VnLv
+                            :label="t('globals.isVies')"
+                            :value="entity.supplier?.isVies"
+                        />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('invoiceIn.summary.sage')"
+                            :value="entity.sageWithholding?.withholding"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.summary.vat')"
+                            :value="entity.expenseDeductible?.name"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.card.company')"
+                            :value="entity.company?.code"
+                        />
+                        <VnLv
+                            :label="t('invoiceIn.isBooked')"
+                            :value="invoiceIn?.isBooked"
+                        />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('invoiceIn.summary.taxableBase')"
+                            :value="toCurrency(entity.totals.totalTaxableBase)"
+                        />
+                        <VnLv label="Total" :value="toCurrency(entity.totals.totalVat)" />
+                        <VnLv :label="t('invoiceIn.summary.dueTotal')">
+                            <template #value>
+                                <QChip
+                                    dense
+                                    class="q-pa-xs"
+                                    :color="amountsNotMatch ? 'negative' : 'transparent'"
+                                    :title="
+                                        amountsNotMatch
+                                            ? t('invoiceIn.noMatch', {
+                                                  totalTaxableBase:
+                                                      entity.totals.totalTaxableBase,
+                                              })
+                                            : t('invoiceIn.summary.dueTotal')
+                                    "
+                                >
+                                    {{ toCurrency(entity.totals.totalDueDay) }}
+                                </QChip>
+                            </template>
+                        </VnLv>
+                    </div>
+                </div>
             </QCard>
             <!--Vat-->
             <QCard v-if="entity.invoiceInTax.length" class="vat">
@@ -334,6 +338,15 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
                             </QTh>
                         </QTr>
                     </template>
+                    <template #body-cell-isDeductible="{ row }">
+                        <QTd align="center">
+                            <QCheckbox
+                                v-model="row.isDeductible"
+                                disable
+                                data-cy="isDeductible_checkbox"
+                            />
+                        </QTd>
+                    </template>
                     <template #body-cell-vat="{ value: vatCell }">
                         <QTd :title="vatCell" shrink>
                             {{ vatCell }}
diff --git a/src/pages/InvoiceIn/Card/InvoiceInVat.vue b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
index eae255120..61c3040ae 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInVat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
@@ -53,6 +53,13 @@ const columns = computed(() => [
         sortable: true,
         align: 'left',
     },
+    {
+        name: 'isDeductible',
+        label: t('invoiceIn.isDeductible'),
+        field: (row) => row.isDeductible,
+        model: 'isDeductible',
+        align: 'center',
+    },
     {
         name: 'sageiva',
         label: t('Sage iva'),
@@ -119,6 +126,7 @@ const filter = {
         'foreignValue',
         'taxTypeSageFk',
         'transactionTypeSageFk',
+        'isDeductible',
     ],
     where: {
         invoiceInFk: route.params.id,
@@ -202,6 +210,9 @@ function setCursor(ref) {
                             :option-label="col.optionLabel"
                             :filter-options="['id', 'name']"
                             :tooltip="t('Create a new expense')"
+                            :acls="[
+                                { model: 'Expense', props: '*', accessType: 'WRITE' },
+                            ]"
                             @keydown.tab.prevent="
                                 autocompleteExpense(
                                     $event,
@@ -227,6 +238,14 @@ function setCursor(ref) {
                         </VnSelectDialog>
                     </QTd>
                 </template>
+                <template #body-cell-isDeductible="{ row }">
+                    <QTd align="center">
+                        <QCheckbox
+                            v-model="row.isDeductible"
+                            data-cy="isDeductible_checkbox"
+                        />
+                    </QTd>
+                </template>
                 <template #body-cell-taxablebase="{ row }">
                     <QTd shrink>
                         <VnInputNumber
@@ -321,6 +340,7 @@ function setCursor(ref) {
                         </QTd>
                         <QTd />
                         <QTd />
+                        <QTd />
                         <QTd>
                             {{ toCurrency(taxRateTotal) }}
                         </QTd>
diff --git a/src/pages/InvoiceIn/InvoiceInFilter.vue b/src/pages/InvoiceIn/InvoiceInFilter.vue
index e010a1edb..6551a7ca9 100644
--- a/src/pages/InvoiceIn/InvoiceInFilter.vue
+++ b/src/pages/InvoiceIn/InvoiceInFilter.vue
@@ -7,6 +7,7 @@ import VnInputNumber from 'src/components/common/VnInputNumber.vue';
 import { dateRange } from 'src/filters';
 import { date } from 'quasar';
 import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
 
 defineProps({ dataKey: { type: String, required: true } });
 const dateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
@@ -39,17 +40,13 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInputDate
                         :label="$t('globals.from')"
                         v-model="params.from"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInputDate
-                        :label="$t('globals.to')"
-                        v-model="params.to"
-                        is-outlined
-                    />
+                    <VnInputDate :label="$t('globals.to')" v-model="params.to" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -57,7 +54,7 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInputNumber
                         :label="$t('globals.daysAgo')"
                         v-model="params.daysAgo"
-                        is-outlined
+                        filled
                         :step="0"
                         @update:model-value="(val) => handleDaysAgo(params, val)"
                         @remove="(val) => handleDaysAgo(params, val)"
@@ -66,12 +63,7 @@ function handleDaysAgo(params, daysAgo) {
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnSelectSupplier
-                        v-model="params.supplierFk"
-                        dense
-                        outlined
-                        rounded
-                    />
+                    <VnSelectSupplier v-model="params.supplierFk" dense filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -79,7 +71,7 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInput
                         :label="getLocale('supplierRef')"
                         v-model="params.supplierRef"
-                        is-outlined
+                        filled
                         lazy-rules
                     />
                 </QItemSection>
@@ -89,7 +81,7 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInput
                         :label="getLocale('fi')"
                         v-model="params.fi"
-                        is-outlined
+                        filled
                         lazy-rules
                     />
                 </QItemSection>
@@ -99,7 +91,7 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInput
                         :label="getLocale('serial')"
                         v-model="params.serial"
-                        is-outlined
+                        filled
                         lazy-rules
                     />
                 </QItemSection>
@@ -109,7 +101,7 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInput
                         :label="getLocale('account')"
                         v-model="params.account"
-                        is-outlined
+                        filled
                         lazy-rules
                     />
                 </QItemSection>
@@ -119,7 +111,7 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInput
                         :label="getLocale('globals.params.awbCode')"
                         v-model="params.awbCode"
-                        is-outlined
+                        filled
                         lazy-rules
                     />
                 </QItemSection>
@@ -129,7 +121,7 @@ function handleDaysAgo(params, daysAgo) {
                     <VnInputNumber
                         :label="$t('globals.amount')"
                         v-model="params.amount"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -141,19 +133,19 @@ function handleDaysAgo(params, daysAgo) {
                         url="Companies"
                         option-label="code"
                         :fields="['id', 'code']"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <QCheckbox
+                    <VnCheckbox
                         :label="$t('invoiceIn.isBooked')"
                         v-model="params.isBooked"
                         @update:model-value="searchFn()"
                         toggle-indeterminate
                     />
-                    <QCheckbox
+                    <VnCheckbox
                         :label="getLocale('params.correctingFk')"
                         v-model="params.correctingFk"
                         @update:model-value="searchFn()"
diff --git a/src/pages/InvoiceIn/InvoiceInList.vue b/src/pages/InvoiceIn/InvoiceInList.vue
index 0960d0d6c..10ddcbf05 100644
--- a/src/pages/InvoiceIn/InvoiceInList.vue
+++ b/src/pages/InvoiceIn/InvoiceInList.vue
@@ -119,7 +119,7 @@ const cols = computed(() => [
                 icon: 'preview',
                 type: 'submit',
                 isPrimary: true,
-                action: (row) => viewSummary(row.id, InvoiceInSummary),
+                action: (row) => viewSummary(row.id, InvoiceInSummary, 'lg-width'),
             },
             {
                 title: t('globals.download'),
@@ -156,7 +156,7 @@ const cols = computed(() => [
                 :create="{
                     urlCreate: 'InvoiceIns',
                     title: t('globals.createInvoiceIn'),
-                    onDataSaved: ({ id }) => tableRef.redirect(id),
+                    onDataSaved: ({ id }) => tableRef.redirect(`${id}/basic-data`),
                     formInitialData: { companyFk: user.companyFk, issued: Date.vnNew() },
                 }"
                 redirect="invoice-in"
diff --git a/src/pages/InvoiceIn/InvoiceInToBook.vue b/src/pages/InvoiceIn/InvoiceInToBook.vue
index 5bdbe197b..28f54f040 100644
--- a/src/pages/InvoiceIn/InvoiceInToBook.vue
+++ b/src/pages/InvoiceIn/InvoiceInToBook.vue
@@ -4,7 +4,7 @@ import { useQuasar } from 'quasar';
 import { useI18n } from 'vue-i18n';
 import VnConfirm from 'src/components/ui/VnConfirm.vue';
 import { useArrayData } from 'src/composables/useArrayData';
-import qs from 'qs';
+
 const { notify, dialog } = useQuasar();
 const { t } = useI18n();
 
@@ -56,22 +56,21 @@ async function checkToBook(id) {
             componentProps: {
                 title: t('Are you sure you want to book this invoice?'),
                 message: messages.reduce((acc, msg) => `${acc}<p>${msg}</p>`, ''),
+                promise: () => toBook(id),
             },
-        }).onOk(() => toBook(id));
+        });
 }
 
 async function toBook(id) {
-    let type = 'positive';
-    let message = t('globals.dataSaved');
-
+    let err = false;
     try {
         await axios.post(`InvoiceIns/${id}/toBook`);
         store.data.isBooked = true;
     } catch (e) {
-        type = 'negative';
-        message = t('It was not able to book the invoice');
+        err = true;
+        throw e;
     } finally {
-        notify({ type, message });
+        if (!err) notify({ type: 'positive', message: t('globals.dataSaved') });
     }
 }
 </script>
diff --git a/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue b/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue
index 19ed73e50..66b7fa433 100644
--- a/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue
+++ b/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue
@@ -25,8 +25,7 @@ const { t } = useI18n();
                     <VnInputNumber
                         v-model="params.daysAgo"
                         :label="t('params.daysAgo')"
-                        outlined
-                        rounded
+                        filled
                         dense
                     />
                 </QItemSection>
@@ -36,8 +35,7 @@ const { t } = useI18n();
                     <VnInput
                         v-model="params.serial"
                         :label="t('params.serial')"
-                        outlined
-                        rounded
+                        filled
                         dense
                     />
                 </QItemSection>
diff --git a/src/pages/InvoiceIn/locale/en.yml b/src/pages/InvoiceIn/locale/en.yml
index 548e6c201..a7a8d2469 100644
--- a/src/pages/InvoiceIn/locale/en.yml
+++ b/src/pages/InvoiceIn/locale/en.yml
@@ -4,6 +4,7 @@ invoiceIn:
     serial: Serial
     isBooked: Is booked
     supplierRef: Invoice nº
+    isDeductible: Deductible
     list:
         ref: Reference
         supplier: Supplier
@@ -14,6 +15,7 @@ invoiceIn:
         amount: Amount
     descriptor:
         ticketList: Ticket list
+        invoices: Supplier invoices
     descriptorMenu:
         book: Book
         unbook: Unbook
@@ -57,7 +59,6 @@ invoiceIn:
         bank: Bank
         foreignValue: Foreign value
         dueTotal: Due day
-        noMatch: Do not match
         code: Code
         net: Net
         stems: Stems
@@ -68,3 +69,4 @@ invoiceIn:
         isBooked: Is booked
         account: Ledger account
         correctingFk: Rectificative
+    noMatch: No match with the vat({totalTaxableBase})
diff --git a/src/pages/InvoiceIn/locale/es.yml b/src/pages/InvoiceIn/locale/es.yml
index 142d95f92..c593f5a08 100644
--- a/src/pages/InvoiceIn/locale/es.yml
+++ b/src/pages/InvoiceIn/locale/es.yml
@@ -4,6 +4,7 @@ invoiceIn:
     serial: Serie
     isBooked: Contabilizada
     supplierRef: Nº factura
+    isDeductible: Deducible
     list:
         ref: Referencia
         supplier: Proveedor
@@ -13,7 +14,7 @@ invoiceIn:
         awb: AWB
         amount: Importe
     descriptor:
-        ticketList: Listado de tickets
+        invoices: Facturas de proveedor
     descriptorMenu:
         book: Contabilizar
         unbook: Descontabilizar
@@ -66,3 +67,4 @@ invoiceIn:
         isBooked: Contabilizada
         account: Cuenta contable
         correctingFk: Rectificativa
+    noMatch: No cuadra con el iva({totalTaxableBase})
diff --git a/src/pages/InvoiceOut/Card/InvoiceOutCard.vue b/src/pages/InvoiceOut/Card/InvoiceOutCard.vue
index a50c9d247..cdb736555 100644
--- a/src/pages/InvoiceOut/Card/InvoiceOutCard.vue
+++ b/src/pages/InvoiceOut/Card/InvoiceOutCard.vue
@@ -1,10 +1,10 @@
 <script setup>
 import InvoiceOutDescriptor from './InvoiceOutDescriptor.vue';
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import filter from './InvoiceOutFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="InvoiceOut"
         url="InvoiceOuts"
         :filter="filter"
diff --git a/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue b/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue
index 9b5215986..b93b8c8b7 100644
--- a/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue
+++ b/src/pages/InvoiceOut/Card/InvoiceOutDescriptor.vue
@@ -3,7 +3,7 @@ import { ref, computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import InvoiceOutDescriptorMenu from './InvoiceOutDescriptorMenu.vue';
@@ -34,7 +34,7 @@ function ticketFilter(invoice) {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         ref="descriptor"
         :url="`InvoiceOuts/${entityId}`"
         :filter="filter"
@@ -46,6 +46,11 @@ function ticketFilter(invoice) {
             <InvoiceOutDescriptorMenu :invoice-out-data="entity" :menu-ref="menuRef" />
         </template>
         <template #body="{ entity }">
+            <VnLv
+                v-if="entity.externalRef"
+                :label="t('invoiceOut.externalRef')"
+                :value="entity.externalRef"
+            />
             <VnLv :label="t('invoiceOut.card.issued')" :value="toDate(entity.issued)" />
             <VnLv :label="t('globals.amount')" :value="toCurrency(entity.amount)" />
             <VnLv v-if="entity.client" :label="t('globals.client')">
@@ -88,5 +93,5 @@ function ticketFilter(invoice) {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
diff --git a/src/pages/InvoiceOut/InvoiceOutFilter.vue b/src/pages/InvoiceOut/InvoiceOutFilter.vue
index 648b8e4e6..93a343565 100644
--- a/src/pages/InvoiceOut/InvoiceOutFilter.vue
+++ b/src/pages/InvoiceOut/InvoiceOutFilter.vue
@@ -7,6 +7,7 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import VnInputDate from 'components/common/VnInputDate.vue';
 import VnInputNumber from 'src/components/common/VnInputNumber.vue';
+import VnSelect from 'src/components/common/VnSelect.vue';
 
 const { t } = useI18n();
 const props = defineProps({
@@ -30,23 +31,23 @@ const states = ref();
             <QItem>
                 <QItemSection>
                     <VnInput
-                        :label="t('Customer ID')"
+                        :label="t('globals.params.clientFk')"
                         v-model="params.clientFk"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput v-model="params.fi" :label="t('FI')" is-outlined />
+                    <VnInput v-model="params.fi" :label="t('globals.params.fi')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
                     <VnInputNumber
-                        :label="t('Amount')"
+                        :label="t('globals.amount')"
                         v-model="params.amount"
-                        is-outlined
+                        filled
                         data-cy="InvoiceOutFilterAmountBtn"
                     />
                 </QItemSection>
@@ -54,22 +55,20 @@ const states = ref();
             <QItem>
                 <QItemSection>
                     <QInput
-                        :label="t('Min')"
+                        :label="t('invoiceOut.params.min')"
                         dense
                         lazy-rules
-                        outlined
-                        rounded
+                        filled
                         type="number"
                         v-model.number="params.min"
                     />
                 </QItemSection>
                 <QItemSection>
                     <QInput
-                        :label="t('Max')"
+                        :label="t('invoiceOut.params.max')"
                         dense
                         lazy-rules
-                        outlined
-                        rounded
+                        filled
                         type="number"
                         v-model.number="params.max"
                     />
@@ -78,7 +77,7 @@ const states = ref();
             <QItem>
                 <QItemSection>
                     <QCheckbox
-                        :label="t('Has PDF')"
+                        :label="t('invoiceOut.params.hasPdf')"
                         toggle-indeterminate
                         v-model="params.hasPdf"
                     />
@@ -88,14 +87,30 @@ const states = ref();
                 <QItemSection>
                     <VnInputDate
                         v-model="params.created"
-                        :label="t('Created')"
-                        is-outlined
+                        :label="t('invoiceOut.params.created')"
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInputDate v-model="params.dued" :label="t('Dued')" is-outlined />
+                    <VnInputDate
+                        v-model="params.dued"
+                        :label="t('invoiceOut.params.dued')"
+                        filled
+                    />
+                </QItemSection>
+            </QItem>
+            <QItem>
+                <QItemSection>
+                    <VnSelect
+                        filled
+                        :label="t('globals.params.departmentFk')"
+                        v-model="params.departmentFk"
+                        option-value="id"
+                        option-label="name"
+                        url="Departments"
+                    />
                 </QItemSection>
             </QItem>
         </template>
diff --git a/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue b/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue
index 392256473..53433c56b 100644
--- a/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue
+++ b/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue
@@ -26,7 +26,7 @@ const serialTypesOptions = ref([]);
 
 const handleInvoiceOutSerialsFetch = (data) => {
     serialTypesOptions.value = Array.from(
-        new Set(data.map((item) => item.type).filter((type) => type))
+        new Set(data.map((item) => item.type).filter((type) => type)),
     );
 };
 
@@ -99,8 +99,7 @@ onMounted(async () => {
                 option-label="name"
                 hide-selected
                 dense
-                outlined
-                rounded
+                filled
                 data-cy="InvoiceOutGlobalClientSelect"
             >
                 <template #option="scope">
@@ -124,19 +123,18 @@ onMounted(async () => {
                 option-label="type"
                 hide-selected
                 dense
-                outlined
-                rounded
+                filled
                 data-cy="InvoiceOutGlobalSerialSelect"
             />
             <VnInputDate
                 v-model="formData.invoiceDate"
                 :label="t('invoiceDate')"
-                is-outlined
+                filled
             />
             <VnInputDate
                 v-model="formData.maxShipped"
                 :label="t('maxShipped')"
-                is-outlined
+                filled
                 data-cy="InvoiceOutGlobalMaxShippedDate"
             />
             <VnSelect
@@ -145,8 +143,7 @@ onMounted(async () => {
                 :options="companiesOptions"
                 option-label="code"
                 dense
-                outlined
-                rounded
+                filled
                 data-cy="InvoiceOutGlobalCompanySelect"
             />
             <VnSelect
@@ -154,8 +151,7 @@ onMounted(async () => {
                 v-model="formData.printer"
                 :options="printersOptions"
                 dense
-                outlined
-                rounded
+                filled
                 data-cy="InvoiceOutGlobalPrinterSelect"
             />
         </div>
@@ -166,7 +162,7 @@ onMounted(async () => {
             color="primary"
             class="q-mt-md full-width"
             unelevated
-            rounded
+            filled
             dense
         />
         <QBtn
@@ -175,7 +171,7 @@ onMounted(async () => {
             color="primary"
             class="q-mt-md full-width"
             unelevated
-            rounded
+            filled
             dense
             @click="getStatus = 'stopping'"
         />
diff --git a/src/pages/InvoiceOut/InvoiceOutList.vue b/src/pages/InvoiceOut/InvoiceOutList.vue
index a6ec9923e..c87428a94 100644
--- a/src/pages/InvoiceOut/InvoiceOutList.vue
+++ b/src/pages/InvoiceOut/InvoiceOutList.vue
@@ -8,7 +8,7 @@ import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 import { usePrintService } from 'src/composables/usePrintService';
 import VnTable from 'src/components/VnTable/VnTable.vue';
 import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
-import { toCurrency, toDate } from 'src/filters/index';
+import { toCurrency, toDate, dashIfEmpty } from 'src/filters/index';
 import { QBtn } from 'quasar';
 import axios from 'axios';
 import InvoiceOutFilter from './InvoiceOutFilter.vue';
@@ -16,6 +16,7 @@ import VnRow from 'src/components/ui/VnRow.vue';
 import VnRadio from 'src/components/common/VnRadio.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from '../Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import VnSection from 'src/components/common/VnSection.vue';
 
 const { t } = useI18n();
@@ -54,6 +55,14 @@ const columns = computed(() => [
             name: 'id',
         },
     },
+    {
+        align: 'left',
+        name: 'issued',
+        label: t('invoiceOut.summary.issued'),
+        component: 'date',
+        format: (row) => toDate(row.issued),
+        columnField: { component: null },
+    },
     {
         align: 'left',
         name: 'ref',
@@ -70,6 +79,30 @@ const columns = computed(() => [
             inWhere: true,
         },
     },
+    {
+        align: 'left',
+        name: 'issued',
+        label: t('invoiceOut.summary.issued'),
+        component: 'date',
+        format: (row) => toDate(row.issued),
+        columnField: { component: null },
+    },
+    {
+        align: 'left',
+        name: 'created',
+        label: t('globals.created'),
+        component: 'date',
+        columnField: { component: null },
+        format: (row) => toDate(row.created),
+    },
+    {
+        align: 'left',
+        name: 'dued',
+        label: t('invoiceOut.summary.expirationDate'),
+        component: 'date',
+        columnField: { component: null },
+        format: (row) => toDate(row.dued),
+    },
     {
         align: 'left',
         name: 'clientFk',
@@ -86,6 +119,20 @@ const columns = computed(() => [
             component: null,
         },
     },
+    {
+        align: 'left',
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
+        cardVisible: true,
+        component: 'select',
+        attrs: {
+            url: 'Departments',
+        },
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
+    },
     {
         align: 'left',
         name: 'companyFk',
@@ -109,22 +156,6 @@ const columns = computed(() => [
         cardVisible: true,
         format: (row) => toCurrency(row.amount),
     },
-    {
-        align: 'left',
-        name: 'created',
-        label: t('globals.created'),
-        component: 'date',
-        columnField: { component: null },
-        format: (row) => toDate(row.created),
-    },
-    {
-        align: 'left',
-        name: 'dued',
-        label: t('invoiceOut.summary.dued'),
-        component: 'date',
-        columnField: { component: null },
-        format: (row) => toDate(row.dued),
-    },
     {
         align: 'left',
         name: 'customsAgentFk',
@@ -185,7 +216,7 @@ watchEffect(selectedRows);
         prefix="invoiceOut"
         :array-data-props="{
             url: 'InvoiceOuts/filter',
-            order: ['id DESC'],
+            order: 'id DESC',
         }"
     >
         <template #advanced-menu>
@@ -229,8 +260,14 @@ watchEffect(selectedRows);
                         <CustomerDescriptorProxy :id="row.clientFk" />
                     </span>
                 </template>
+                <template #column-departmentFk="{ row }">
+                    <span class="link" @click.stop>
+                        {{ dashIfEmpty(row.departmentName) }}
+                        <DepartmentDescriptorProxy :id="row?.departmentFk" />
+                    </span>
+                </template>
                 <template #more-create-dialog="{ data }">
-                    <div class="row q-col-gutter-xs">
+                    <div class="row q-col-gutter-xs col-span-2">
                         <div class="col-12">
                             <div class="q-col-gutter-xs">
                                 <VnRow fixed>
@@ -396,7 +433,6 @@ watchEffect(selectedRows);
                                     :label="
                                         t('invoiceOutList.tableVisibleColumns.taxArea')
                                     "
-                                    :options="taxAreasOptions"
                                     option-label="code"
                                     option-value="code"
                                 />
diff --git a/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue b/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue
index b062678a0..432cd07d7 100644
--- a/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue
+++ b/src/pages/InvoiceOut/InvoiceOutNegativeBases.vue
@@ -8,7 +8,7 @@ import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js';
 import { useArrayData } from 'src/composables/useArrayData';
 import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
 import TicketDescriptorProxy from '../Ticket/Card/TicketDescriptorProxy.vue';
-import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from '../Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import VnInputDate from 'components/common/VnInputDate.vue';
 import InvoiceOutNegativeBasesFilter from './InvoiceOutNegativeBasesFilter.vue';
 import RightMenu from 'src/components/common/RightMenu.vue';
@@ -115,18 +115,16 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
-        name: 'workerName',
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
         component: 'select',
         attrs: {
-            url: 'Workers/activeWithInheritedRole',
-            fields: ['id', 'name'],
-            where: { role: 'salesPerson' },
+            url: 'Departments',
         },
         columnField: {
             component: null,
         },
-        format: (row, dashIfEmpty) => dashIfEmpty(row.workerName),
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
 ]);
 
@@ -198,10 +196,10 @@ const downloadCSV = async () => {
                 <TicketDescriptorProxy :id="row.ticketFk" />
             </span>
         </template>
-        <template #column-workerName="{ row }">
+        <template #column-departmentFk="{ row }">
             <span class="link" @click.stop>
-                {{ row.workerName }}
-                <WorkerDescriptorProxy :id="row.comercialId" />
+                {{ row.departmentName }}
+                <DepartmentDescriptorProxy :id="row.departmentFk" />
             </span>
         </template>
         <template #moreFilterPanel="{ params }">
diff --git a/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue b/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue
index cd9836bb7..1e2f80ec2 100644
--- a/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue
+++ b/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue
@@ -20,7 +20,7 @@ const props = defineProps({
     <VnFilterPanel
         :data-key="props.dataKey"
         :search-button="true"
-        :un-removable-params="['from', 'to']"
+        :unremovable-params="['from', 'to']"
         :hidden-tags="['from', 'to']"
     >
         <template #tags="{ tag, formatFn }">
@@ -35,17 +35,13 @@ const props = defineProps({
                     <VnInputDate
                         v-model="params.from"
                         :label="t('globals.from')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInputDate
-                        v-model="params.to"
-                        :label="t('globals.to')"
-                        is-outlined
-                    />
+                    <VnInputDate v-model="params.to" :label="t('globals.to')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -57,8 +53,7 @@ const props = defineProps({
                         option-label="code"
                         option-value="code"
                         dense
-                        outlined
-                        rounded
+                        filled
                         @update:model-value="searchFn()"
                     >
                         <template #option="scope">
@@ -84,9 +79,8 @@ const props = defineProps({
                         v-model="params.country"
                         option-label="name"
                         option-value="name"
-                        outlined
                         dense
-                        rounded
+                        filled
                         @update:model-value="searchFn()"
                     >
                         <template #option="scope">
@@ -110,9 +104,8 @@ const props = defineProps({
                         url="Clients"
                         :label="t('globals.client')"
                         v-model="params.clientId"
-                        outlined
                         dense
-                        rounded
+                        filled
                         @update:model-value="searchFn()"
                     />
                 </QItemSection>
@@ -122,19 +115,21 @@ const props = defineProps({
                     <VnInputNumber
                         v-model="params.amount"
                         :label="t('globals.amount')"
-                        is-outlined
+                        filled
                         :positive="false"
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnSelectWorker
-                        :label="t('invoiceOut.negativeBases.comercial')"
-                        v-model="params.workerName"
-                        option-value="name"
-                        is-outlined
-                        @update:model-value="searchFn()"
+                    <VnSelect
+                        dense
+                        filled
+                        :label="t('globals.params.departmentFk')"
+                        v-model="params.departmentFk"
+                        option-value="id"
+                        option-label="name"
+                        url="Departments"
                     />
                 </QItemSection>
             </QItem>
diff --git a/src/pages/InvoiceOut/locale/en.yml b/src/pages/InvoiceOut/locale/en.yml
index 17d198351..9d6a4a244 100644
--- a/src/pages/InvoiceOut/locale/en.yml
+++ b/src/pages/InvoiceOut/locale/en.yml
@@ -1,6 +1,7 @@
 invoiceOut:
     search: Search invoice
     searchInfo: You can search by invoice reference
+    externalRef: External Ref.
     params:
         id: ID
         company: Company
@@ -12,7 +13,6 @@ invoiceOut:
         isActive: Active
         hasToInvoice: Has to invoice
         hasVerifiedData: Verified data
-        workerName: Worker
         isTaxDataChecked: Verified data
         amount: Amount
         clientFk: Client
@@ -26,6 +26,7 @@ invoiceOut:
         max: Max
         hasPdf: Has PDF
         search: Contains
+        departmentFk: Department
     card:
         issued: Issued
         customerCard: Customer card
diff --git a/src/pages/InvoiceOut/locale/es.yml b/src/pages/InvoiceOut/locale/es.yml
index 3df95d6b2..f9448cd9b 100644
--- a/src/pages/InvoiceOut/locale/es.yml
+++ b/src/pages/InvoiceOut/locale/es.yml
@@ -1,6 +1,7 @@
 invoiceOut:
     search: Buscar factura emitida
     searchInfo: Puedes buscar por referencia de la factura
+    externalRef: Ref. externa
     params:
         id: ID
         company: Empresa
@@ -12,7 +13,6 @@ invoiceOut:
         isActive: Activo
         hasToInvoice: Debe facturar
         hasVerifiedData: Datos verificados
-        workerName: Comercial
         isTaxDataChecked: Datos comprobados
         amount: Importe
         clientFk: Cliente
@@ -26,6 +26,7 @@ invoiceOut:
         max: Max
         hasPdf: Tiene PDF
         search: Contiene
+        departmentFk: Departamento
     card:
         issued: Fecha emisión
         customerCard: Ficha del cliente
diff --git a/src/pages/Item/Card/ItemCard.vue b/src/pages/Item/Card/ItemCard.vue
index 610b77a02..ddd21fe36 100644
--- a/src/pages/Item/Card/ItemCard.vue
+++ b/src/pages/Item/Card/ItemCard.vue
@@ -1,9 +1,9 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import ItemDescriptor from './ItemDescriptor.vue';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Item"
         :url="`Items/${$route.params.id}/getCard`"
         :descriptor="ItemDescriptor"
diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index 84e07a293..09f63a3b1 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -3,7 +3,7 @@ import { computed, ref, onMounted } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 
-import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'src/components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 import ItemDescriptorImage from 'src/pages/Item/Card/ItemDescriptorImage.vue';
@@ -90,7 +90,7 @@ const updateStock = async () => {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         data-key="Item"
         :summary="$props.summary"
         :url="`Items/${entityId}/getCard`"
@@ -162,7 +162,7 @@ const updateStock = async () => {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 
 <i18n>
diff --git a/src/pages/Item/Card/ItemDescriptorProxy.vue b/src/pages/Item/Card/ItemDescriptorProxy.vue
index f686e8221..6e1f6d71f 100644
--- a/src/pages/Item/Card/ItemDescriptorProxy.vue
+++ b/src/pages/Item/Card/ItemDescriptorProxy.vue
@@ -22,7 +22,7 @@ const $props = defineProps({
 });
 </script>
 <template>
-    <QPopupProxy style="max-width: 10px">
+    <QPopupProxy style="max-width: 10px" data-cy="ItemDescriptor">
         <ItemDescriptor
             v-if="$props.id"
             :id="$props.id"
diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index fdfa1d3d1..eb156ce9f 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -1,574 +1,386 @@
 <script setup>
-import { onMounted, ref, onUnmounted, nextTick, computed } from 'vue';
+import { onMounted, ref, onUnmounted, computed, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
-import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
-import FetchedTags from 'components/ui/FetchedTags.vue';
-import VnInput from 'src/components/common/VnInput.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
-import VnInputDate from 'src/components/common/VnInputDate.vue';
-import EditTableCellValueForm from 'src/components/EditTableCellValueForm.vue';
-import ItemFixedPriceFilter from './ItemFixedPriceFilter.vue';
-import { useQuasar } from 'quasar';
-import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
-import { tMobile } from 'src/composables/tMobile';
-import VnConfirm from 'components/ui/VnConfirm.vue';
-import FetchData from 'src/components/FetchData.vue';
 import { useStateStore } from 'stores/useStateStore';
-import { toDate } from 'src/filters';
-import { useVnConfirm } from 'composables/useVnConfirm';
 import { useState } from 'src/composables/useState';
-import useNotify from 'src/composables/useNotify.js';
-import axios from 'axios';
-import { isLower, isBigger } from 'src/filters/date.js';
+
+import { beforeSave } from 'src/composables/updateMinPriceBeforeSave';
+
+import FetchedTags from 'components/ui/FetchedTags.vue';
+import VnSelect from 'src/components/common/VnSelect.vue';
+import EditFixedPriceForm from 'src/pages/Item/components/EditFixedPriceForm.vue';
+import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import RightMenu from 'src/components/common/RightMenu.vue';
 import VnTable from 'src/components/VnTable/VnTable.vue';
-import { QCheckbox } from 'quasar';
+import VnColor from 'src/components/common/VnColor.vue';
+
+import { toDate } from 'src/filters';
+import { isLower, isBigger } from 'src/filters/date.js';
+import ItemFixedPriceFilter from './ItemFixedPriceFilter.vue';
+import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
+import { toCurrency } from 'src/filters';
 
-const quasar = useQuasar();
 const stateStore = useStateStore();
 const { t } = useI18n();
-const { openConfirmationModal } = useVnConfirm();
-const state = useState();
-const { notify } = useNotify();
 const tableRef = ref();
-const editTableCellDialogRef = ref(null);
-const user = state.getUser();
-const fixedPrices = ref([]);
-const warehousesOptions = ref([]);
-const hasSelectedRows = computed(() => rowsSelected.value.length > 0);
-const rowsSelected = ref([]);
-const itemFixedPriceFilterRef = ref();
-
+const editFixedPriceForm = ref(null);
+const selectedRows = ref([]);
+const hasSelectedRows = computed(() => selectedRows.value.length > 0);
+const isToClone = ref(false);
+const dateColor = 'var(--vn-label-text-color)';
+const state = useState();
+const user = state.getUser().fn();
+const warehouse = computed(() => user.warehouseFk);
 onMounted(async () => {
     stateStore.rightDrawer = true;
 });
 onUnmounted(() => (stateStore.rightDrawer = false));
 
-const defaultColumnAttrs = {
-    align: 'left',
-    sortable: true,
-};
 const columns = computed(() => [
     {
-        label: t('item.fixedPrice.itemFk'),
         name: 'itemFk',
-        ...defaultColumnAttrs,
-        isId: true,
-        columnField: {
-            component: 'input',
-            type: 'number',
-        },
-        columnClass: 'shrink',
-    },
-    {
-        label: t('globals.name'),
-        name: 'name',
-        ...defaultColumnAttrs,
-        create: true,
+        label: t('item.fixedPrice.itemFk'),
+        labelAbbreviation: 'Id',
+        toolTip: t('item.fixedPrice.itemFk'),
+        component: 'input',
         columnFilter: {
-            component: 'select',
             attrs: {
+                component: 'select',
                 url: 'Items',
                 fields: ['id', 'name', 'subName'],
                 optionLabel: 'name',
-                optionValue: 'name',
+                optionValue: 'id',
                 uppercase: false,
             },
+            inWhere: true,
         },
+        width: '55px',
+        isEditable: false,
+    },
+    {
+        labelAbbreviation: '',
+        name: 'hex',
+        columnSearch: false,
+        isEditable: false,
+        width: '9px',
+        component: 'select',
+        attrs: {
+            url: 'Inks',
+            fields: ['id', 'name'],
+        },
+    },
+    {
+        align: 'left',
+        label: t('globals.name'),
+        name: 'name',
+        create: true,
+        component: 'input',
+        isEditable: false,
     },
     {
         label: t('item.fixedPrice.groupingPrice'),
+        labelAbbreviation: 'P. Group',
+        toolTip: t('item.fixedPrice.groupingPrice'),
         name: 'rate2',
-        ...defaultColumnAttrs,
-        component: 'input',
-        type: 'number',
+        component: 'number',
+        create: true,
+        createOrder: 3,
+        createAttrs: {
+            required: true,
+        },
+        width: '50px',
+        format: (row) => toCurrency(row.rate2),
     },
     {
         label: t('item.fixedPrice.packingPrice'),
+        labelAbbreviation: 'P. Pack',
+        toolTip: t('item.fixedPrice.packingPrice'),
         name: 'rate3',
-        ...defaultColumnAttrs,
-        component: 'input',
-        type: 'number',
+        component: 'number',
+        create: true,
+        createOrder: 4,
+        createAttrs: {
+            required: true,
+        },
+        width: '50px',
+        format: (row) => toCurrency(row.rate3),
+    },
+    {
+        name: 'hasMinPrice',
+        label: t('item.fixedPrice.hasMinPrice'),
+        labelAbbreviation: t('item.fixedPrice.MP'),
+        toolTip: t('item.fixedPrice.hasMinPrice'),
+        label: t('item.fixedPrice.hasMinPrice'),
+        component: 'checkbox',
+        attrs: {
+            toggleIndeterminate: false,
+        },
+        width: '50px',
     },
-
     {
         label: t('item.fixedPrice.minPrice'),
+        labelAbbreviation: 'Min.P',
+        toolTip: t('item.fixedPrice.minPrice'),
         name: 'minPrice',
-        ...defaultColumnAttrs,
-        component: 'input',
-        type: 'number',
+        component: 'number',
+        width: '50px',
+        style: (row) => {
+            if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
+        },
+        format: (row) => toCurrency(row.minPrice),
     },
     {
         label: t('item.fixedPrice.started'),
-        field: 'started',
         name: 'started',
-        format: ({ started }) => toDate(started),
-        ...defaultColumnAttrs,
-        columnField: {
-            component: 'date',
-            class: 'shrink',
-        },
+        component: 'date',
         columnFilter: {
             component: 'date',
         },
-        columnClass: 'expand',
+        createAttrs: {
+            required: true,
+        },
+        create: true,
+        createOrder: 5,
+        width: '65px',
     },
     {
         label: t('item.fixedPrice.ended'),
         name: 'ended',
-        ...defaultColumnAttrs,
-        columnField: {
-            component: 'date',
-            class: 'shrink',
-        },
+        component: 'date',
         columnFilter: {
             component: 'date',
         },
-        columnClass: 'expand',
-        format: (row) => toDate(row.ended),
+        createAttrs: {
+            required: true,
+        },
+        create: true,
+        createOrder: 6,
+        width: '65px',
     },
-
     {
+        align: 'center',
         label: t('globals.warehouse'),
         name: 'warehouseFk',
-        ...defaultColumnAttrs,
-        columnClass: 'shrink',
         component: 'select',
-        options: warehousesOptions,
-        columnFilter: {
-            name: 'warehouseFk',
-            inWhere: true,
-            component: 'select',
-            attrs: {
-                options: warehousesOptions,
-                'option-label': 'name',
-                'option-value': 'id',
-            },
+        attrs: {
+            url: 'Warehouses',
+            fields: ['id', 'name'],
+            optionLabel: 'name',
+            optionValue: 'id',
         },
+        create: true,
+        format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseName),
+        width: '80px',
     },
     {
         align: 'right',
         name: 'tableActions',
         actions: [
             {
-                title: t('delete'),
-                icon: 'delete',
-                action: (row) => confirmRemove(row),
+                title: t('globals.clone'),
+                icon: 'vn:clone',
+                action: (row) => openCloneFixedPriceForm(row),
                 isPrimary: true,
             },
         ],
     },
 ]);
 
-const editTableFieldsOptions = [
-    {
-        field: 'rate2',
-        label: t('item.fixedPrice.groupingPrice'),
-        component: 'input',
-        attrs: {
-            type: 'number',
-        },
-    },
-    {
-        field: 'rate3',
-        label: t('item.fixedPrice.packingPrice'),
-        component: 'input',
-        attrs: {
-            type: 'number',
-        },
-    },
-    {
-        field: 'minPrice',
-        label: t('item.fixedPrice.minPrice'),
-        component: 'input',
-        attrs: {
-            type: 'number',
-        },
-    },
-    {
-        field: 'started',
-        label: t('item.fixedPrice.started'),
-        component: 'date',
-    },
-    {
-        field: 'ended',
-        label: t('item.fixedPrice.ended'),
-        component: 'date',
-    },
-    {
-        field: 'warehouseFk',
-        label: t('globals.warehouse'),
-        component: 'select',
-        attrs: {
-            options: [],
-            'option-label': 'name',
-            'option-value': 'id',
-        },
-    },
-];
-const getRowUpdateInputEvents = (props, resetMinPrice, inputType = 'text') => {
-    return inputType === 'text'
-        ? {
-              'keyup.enter': () => upsertPrice(props, resetMinPrice),
-              blur: () => upsertPrice(props, resetMinPrice),
-          }
-        : { 'update:modelValue': () => upsertPrice(props, resetMinPrice) };
+const openEditFixedPriceForm = () => {
+    editFixedPriceForm.value.show();
 };
 
-const updateMinPrice = async (value, props) => {
-    props.row.hasMinPrice = value;
-    await upsertPrice({
-        row: props.row,
-        col: { field: 'hasMinPrice' },
-        rowIndex: props.rowIndex,
-    });
+const openCloneFixedPriceForm = (row) => {
+    tableRef.value.showForm = true;
+    isToClone.value = true;
+    tableRef.value.create.title = t('Clone fixed price');
+    tableRef.value.create.formInitialData = (({
+        itemFk,
+        rate2,
+        rate3,
+        started,
+        ended,
+        warehouseFk,
+    }) => ({
+        itemFk,
+        rate2,
+        rate3,
+        started,
+        ended,
+        warehouseFk,
+    }))(JSON.parse(JSON.stringify(row)));
 };
 
-const validations = ({ row }) => {
-    const requiredFields = [
-        'itemFk',
-        'started',
-        'ended',
-        'rate2',
-        'rate3',
-        'warehouseFk',
-    ];
-    const isValid = requiredFields.every(
-        (field) => row[field] !== null && row[field] !== undefined
-    );
-    return isValid;
-};
-const upsertPrice = async (props, resetMinPrice = false) => {
-    const isValid = validations({ ...props });
-    if (!isValid) {
-        return;
-    }
-    const { row } = props;
-    const changes = tableRef.value.CrudModelRef.getChanges();
-    if (changes?.updates?.length > 0) {
-        if (resetMinPrice) row.hasMinPrice = 0;
-    }
-    if (!changes.updates && !changes.creates) return;
-    const data = await upsertFixedPrice(row);
-    Object.assign(tableRef.value.CrudModelRef.formData[props.rowIndex], data);
-    notify(t('globals.dataSaved'), 'positive');
-    tableRef.value.reload();
-};
-
-async function upsertFixedPrice(row) {
-    const { data } = await axios.patch('FixedPrices/upsertFixedPrice', row);
-    data.hasMinPrice = data.hasMinPrice ? 1 : 0;
-    return data;
-}
-
-function checkLastVisibleRow() {
-    let lastVisibleRow = null;
-
-    getTableRows().forEach((row, index) => {
-        const rect = row.getBoundingClientRect();
-        if (rect.top >= 0 && rect.bottom <= window.innerHeight) {
-            lastVisibleRow = index;
-        }
-    });
-
-    return lastVisibleRow;
-}
-
-const addRow = (original = null) => {
-    let copy = null;
-    const today = Date.vnNew();
-    const millisecsInDay = 86400000;
-    const daysInWeek = 7;
-    const nextWeek = new Date(today.getTime() + daysInWeek * millisecsInDay);
-
-    copy = {
-        id: 0,
-        started: today,
-        ended: nextWeek,
-        hasMinPrice: 0,
-        $index: 0,
-    };
-    return { original, copy };
-};
-
-const getTableRows = () =>
-    document.getElementsByClassName('q-table')[0].querySelectorAll('tr.cursor-pointer');
-
-function highlightNewRow({ $index: index }) {
-    const row = getTableRows()[index];
-    if (row) {
-        row.classList.add('highlight');
-        setTimeout(() => {
-            row.classList.remove('highlight');
-        }, 3000);
-    }
-}
-const openEditTableCellDialog = () => {
-    editTableCellDialogRef.value.show();
-};
-
-const onEditCellDataSaved = async () => {
-    rowsSelected.value = [];
-    tableRef.value.reload();
-};
-
-const removeFuturePrice = async () => {
-    rowsSelected.value.forEach(({ id }) => {
-        const rowIndex = fixedPrices.value.findIndex(({ id }) => id === id);
-        removePrice(id, rowIndex);
-    });
-};
-
-function confirmRemove(item, isFuture) {
-    const promise = async () =>
-        isFuture ? removeFuturePrice(item.id) : removePrice(item.id);
-    quasar.dialog({
-        component: VnConfirm,
-        componentProps: {
-            title: t('globals.rowWillBeRemoved'),
-            message: t('globals.confirmDeletion'),
-            promise,
-        },
-    });
-}
-
-const removePrice = async (id) => {
-    await axios.delete(`FixedPrices/${id}`);
-    notify(t('globals.dataSaved'), 'positive');
-    tableRef.value.reload({});
-};
 const dateStyle = (date) =>
     date
         ? {
-              'bg-color': 'warning',
-              'is-outlined': true,
+              color: 'var(--vn-black-text-color)',
           }
-        : {};
+        : { color: dateColor, 'background-color': 'transparent' };
 
-function handleOnDataSave({ CrudModelRef }) {
-    const { original, copy } = addRow(CrudModelRef.formData[checkLastVisibleRow()]);
-    if (original) {
-        CrudModelRef.formData.splice(original?.$index ?? 0, 0, copy);
-    } else {
-        CrudModelRef.insert(copy);
+const onDataSaved = () => {
+    tableRef.value.CrudModelRef.saveChanges();
+    selectedRows.value = [];
+};
+
+onMounted(() => {
+    if (tableRef.value) {
+        tableRef.value.showForm = false;
     }
-    nextTick(() => {
-        highlightNewRow(original ?? { $index: 0 });
-    });
-}
+});
+
+watch(
+    () => tableRef.value?.showForm,
+    (newVal) => {
+        if (!newVal) {
+            tableRef.value.create.title = '';
+            tableRef.value.create.formInitialData = { warehouseFk: warehouse };
+            if (tableRef.value) {
+                isToClone.value = false;
+                tableRef.value.create.title = t('Create fixed price');
+            }
+        }
+    },
+);
 </script>
 
 <template>
-    <FetchData
-        @on-fetch="(data) => (warehousesOptions = data)"
-        auto-load
-        url="Warehouses"
-        :filter="{ fields: ['id', 'name'], order: 'name ASC' }"
-    />
     <RightMenu>
         <template #right-panel>
-            <ItemFixedPriceFilter
-                data-key="ItemFixedPrices"
-                ref="itemFixedPriceFilterRef"
-            />
+            <ItemFixedPriceFilter data-key="ItemFixedPrices" />
         </template>
     </RightMenu>
-    <VnSubToolbar>
-        <template #st-actions>
+    <VnSubToolbar />
+    <Teleport to="#st-data" v-if="stateStore?.isSubToolbarShown()">
+        <QBtnGroup push style="column-gap: 10px">
             <QBtn
                 :disable="!hasSelectedRows"
-                @click="openEditTableCellDialog()"
+                @click="openEditFixedPriceForm()"
                 color="primary"
                 icon="edit"
+                flat
+                :label="t('globals.edit')"
+                data-cy="FixedPriceToolbarEditBtn"
             >
                 <QTooltip>
                     {{ t('Edit fixed price(s)') }}
                 </QTooltip>
             </QBtn>
-            <QBtn
-                :disable="!hasSelectedRows"
-                :label="tMobile('globals.remove')"
-                color="primary"
-                icon="delete"
-                flat
-                @click="(row) => confirmRemove(row, true)"
-                :title="t('globals.remove')"
-            />
-        </template>
-    </VnSubToolbar>
+        </QBtnGroup>
+    </Teleport>
     <VnTable
-        :default-remove="false"
-        :default-reset="false"
-        :default-save="false"
+        ref="tableRef"
         data-key="ItemFixedPrices"
         url="FixedPrices/filter"
-        :order="['name DESC', 'itemFk DESC']"
+        :order="'name DESC'"
         save-url="FixedPrices/crud"
-        ref="tableRef"
-        dense
-        :filter="{
-            where: {
-                warehouseFk: user.warehouseFk,
-            },
-        }"
         :columns="columns"
-        default-mode="table"
-        auto-load
         :is-editable="true"
         :right-search="false"
         :table="{
             'row-key': 'id',
             selection: 'multiple',
         }"
-        v-model:selected="rowsSelected"
-        :create-as-dialog="false"
+        v-model:selected="selectedRows"
         :create="{
-            onDataSaved: handleOnDataSave,
+            urlCreate: 'FixedPrices',
+            title: t('Create fixed price'),
+            formInitialData: { warehouseFk: warehouse },
+            onDataSaved: () => tableRef.reload(),
+            showSaveAndContinueBtn: true,
         }"
         :disable-option="{ card: true }"
-        :has-sub-toolbar="false"
+        auto-load
+        :beforeSaveFn="(data, getChanges) => beforeSave(data, getChanges, 'FixedPrices')"
     >
-        <template #header-selection="scope">
-            <QCheckbox v-model="scope.selected" />
+        <template #column-hex="{ row }">
+            <VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />
         </template>
-        <template #body-selection="scope">
-            {{ scope }}
-            <QCheckbox flat v-model="scope.selected" />
+        <template #column-name="{ row }">
+            <span class="link">
+                {{ row.name }}
+                <ItemDescriptorProxy :id="row.itemFk" />
+            </span>
+            <span class="subName">{{ row.subName }}</span>
+            <FetchedTags :item="row" :columns="6" />
         </template>
-
-        <template #column-itemFk="props">
+        <template #column-started="{ row }">
+            <div class="editable-text q-pb-xxs">
+                <QBadge class="badge" :style="dateStyle(isLower(row?.ended))">
+                    {{ toDate(row?.started) }}
+                </QBadge>
+            </div>
+        </template>
+        <template #column-ended="{ row }">
+            <div class="editable-text q-pb-xxs">
+                <QBadge class="badge" :style="dateStyle(isBigger(row?.ended))">
+                    {{ toDate(row?.ended) }}
+                </QBadge>
+            </div>
+        </template>
+        <template #column-create-name="{ data }">
             <VnSelect
-                style="max-width: 100px"
-                url="Items/withName"
-                hide-selected
-                option-label="id"
+                url="Items/search"
+                v-model="data.itemFk"
+                :label="t('item.fixedPrice.itemName')"
+                :fields="['id', 'name']"
+                :filter-options="['id', 'name']"
+                option-label="name"
                 option-value="id"
-                v-model="props.row.itemFk"
-                v-on="getRowUpdateInputEvents(props, true, 'select')"
+                :required="true"
+                sort-by="name ASC"
+                data-cy="FixedPriceCreateNameSelect"
             >
                 <template #option="scope">
                     <QItem v-bind="scope.itemProps">
                         <QItemSection>
-                            <QItemLabel> #{{ scope.opt?.id }} </QItemLabel>
-                            <QItemLabel caption>{{ scope.opt?.name }}</QItemLabel>
+                            <QItemLabel>
+                                {{ scope.opt.name }}
+                            </QItemLabel>
+                            <QItemLabel caption> #{{ scope.opt.id }} </QItemLabel>
                         </QItemSection>
                     </QItem>
                 </template>
             </VnSelect>
         </template>
-        <template #column-name="{ row }">
-            <span class="link">
-                {{ row.name }}
-            </span>
-            <span class="subName">{{ row.subName }}</span>
-            <ItemDescriptorProxy :id="row.itemFk" />
-            <FetchedTags :item="row" :columns="3" />
-        </template>
-        <template #column-rate2="props">
-            <QTd class="col">
-                <VnInput
-                    type="currency"
-                    style="width: 75px"
-                    v-model.number="props.row.rate2"
-                    v-on="getRowUpdateInputEvents(props)"
-                >
-                    <template #append>€</template>
-                </VnInput>
-            </QTd>
-        </template>
-        <template #column-rate3="props">
-            <QTd class="col">
-                <VnInput
-                    style="width: 75px"
-                    type="currency"
-                    v-model.number="props.row.rate3"
-                    v-on="getRowUpdateInputEvents(props)"
-                >
-                    <template #append>€</template>
-                </VnInput>
-            </QTd>
-        </template>
-        <template #column-minPrice="props">
-            <QTd class="col">
-                <div class="row" style="align-items: center">
-                    <QCheckbox
-                        :model-value="props.row.hasMinPrice"
-                        @update:model-value="updateMinPrice($event, props)"
-                        :false-value="0"
-                        :true-value="1"
-                        :toggle-indeterminate="false"
-                    />
-                    <VnInput
-                        class="col"
-                        type="currency"
-                        mask="###.##"
-                        :disable="props.row.hasMinPrice === 0"
-                        v-model.number="props.row.minPrice"
-                        v-on="getRowUpdateInputEvents(props)"
-                    >
-                        <template #append>€</template>
-                    </VnInput>
-                </div>
-            </QTd>
-        </template>
-        <template #column-started="props">
-            <VnInputDate
-                class="vnInputDate"
-                :show-event="true"
-                v-model="props.row.started"
-                v-on="getRowUpdateInputEvents(props, false, 'date')"
-                v-bind="dateStyle(isBigger(props.row.started))"
-            />
-        </template>
-        <template #column-ended="props">
-            <VnInputDate
-                class="vnInputDate"
-                :show-event="true"
-                v-model="props.row.ended"
-                v-on="getRowUpdateInputEvents(props, false, 'date')"
-                v-bind="dateStyle(isLower(props.row.ended))"
-            />
-        </template>
-        <template #column-warehouseFk="props">
-            <QTd class="col">
-                <VnSelect
-                    style="max-width: 150px"
-                    :options="warehousesOptions"
-                    hide-selected
-                    option-label="name"
-                    option-value="id"
-                    v-model="props.row.warehouseFk"
-                    v-on="getRowUpdateInputEvents(props, false, 'select')"
-                />
-            </QTd>
-        </template>
-        <template #column-deleteAction="{ row, rowIndex }">
-            <QIcon
-                name="delete"
-                size="sm"
-                class="cursor-pointer fill-icon-on-hover"
-                color="primary"
-                @click.stop="
-                    openConfirmationModal(
-                        t('globals.rowWillBeRemoved'),
-                        t('Do you want to clone this item?'),
-                        () => removePrice(row.id, rowIndex)
-                    )
-                "
+        <template #column-create-warehouseFk="{ data }">
+            <VnSelect
+                :label="t('globals.warehouse')"
+                url="Warehouses"
+                v-model="data.warehouseFk"
+                :fields="['id', 'name']"
+                option-label="name"
+                option-value="id"
+                hide-selected
+                :required="true"
+                sort-by="name ASC"
+                data-cy="FixedPriceCreateWarehouseSelect"
             >
-                <QTooltip class="text-no-wrap">
-                    {{ t('globals.delete') }}
-                </QTooltip>
-            </QIcon>
+                <template #option="scope">
+                    <QItem v-bind="scope.itemProps">
+                        <QItemSection>
+                            <QItemLabel>
+                                {{ scope.opt.name }}
+                            </QItemLabel>
+                            <QItemLabel caption> #{{ scope.opt.id }} </QItemLabel>
+                        </QItemSection>
+                    </QItem>
+                </template>
+            </VnSelect>
         </template>
     </VnTable>
-
-    <QDialog ref="editTableCellDialogRef">
-        <EditTableCellValueForm
+    <QDialog ref="editFixedPriceForm">
+        <EditFixedPriceForm
             edit-url="FixedPrices/editFixedPrice"
-            :rows="rowsSelected"
-            :fields-options="editTableFieldsOptions"
-            @on-data-saved="onEditCellDataSaved()"
+            :rows="selectedRows"
+            :fields-options="
+                columns.filter(
+                    ({ isEditable, component, name }) =>
+                        isEditable !== false && component && name !== 'itemFk',
+                )
+            "
+            :beforeSave="beforeSave"
+            @on-data-saved="onDataSaved"
         />
     </QDialog>
 </template>
@@ -623,8 +435,17 @@ tbody tr.highlight .q-td {
     color: var(--vn-label-color);
 }
 </style>
+
+<style lang="scss" scoped>
+.badge {
+    background-color: $warning;
+}
+</style>
+
 <i18n>
 es:
     Add fixed price: Añadir precio fijado
     Edit fixed price(s): Editar precio(s) fijado(s)
+    Create fixed price: Crear precio fijado
+    Clone fixed price: Clonar precio fijado
 </i18n>
diff --git a/src/pages/Item/ItemFixedPriceFilter.vue b/src/pages/Item/ItemFixedPriceFilter.vue
index 8d92e245d..9c11a2e69 100644
--- a/src/pages/Item/ItemFixedPriceFilter.vue
+++ b/src/pages/Item/ItemFixedPriceFilter.vue
@@ -13,7 +13,6 @@ const props = defineProps({
         required: true,
     },
 });
-
 </script>
 
 <template>
@@ -28,9 +27,9 @@ const props = defineProps({
                         :fields="['id', 'nickname']"
                         option-label="nickname"
                         dense
-                        outlined
-                        rounded
+                        filled
                         use-input
+                        :use-like="false"
                         @update:model-value="searchFn()"
                         sort-by="nickname ASC"
                     />
@@ -46,29 +45,26 @@ const props = defineProps({
                         :label="t('params.warehouseFk')"
                         v-model="params.warehouseFk"
                         dense
-                        outlined
-                        rounded
+                        filled
                         use-input
                         @update:model-value="searchFn()"
                     />
                 </QItemSection>
             </QItem>
-            <QItem class="q-my-md">
+            <QItem>
                 <QItemSection>
                     <VnInputDate
-                        :label="t('params.started')"
                         v-model="params.started"
-                        is-outlined
+                        :label="t('params.started')"
+                        filled
                         @update:model-value="searchFn()"
                     />
                 </QItemSection>
-            </QItem>
-            <QItem class="q-my-md">
                 <QItemSection>
                     <VnInputDate
-                        :label="t('params.ended')"
                         v-model="params.ended"
-                        is-outlined
+                        :label="t('params.ended')"
+                        filled
                         @update:model-value="searchFn()"
                     />
                 </QItemSection>
diff --git a/src/pages/Item/ItemListFilter.vue b/src/pages/Item/ItemListFilter.vue
index 22e948e06..ab9b91d06 100644
--- a/src/pages/Item/ItemListFilter.vue
+++ b/src/pages/Item/ItemListFilter.vue
@@ -7,7 +7,7 @@ import FetchData from 'components/FetchData.vue';
 import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnInput from 'src/components/common/VnInput.vue';
-import { QCheckbox } from 'quasar';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
 
 import { useArrayData } from 'composables/useArrayData';
 import { useValidator } from 'src/composables/useValidator';
@@ -177,11 +177,7 @@ onMounted(async () => {
         <template #body="{ params, searchFn }">
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.search"
-                        :label="t('params.search')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.search" :label="t('params.search')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -197,8 +193,7 @@ onMounted(async () => {
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -213,8 +208,7 @@ onMounted(async () => {
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                         <template #option="scope">
                             <QItem v-bind="scope.itemProps">
@@ -240,8 +234,7 @@ onMounted(async () => {
                         option-label="nickname"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -252,16 +245,14 @@ onMounted(async () => {
                         @update:model-value="searchFn()"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <!-- Tags filter -->
-            <QItem class="row items-center">
-                <QItemLabel>
-                    {{ t('params.tags') }}
-                </QItemLabel>
+            <QItemLabel header>
+                {{ t('params.tags') }}
+
                 <QIcon
                     name="add_circle"
                     class="fill-icon-on-hover q-ml-md"
@@ -269,7 +260,7 @@ onMounted(async () => {
                     color="primary"
                     @click="tagValues.push({})"
                 />
-            </QItem>
+            </QItemLabel>
             <QItem
                 v-for="(tag, index) in tagValues"
                 :key="index"
@@ -277,13 +268,13 @@ onMounted(async () => {
             >
                 <QItemSection class="col">
                     <VnSelect
+                        class="full-width"
                         :label="t('params.tag')"
                         v-model="tag.selectedTag"
                         :options="tagOptions"
                         option-label="name"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :emit-value="false"
                         use-input
                         :is-clearable="false"
@@ -299,8 +290,7 @@ onMounted(async () => {
                         option-value="value"
                         option-label="value"
                         dense
-                        outlined
-                        rounded
+                        filled
                         emit-value
                         use-input
                         :disable="!tag"
@@ -312,7 +302,7 @@ onMounted(async () => {
                         v-model="tag.value"
                         :label="t('params.value')"
                         :disable="!tag"
-                        is-outlined
+                        filled
                         :is-clearable="false"
                         @keydown.enter.prevent="applyTags(params, searchFn)"
                     />
@@ -326,33 +316,26 @@ onMounted(async () => {
                 />
             </QItem>
             <!-- Filter fields -->
-            <QItem class="row items-center">
-                <QItemLabel>
-                    {{ t('More fields') }}
-                </QItemLabel>
+            <QItemLabel header
+                >{{ t('More fields') }}
                 <QIcon
                     name="add_circle"
                     class="fill-icon-on-hover q-ml-md"
                     size="sm"
                     color="primary"
                     @click="fieldFiltersValues.push({})"
-                />
-            </QItem>
-            <QItem
-                v-for="(fieldFilter, index) in fieldFiltersValues"
-                :key="index"
-                class="row items-center"
-            >
+            /></QItemLabel>
+            <QItem v-for="(fieldFilter, index) in fieldFiltersValues" :key="index">
                 <QItemSection class="col">
                     <VnSelect
+                        class="full-width"
                         :label="t('params.tag')"
                         :model-value="fieldFilter.selectedField"
                         :options="moreFields"
                         option-label="label"
                         option-value="label"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :emit-value="false"
                         use-input
                         :is-clearable="false"
@@ -366,7 +349,7 @@ onMounted(async () => {
                     />
                 </QItemSection>
                 <QItemSection class="col">
-                    <QCheckbox
+                    <VnCheckbox
                         v-if="fieldFilter.selectedField?.type === 'boolean'"
                         v-model="fieldFilter.value"
                         :label="t('params.value')"
@@ -377,17 +360,18 @@ onMounted(async () => {
                         v-model="fieldFilter.value"
                         :label="t('params.value')"
                         :disable="!fieldFilter.selectedField"
-                        is-outlined
+                        filled
                         @keydown.enter="applyFieldFilters(params, searchFn)"
                     />
                 </QItemSection>
-                <QIcon
-                    name="delete"
-                    class="fill-icon-on-hover q-ml-xs"
-                    size="sm"
-                    color="primary"
-                    @click="removeFieldFilter(index, params, searchFn)"
-                />
+                <QItemSection side
+                    ><QIcon
+                        name="delete"
+                        class="fill-icon-on-hover q-ml-xs"
+                        size="sm"
+                        color="primary"
+                        @click="removeFieldFilter(index, params, searchFn)"
+                /></QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 43fc611d8..ccae98025 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -3,6 +3,7 @@ import { ref, computed, onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { toCurrency } from 'filters/index';
 import useNotify from 'src/composables/useNotify.js';
@@ -61,6 +62,7 @@ const columns = computed(() => [
         columnClass: 'expand',
     },
     {
+        align: 'left',
         label: t('item.buyRequest.requester'),
         name: 'requesterName',
         component: 'select',
@@ -77,6 +79,19 @@ const columns = computed(() => [
         },
         columnClass: 'shrink',
     },
+    {
+        align: 'left',
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
+        component: 'select',
+        attrs: {
+            url: 'Departments',
+        },
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
+    },
     {
         label: t('item.buyRequest.requested'),
         name: 'quantity',
@@ -107,6 +122,7 @@ const columns = computed(() => [
         },
         columnClass: 'shrink',
     },
+
     {
         label: t('globals.item'),
         name: 'item',
@@ -262,6 +278,12 @@ const onDenyAccept = (_, responseData) => {
                 <WorkerDescriptorProxy :id="row.requesterFk" />
             </span>
         </template>
+        <template #column-departmentFk="{ row }">
+            <span class="link" @click.stop>
+                {{ row.departmentName }}
+                <DepartmentDescriptorProxy :id="row.departmentFk" />
+            </span>
+        </template>
 
         <template #column-item="{ row }">
             <span>
diff --git a/src/pages/Item/ItemRequestFilter.vue b/src/pages/Item/ItemRequestFilter.vue
index c2a63ddd9..68f36c566 100644
--- a/src/pages/Item/ItemRequestFilter.vue
+++ b/src/pages/Item/ItemRequestFilter.vue
@@ -87,11 +87,7 @@ onMounted(async () => {
         <template #body="{ params, searchFn }">
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.search"
-                        :label="t('params.search')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.search" :label="t('params.search')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -99,7 +95,7 @@ onMounted(async () => {
                     <VnInput
                         v-model="params.ticketFk"
                         :label="t('params.ticketFk')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -114,8 +110,7 @@ onMounted(async () => {
                         option-label="nickname"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -124,7 +119,7 @@ onMounted(async () => {
                     <VnInput
                         v-model="params.clientFk"
                         :label="t('params.clientFk')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -139,8 +134,7 @@ onMounted(async () => {
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -153,25 +147,16 @@ onMounted(async () => {
                         :params="{ departmentCodes: ['VT'] }"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInputDate
-                        v-model="params.from"
-                        :label="t('params.from')"
-                        is-outlined
-                    />
+                    <VnInputDate v-model="params.from" :label="t('params.from')" filled />
                 </QItemSection>
                 <QItemSection>
-                    <VnInputDate
-                        v-model="params.to"
-                        :label="t('params.to')"
-                        is-outlined
-                    />
+                    <VnInputDate v-model="params.to" :label="t('params.to')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -180,7 +165,7 @@ onMounted(async () => {
                         :label="t('params.daysOnward')"
                         v-model="params.daysOnward"
                         lazy-rules
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -195,8 +180,7 @@ onMounted(async () => {
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -221,7 +205,7 @@ en:
         attenderFk: Atender
         clientFk: Client id
         warehouseFk: Warehouse
-        requesterFk: Salesperson
+        requesterFk: Requester
         from: From
         to: To
         mine: For me
@@ -239,7 +223,7 @@ es:
         attenderFk: Comprador
         clientFk: Id cliente
         warehouseFk: Almacén
-        requesterFk: Comercial
+        requesterFk: Solicitante
         from: Desde
         to: Hasta
         mine: Para mi
diff --git a/src/pages/Item/ItemType/Card/ItemTypeCard.vue b/src/pages/Item/ItemType/Card/ItemTypeCard.vue
index 84e810de5..bd41b1be2 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeCard.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeCard.vue
@@ -1,11 +1,11 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import ItemTypeDescriptor from 'src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue';
 import filter from './ItemTypeFilter.js';
 </script>
 
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="ItemType"
         url="ItemTypes"
         :filter="filter"
diff --git a/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue b/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
index 725fb30aa..106b005bf 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
@@ -2,7 +2,7 @@
 import { computed } from 'vue';
 import { useRoute } from 'vue-router';
 
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 import filter from './ItemTypeFilter.js';
@@ -25,11 +25,12 @@ const entityId = computed(() => {
 });
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         :url="`ItemTypes/${entityId}`"
         :filter="filter"
         title="code"
         data-key="ItemType"
+        :to-module="{ name: 'ItemTypeList' }"
     >
         <template #body="{ entity }">
             <VnLv :label="$t('itemType.shared.code')" :value="entity.code" />
@@ -45,5 +46,5 @@ const entityId = computed(() => {
                 :value="entity.category?.name"
             />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
diff --git a/src/pages/Item/ItemType/Card/ItemTypeSummary.vue b/src/pages/Item/ItemType/Card/ItemTypeSummary.vue
index 3b63c4b63..ba294e144 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeSummary.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeSummary.vue
@@ -7,6 +7,7 @@ import filter from './ItemTypeFilter.js';
 import CardSummary from 'components/ui/CardSummary.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import VnToSummary from 'src/components/ui/VnToSummary.vue';
+import VnTitle from 'src/components/common/VnTitle.vue';
 
 onUpdated(() => summaryRef.value.fetch());
 
@@ -62,13 +63,10 @@ async function setItemTypeData(data) {
         </template>
         <template #body>
             <QCard class="vn-one">
-                <router-link
-                    :to="{ name: 'ItemTypeBasicData', params: { id: entityId } }"
-                    class="header header-link"
-                >
-                    {{ t('globals.summary.basicData') }}
-                    <QIcon name="open_in_new" />
-                </router-link>
+                <VnTitle
+                    :url="`#/item/item-type/${entityId}/basic-data`"
+                    :text="$t('globals.summary.basicData')"
+                />
                 <VnLv :label="t('itemType.summary.id')" :value="itemType.id" />
                 <VnLv :label="t('itemType.shared.code')" :value="itemType.code" />
                 <VnLv :label="t('itemType.shared.name')" :value="itemType.name" />
diff --git a/src/components/EditTableCellValueForm.vue b/src/pages/Item/components/EditFixedPriceForm.vue
similarity index 81%
rename from src/components/EditTableCellValueForm.vue
rename to src/pages/Item/components/EditFixedPriceForm.vue
index 172866191..9c6a63893 100644
--- a/src/components/EditTableCellValueForm.vue
+++ b/src/pages/Item/components/EditFixedPriceForm.vue
@@ -8,11 +8,6 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import { QCheckbox } from 'quasar';
 
-import axios from 'axios';
-import useNotify from 'src/composables/useNotify.js';
-
-const emit = defineEmits(['onDataSaved']);
-
 const $props = defineProps({
     rows: {
         type: Array,
@@ -26,10 +21,14 @@ const $props = defineProps({
         type: String,
         default: '',
     },
+    beforeSave: {
+        type: Function,
+        default: () => {},
+    },
 });
 
 const { t } = useI18n();
-const { notify } = useNotify();
+const emit = defineEmits(['onDataSaved']);
 
 const inputs = {
     input: markRaw(VnInput),
@@ -44,24 +43,13 @@ const selectedField = ref(null);
 const closeButton = ref(null);
 const isLoading = ref(false);
 
-const onDataSaved = () => {
-    notify('globals.dataSaved', 'positive');
-    emit('onDataSaved');
-    closeForm();
-};
-
 const onSubmit = async () => {
     isLoading.value = true;
-    const rowsToEdit = $props.rows.map((row) => ({ id: row.id, itemFk: row.itemFk }));
-    const payload = {
-        field: selectedField.value.field,
-        newValue: newValue.value,
-        lines: rowsToEdit,
-    };
-
-    await axios.post($props.editUrl, payload);
-    onDataSaved();
-    isLoading.value = false;
+    $props.rows.forEach((row) => {
+        row[selectedField.value.name] = newValue.value;
+    });
+    emit('onDataSaved', $props.rows);
+    closeForm();
 };
 
 const closeForm = () => {
@@ -78,21 +66,24 @@ const closeForm = () => {
             <span class="title">{{ t('Edit') }}</span>
             <span class="countLines">{{ ` ${rows.length} ` }}</span>
             <span class="title">{{ t('buy(s)') }}</span>
-            <VnRow>
+            <VnRow class="q-mt-md">
                 <VnSelect
+                    class="editOption"
                     :label="t('Field to edit')"
                     :options="fieldsOptions"
                     hide-selected
                     option-label="label"
                     v-model="selectedField"
-                    data-cy="field-to-edit"
+                    data-cy="EditFixedPriceSelectOption"
+                    @update:model-value="newValue = null"
+                    :class="{ 'is-select': selectedField?.component === 'select' }"
                 />
                 <component
                     :is="inputs[selectedField?.component || 'input']"
                     v-bind="selectedField?.attrs || {}"
                     v-model="newValue"
                     :label="t('Value')"
-                    data-cy="value-to-edit"
+                    data-cy="EditFixedPriceValueOption"
                     style="width: 200px"
                 />
             </VnRow>
@@ -140,6 +131,15 @@ const closeForm = () => {
 }
 </style>
 
+<style lang="scss">
+.editOption .q-field__inner .q-field__control {
+    padding: 0 !important;
+}
+.editOption.is-select .q-field__inner .q-field__control {
+    padding: 0 !important;
+}
+</style>
+
 <i18n>
 es:
     Edit: Editar
diff --git a/src/pages/Item/components/__tests__/EditFixedPriceForm.spec.js b/src/pages/Item/components/__tests__/EditFixedPriceForm.spec.js
new file mode 100644
index 000000000..6ac8f372d
--- /dev/null
+++ b/src/pages/Item/components/__tests__/EditFixedPriceForm.spec.js
@@ -0,0 +1,46 @@
+import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
+import { createWrapper } from 'app/test/vitest/helper';
+import EditFixedPriceForm from 'src/pages/Item/components/EditFixedPriceForm.vue';
+
+describe('EditFixedPriceForm.vue', () => {
+    let wrapper;
+    let vm;
+
+    const mockRows = [
+        { id: 1, itemFk: 101 },
+        { id: 2, itemFk: 102 },
+    ];
+
+    const mockFieldsOptions = [
+        {
+            name: 'price',
+            label: 'Price',
+            component: 'input',
+            attrs: { type: 'number' },
+        },
+    ];
+
+    beforeEach(() => {
+        wrapper = createWrapper(EditFixedPriceForm, {
+            props: {
+                rows: JSON.parse(JSON.stringify(mockRows)),
+                fieldsOptions: mockFieldsOptions,
+            },
+        });
+        wrapper = wrapper.wrapper;
+        vm = wrapper.vm;
+    });
+
+    afterEach(() => {
+        vi.clearAllMocks();
+    });
+
+    it('should emit "onDataSaved" with updated rows on submit', async () => {
+        vm.selectedField = mockFieldsOptions[0];
+        vm.newValue = 199.99;
+
+        await vm.onSubmit();
+
+        expect(wrapper.emitted('onDataSaved')).toBeTruthy();
+    });
+});
diff --git a/src/pages/Item/locale/en.yml b/src/pages/Item/locale/en.yml
index 9d27fc96e..017f6b11f 100644
--- a/src/pages/Item/locale/en.yml
+++ b/src/pages/Item/locale/en.yml
@@ -84,7 +84,7 @@ item:
         attenderFk: Atender
         clientFk: Client id
         warehouseFk: Warehouse
-        requesterFk: Salesperson
+        requesterFk: Requester
         from: From
         to: To
         mine: For me
@@ -167,6 +167,8 @@ item:
         started: Started
         ended: Ended
         warehouse: Warehouse
+        MP: MP
+        itemName: Item
     create:
         name: Name
         tag: Tag
diff --git a/src/pages/Item/locale/es.yml b/src/pages/Item/locale/es.yml
index 935f5160b..a06695fe9 100644
--- a/src/pages/Item/locale/es.yml
+++ b/src/pages/Item/locale/es.yml
@@ -93,7 +93,7 @@ item:
         attenderFk: Comprador
         clientFk: Id cliente
         warehouseFk: Almacén
-        requesterFk: Comercial
+        requesterFk: Solicitante
         from: Desde
         to: Hasta
         mine: Para mi
@@ -173,6 +173,8 @@ item:
         started: Inicio
         ended: Fin
         warehouse: Almacén
+        MP: PM
+        itemName: Nombre
     create:
         name: Nombre
         tag: Etiqueta
diff --git a/src/pages/Login/__tests__/Login.spec.js b/src/pages/Login/__tests__/Login.spec.js
index e90a8ee53..b25246f52 100644
--- a/src/pages/Login/__tests__/Login.spec.js
+++ b/src/pages/Login/__tests__/Login.spec.js
@@ -1,6 +1,7 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
 import Login from 'pages/Login/LoginMain.vue';
+import axios from 'axios';
 
 describe('Login', () => {
     let vm;
diff --git a/src/pages/Monitor/MonitorClients.vue b/src/pages/Monitor/MonitorClients.vue
index c1958cdcb..2ba5f4c0b 100644
--- a/src/pages/Monitor/MonitorClients.vue
+++ b/src/pages/Monitor/MonitorClients.vue
@@ -1,19 +1,22 @@
 <script setup>
 import { ref, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
-import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from '../Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
 import { toDateFormat } from 'src/filters/date.js';
 import VnTable from 'src/components/VnTable/VnTable.vue';
 import VnInputDate from 'src/components/common/VnInputDate.vue';
 import VnRow from 'src/components/ui/VnRow.vue';
 import { dateRange } from 'src/filters';
+import useOpenURL from 'src/composables/useOpenURL';
+import { useState } from 'src/composables/useState';
 const { t } = useI18n();
 
 const dates = dateRange(Date.vnNew());
 const from = ref(dates[0]);
 const to = ref(dates[1]);
 
+const state = useState();
 const filter = computed(() => {
     const obj = {};
     const formatFrom = setHours(from.value, 'from');
@@ -23,16 +26,18 @@ const filter = computed(() => {
     if (!formatFrom && formatTo) stamp = { lte: formatTo };
     else if (formatFrom && !formatTo) stamp = { gte: formatFrom };
     else if (formatFrom && formatTo) stamp = { between: [formatFrom, formatTo] };
-
-    return Object.assign(obj, { where: { 'v.stamp': stamp } });
+    return Object.assign(obj, {
+        where: {
+            'v.stamp': stamp,
+            'c.departmentFk': state.getUser().value.departmentFk,
+        },
+    });
 });
 
 function exprBuilder(param, value) {
     switch (param) {
         case 'clientFk':
             return { [`c.id`]: value };
-        case 'salesPersonFk':
-            return { [`c.${param}`]: value };
     }
 }
 
@@ -62,25 +67,21 @@ const columns = computed(() => [
         columnFilter: false,
     },
     {
-        label: t('salesClientsTable.salesPerson'),
-        name: 'salesPersonFk',
-        field: 'salesPerson',
         align: 'left',
-        columnField: {
-            component: null,
-        },
-        optionFilter: 'firstName',
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
         columnFilter: {
             component: 'select',
             attrs: {
-                url: 'Workers/activeWithInheritedRole',
-                fields: ['id', 'name'],
-                sortBy: 'nickname ASC',
-                where: { role: 'salesPerson' },
-                useLike: false,
+                url: 'Departments',
             },
+            alias: 'c',
+            inWhere: true,
         },
-        columnClass: 'no-padding',
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
     {
         label: t('salesClientsTable.client'),
@@ -102,6 +103,7 @@ const columns = computed(() => [
         columnClass: 'no-padding',
     },
 ]);
+const openTab = (id) => useOpenURL(`#/customer/${id}/summary`);
 </script>
 
 <template>
@@ -121,6 +123,8 @@ const columns = computed(() => [
         :disable-option="{ card: true }"
         dense
         class="q-px-none"
+        :row-click="({ id }) => openTab(id)"
+        :row-ctrl-click="(_, { id }) => openTab(id)"
     >
         <template #top-left>
             <VnRow>
@@ -128,13 +132,17 @@ const columns = computed(() => [
                 <VnInputDate v-model="to" :label="$t('globals.to')" dense />
             </VnRow>
         </template>
-        <template #column-salesPersonFk="{ row }">
-            <span class="link" :title="row.salesPerson" v-text="row.salesPerson" />
-            <WorkerDescriptorProxy :id="row.salesPersonFk" dense />
+        <template #column-departmentFk="{ row }">
+            <span @click.stop.prevent class="link" :title="row.department">
+                {{ row.department }}
+                <DepartmentDescriptorProxy :id="row.departmentFk" dense
+            /></span>
         </template>
         <template #column-clientFk="{ row }">
-            <span class="link" :title="row.clientName" v-text="row.clientName" />
-            <CustomerDescriptorProxy :id="row.clientFk" />
+            <span @click.stop.prevent class="link" :title="row.clientName">
+                {{ row.clientName }}
+                <CustomerDescriptorProxy :id="row.clientFk" dense
+            /></span>
         </template>
     </VnTable>
 </template>
diff --git a/src/pages/Monitor/MonitorOrders.vue b/src/pages/Monitor/MonitorOrders.vue
index 873f8abb4..bdfcf3837 100644
--- a/src/pages/Monitor/MonitorOrders.vue
+++ b/src/pages/Monitor/MonitorOrders.vue
@@ -1,14 +1,15 @@
 <script setup>
 import { ref, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
-import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 
 import { toDateFormat, toDateTimeFormat } from 'src/filters/date.js';
 import { toCurrency } from 'src/filters';
 import { useVnConfirm } from 'composables/useVnConfirm';
 import axios from 'axios';
+import useOpenURL from 'src/composables/useOpenURL';
 
 const { t } = useI18n();
 const { openConfirmationModal } = useVnConfirm();
@@ -20,8 +21,8 @@ function exprBuilder(param, value) {
     switch (param) {
         case 'clientFk':
             return { [`c.id`]: value };
-        case 'salesPersonFk':
-            return { [`c.salesPersonFk`]: value };
+        case 'departmentFk':
+            return { [`c.departmentFk`]: value };
     }
 }
 
@@ -63,20 +64,18 @@ const columns = computed(() => [
         columnFilter: false,
     },
     {
-        label: t('salesClientsTable.salesPerson'),
-        name: 'salesPersonFk',
         align: 'left',
-        optionFilter: 'firstName',
-        columnFilter: {
-            component: 'select',
-            attrs: {
-                url: 'Workers/activeWithInheritedRole',
-                fields: ['id', 'name'],
-                sortBy: 'nickname ASC',
-                where: { role: 'salesPerson' },
-                useLike: false,
-            },
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
+        component: 'select',
+        attrs: {
+            url: 'Departments',
         },
+        create: true,
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
     {
         label: t('salesOrdersTable.import'),
@@ -110,8 +109,7 @@ const removeOrders = async () => {
     await table.value.reload();
 };
 
-const openTab = (id) =>
-    window.open(`#/order/${id}/summary`, '_blank', 'noopener, noreferrer');
+const openTab = (id) => useOpenURL(`#/order/${id}/summary`);
 </script>
 <template>
     <VnTable
@@ -131,6 +129,7 @@ const openTab = (id) =>
         }"
         default-mode="table"
         :row-click="({ id }) => openTab(id)"
+        :row-ctrl-click="(_, { id }) => openTab(id)"
         v-model:selected="selectedRows"
         :disable-option="{ card: true }"
     >
@@ -179,17 +178,16 @@ const openTab = (id) =>
         </template>
 
         <template #column-clientFk="{ row }">
-            <QTd @click.stop>
-                <span class="link" v-text="row.clientName" :title="row.clientName" />
-                <CustomerDescriptorProxy :id="row.clientFk" />
-            </QTd>
+            <span class="link" @click.stop :title="row.clientName">
+                {{ row.clientName }}
+                <CustomerDescriptorProxy :id="row.clientFk" dense
+            /></span>
         </template>
-
-        <template #column-salesPersonFk="{ row }">
-            <QTd @click.stop>
-                <span class="link" v-text="row.salesPerson" />
-                <WorkerDescriptorProxy :id="row.salesPersonFk" dense />
-            </QTd>
+        <template #column-departmentFk="{ row }">
+            <span class="link" @click.stop :title="row.departmentName">
+                {{ row.departmentName }}
+                <DepartmentDescriptorProxy :id="row.departmentFk" dense
+            /></span>
         </template>
     </VnTable>
 </template>
diff --git a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue
index 48710d696..1cadd4cb4 100644
--- a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue
+++ b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue
@@ -9,7 +9,6 @@ import VnInput from 'src/components/common/VnInput.vue';
 import VnInputNumber from 'src/components/common/VnInputNumber.vue';
 import FetchData from 'src/components/FetchData.vue';
 import { dateRange } from 'src/filters';
-import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
 
 defineProps({ dataKey: { type: String, required: true } });
 const { t, te } = useI18n();
@@ -78,7 +77,7 @@ const getLocale = (label) => {
                     <VnInput
                         :label="t('globals.params.clientFk')"
                         v-model="params.clientFk"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -87,7 +86,7 @@ const getLocale = (label) => {
                     <VnInput
                         :label="t('params.orderFk')"
                         v-model="params.orderFk"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -96,7 +95,7 @@ const getLocale = (label) => {
                     <VnInputNumber
                         :label="t('params.scopeDays')"
                         v-model="params.scopeDays"
-                        is-outlined
+                        filled
                         @update:model-value="(val) => handleScopeDays(params, val)"
                         @remove="(val) => handleScopeDays(params, val)"
                     />
@@ -107,66 +106,54 @@ const getLocale = (label) => {
                     <VnInput
                         :label="t('params.nickname')"
                         v-model="params.nickname"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnSelectWorker
-                        outlined
+                    <VnSelect
                         dense
-                        rounded
-                        :label="t('globals.params.salesPersonFk')"
-                        v-model="params.salesPersonFk"
-                        :params="{ departmentCodes: ['VT'] }"
-                        :no-one="true"
-                    >
-                    </VnSelectWorker>
+                        filled
+                        :label="t('globals.params.departmentFk')"
+                        v-model="params.departmentFk"
+                        url="Departments"
+                    />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        :label="t('params.refFk')"
-                        v-model="params.refFk"
-                        is-outlined
-                    />
+                    <VnInput :label="t('params.refFk')" v-model="params.refFk" filled />
                 </QItemSection>
             </QItem>
 
             <QItem>
                 <QItemSection>
                     <VnSelect
-                        outlined
                         dense
-                        rounded
+                        filled
                         :label="t('params.agencyModeFk')"
                         v-model="params.agencyModeFk"
                         url="AgencyModes/isActive"
-                        is-outlined
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
                     <VnSelect
-                        outlined
                         dense
-                        rounded
+                        filled
                         :label="t('globals.params.stateFk')"
                         v-model="params.stateFk"
                         url="States"
-                        is-outlined
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
                     <VnSelect
-                        outlined
                         dense
-                        rounded
+                        filled
                         :label="t('params.groupedStates')"
                         v-model="params.alertLevel"
                         :options="groupedStates"
@@ -177,9 +164,8 @@ const getLocale = (label) => {
             <QItem>
                 <QItemSection>
                     <VnSelect
-                        outlined
                         dense
-                        rounded
+                        filled
                         :label="t('globals.params.warehouseFk')"
                         v-model="params.warehouseFk"
                         :options="warehouses"
@@ -189,9 +175,8 @@ const getLocale = (label) => {
             <QItem>
                 <QItemSection>
                     <VnSelect
-                        outlined
                         dense
-                        rounded
+                        filled
                         :label="t('globals.params.countryFk')"
                         v-model="params.countryFk"
                         url="Countries"
@@ -201,9 +186,8 @@ const getLocale = (label) => {
             <QItem>
                 <QItemSection>
                     <VnSelect
-                        outlined
                         dense
-                        rounded
+                        filled
                         :label="t('globals.params.provinceFk')"
                         v-model="params.provinceFk"
                         url="Provinces"
@@ -213,23 +197,8 @@ const getLocale = (label) => {
             <QItem>
                 <QItemSection>
                     <VnSelect
-                        outlined
                         dense
-                        rounded
-                        :label="t('globals.params.departmentFk')"
-                        v-model="params.department"
-                        option-label="name"
-                        option-value="name"
-                        url="Departments"
-                    />
-                </QItemSection>
-            </QItem>
-            <QItem>
-                <QItemSection>
-                    <VnSelect
-                        outlined
-                        dense
-                        rounded
+                        filled
                         :label="t('globals.params.packing')"
                         v-model="params.packing"
                         url="ItemPackingTypes"
diff --git a/src/pages/Monitor/Ticket/MonitorTickets.vue b/src/pages/Monitor/Ticket/MonitorTickets.vue
index 782175cd6..b46eb5bfa 100644
--- a/src/pages/Monitor/Ticket/MonitorTickets.vue
+++ b/src/pages/Monitor/Ticket/MonitorTickets.vue
@@ -2,7 +2,7 @@
 import { ref, computed, onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import FetchData from 'components/FetchData.vue';
-import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
 import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
 import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
@@ -49,8 +49,8 @@ function exprBuilder(param, value) {
     switch (param) {
         case 'stateFk':
             return { 'ts.stateFk': value };
-        case 'salesPersonFk':
-            return { 'c.salesPersonFk': !value ? null : value };
+        case 'departmentFk':
+            return { 'c.departmentFk': !value ? null : value };
         case 'provinceFk':
             return { 'a.provinceFk': value };
         case 'theoreticalHour':
@@ -108,19 +108,18 @@ const columns = computed(() => [
         },
     },
     {
-        label: t('salesClientsTable.salesPerson'),
-        name: 'salesPersonFk',
-        field: 'userName',
         align: 'left',
-        columnFilter: {
-            component: 'select',
-            attrs: {
-                url: 'Workers/search?departmentCodes=["VT"]',
-                fields: ['id', 'name', 'nickname', 'code'],
-                sortBy: 'nickname ASC',
-                optionLabel: 'nickname',
-            },
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
+        component: 'select',
+        attrs: {
+            url: 'Departments',
         },
+        create: true,
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
     {
         label: t('salesClientsTable.date'),
@@ -437,10 +436,10 @@ const openTab = (id) => useOpenURL(`#/ticket/${id}/sale`);
                 <CustomerDescriptorProxy :id="row.clientFk" />
             </div>
         </template>
-        <template #column-salesPersonFk="{ row }">
-            <div @click.stop :title="row.userName">
-                <span class="link" v-text="dashIfEmpty(row.userName)" />
-                <WorkerDescriptorProxy :id="row.salesPersonFk" />
+        <template #column-departmentFk="{ row }">
+            <div @click.stop :title="row.departmentName">
+                <span class="link" v-text="dashIfEmpty(row.departmentName)" />
+                <DepartmentDescriptorProxy :id="row.departmentFk" />
             </div>
         </template>
         <template #column-shippedDate="{ row }">
@@ -450,21 +449,19 @@ const openTab = (id) => useOpenURL(`#/ticket/${id}/sale`);
             <span :title="row.province" v-text="row.province" />
         </template>
         <template #column-state="{ row }">
-            <div @click.stop.prevent>
-                <div v-if="row.refFk">
-                    <span class="link">{{ row.refFk }}</span>
-                    <InvoiceOutDescriptorProxy :id="row.invoiceOutId" />
-                </div>
-                <QBadge
-                    v-else
-                    :color="stateColors[row.classColor] || 'transparent'"
-                    :text-color="stateColors[row.classColor] ? 'black' : 'white'"
-                    class="q-pa-sm"
-                    style="font-size: 14px"
-                >
-                    {{ row.state }}
-                </QBadge>
+            <div v-if="row.refFk" @click.stop.prevent>
+                <span class="link">{{ row.refFk }}</span>
+                <InvoiceOutDescriptorProxy :id="row.invoiceOutId" />
             </div>
+            <QBadge
+                v-else
+                :color="stateColors[row.classColor] || 'transparent'"
+                :text-color="stateColors[row.classColor] ? 'black' : 'white'"
+                class="q-pa-sm"
+                style="font-size: 14px"
+            >
+                {{ row.state }}
+            </QBadge>
         </template>
         <template #column-isFragile="{ row }">
             <QIcon v-if="row.isFragile" name="local_bar" color="primary" size="sm">
diff --git a/src/pages/Monitor/locale/en.yml b/src/pages/Monitor/locale/en.yml
index c049a5e53..a9ce36ffd 100644
--- a/src/pages/Monitor/locale/en.yml
+++ b/src/pages/Monitor/locale/en.yml
@@ -7,7 +7,6 @@ salesClientsTable:
     to: To
     date: Date
     hour: Hour
-    salesPerson: Salesperson
     client: Client
 salesOrdersTable:
     delete: Delete
diff --git a/src/pages/Monitor/locale/es.yml b/src/pages/Monitor/locale/es.yml
index a02d7f36f..6086eda6b 100644
--- a/src/pages/Monitor/locale/es.yml
+++ b/src/pages/Monitor/locale/es.yml
@@ -7,7 +7,6 @@ salesClientsTable:
     to: Hasta
     date: Fecha
     hour: Hora
-    salesPerson: Comercial
     client: Cliente
 salesOrdersTable:
     delete: Eliminar
diff --git a/src/pages/Order/Card/CatalogFilterValueDialog.vue b/src/pages/Order/Card/CatalogFilterValueDialog.vue
index d1bd48c9e..10273a254 100644
--- a/src/pages/Order/Card/CatalogFilterValueDialog.vue
+++ b/src/pages/Order/Card/CatalogFilterValueDialog.vue
@@ -57,9 +57,8 @@ const getSelectedTagValues = async (tag) => {
                 option-value="id"
                 option-label="name"
                 dense
-                outlined
                 class="q-mb-md"
-                rounded
+                filled
                 :emit-value="false"
                 use-input
                 @update:model-value="getSelectedTagValues"
@@ -79,8 +78,7 @@ const getSelectedTagValues = async (tag) => {
                         option-value="value"
                         option-label="value"
                         dense
-                        outlined
-                        rounded
+                        filled
                         emit-value
                         use-input
                         :disable="!value || !selectedTag"
@@ -92,16 +90,14 @@ const getSelectedTagValues = async (tag) => {
                         v-model="value.value"
                         :label="t('components.itemsFilterPanel.value')"
                         :disable="!value"
-                        is-outlined
                         class="col"
                         data-cy="catalogFilterValueDialogValueInput"
                     />
                     <QBtn
                         icon="delete"
                         size="md"
-                        outlined
                         dense
-                        rounded
+                        filled
                         flat
                         class="filter-icon col-2"
                         @click="tagValues.splice(index, 1)"
diff --git a/src/pages/Order/Card/OrderBasicData.vue b/src/pages/Order/Card/OrderBasicData.vue
index 9c02d7494..73b8b6fc8 100644
--- a/src/pages/Order/Card/OrderBasicData.vue
+++ b/src/pages/Order/Card/OrderBasicData.vue
@@ -64,17 +64,7 @@ const orderFilter = {
         {
             relation: 'client',
             scope: {
-                fields: [
-                    'salesPersonFk',
-                    'name',
-                    'isActive',
-                    'isFreezed',
-                    'isTaxDataChecked',
-                ],
-                include: {
-                    relation: 'salesPersonUser',
-                    scope: { fields: ['id', 'name'] },
-                },
+                fields: ['name', 'isActive', 'isFreezed', 'isTaxDataChecked'],
             },
         },
     ],
@@ -167,7 +157,7 @@ const onClientChange = async (clientId) => {
                             !data.isConfirmed &&
                             agencyList?.length &&
                             agencyList.some(
-                                (agency) => agency.agencyModeFk === data.agency_id
+                                (agency) => agency.agencyModeFk === data.agency_id,
                             )
                                 ? data.agencyModeFk
                                 : null
diff --git a/src/pages/Order/Card/OrderCard.vue b/src/pages/Order/Card/OrderCard.vue
index ad5c73a87..11dbbe532 100644
--- a/src/pages/Order/Card/OrderCard.vue
+++ b/src/pages/Order/Card/OrderCard.vue
@@ -1,14 +1,16 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue';
 import filter from './OrderFilter.js';
 </script>
 
 <template>
-    <VnCardBeta
-        data-key="Order"
+    <VnCard
+        :data-key="$attrs['data-key'] ?? 'Order'"
         url="Orders"
         :filter="filter"
         :descriptor="OrderDescriptor"
+        v-bind="$attrs"
+        v-on="$attrs"
     />
 </template>
diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue
index d16a92017..cb380c48f 100644
--- a/src/pages/Order/Card/OrderCatalogFilter.vue
+++ b/src/pages/Order/Card/OrderCatalogFilter.vue
@@ -221,8 +221,7 @@ function addOrder(value, field, params) {
                         option-value="id"
                         option-label="name"
                         dense
-                        outlined
-                        rounded
+                        filled
                         emit-value
                         use-input
                         sort-by="name ASC"
@@ -251,8 +250,7 @@ function addOrder(value, field, params) {
                         v-model="orderBySelected"
                         :options="orderByList"
                         dense
-                        outlined
-                        rounded
+                        filled
                         @update:model-value="(value) => addOrder(value, 'field', params)"
                     />
                 </QItemSection>
@@ -264,8 +262,7 @@ function addOrder(value, field, params) {
                         v-model="orderWaySelected"
                         :options="orderWayList"
                         dense
-                        outlined
-                        rounded
+                        filled
                         @update:model-value="(value) => addOrder(value, 'way', params)"
                     />
                 </QItemSection>
@@ -275,8 +272,7 @@ function addOrder(value, field, params) {
                 <VnInput
                     :label="t('components.itemsFilterPanel.value')"
                     dense
-                    outlined
-                    rounded
+                    filled
                     :is-clearable="false"
                     v-model="searchByTag"
                     @keyup.enter="(val) => onSearchByTag(val, params)"
diff --git a/src/pages/Order/Card/OrderDescriptor.vue b/src/pages/Order/Card/OrderDescriptor.vue
index 0d18864dc..ee66bb57e 100644
--- a/src/pages/Order/Card/OrderDescriptor.vue
+++ b/src/pages/Order/Card/OrderDescriptor.vue
@@ -4,11 +4,11 @@ import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { toCurrency, toDate } from 'src/filters';
 import { useState } from 'src/composables/useState';
-import filter from './OrderFilter.js';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import FetchData from 'components/FetchData.vue';
-import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import OrderCard from './OrderCard.vue';
+import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 
 const DEFAULT_ITEMS = 0;
 
@@ -24,11 +24,14 @@ const route = useRoute();
 const state = useState();
 const { t } = useI18n();
 const getTotalRef = ref();
+const total = ref(0);
 
 const entityId = computed(() => {
     return $props.id || route.params.id;
 });
 
+const orderTotal = computed(() => state.get('orderTotal') ?? 0);
+
 const setData = (entity) => {
     if (!entity) return;
     getTotalRef.value && getTotalRef.value.fetch();
@@ -38,9 +41,6 @@ const setData = (entity) => {
 const getConfirmationValue = (isConfirmed) => {
     return t(isConfirmed ? 'globals.confirmed' : 'order.summary.notConfirmed');
 };
-
-const orderTotal = computed(() => state.get('orderTotal') ?? 0);
-const total = ref(0);
 </script>
 
 <template>
@@ -54,23 +54,23 @@ const total = ref(0);
         "
     />
     <CardDescriptor
-        ref="descriptor"
-        :url="`Orders/${entityId}`"
-        :filter="filter"
+        v-bind="$attrs"
+        :id="entityId"
+        :card="OrderCard"
         title="client.name"
         @on-fetch="setData"
-        data-key="Order"
+        module="Order"
     >
         <template #body="{ entity }">
             <VnLv
                 :label="t('globals.state')"
                 :value="getConfirmationValue(entity.isConfirmed)"
             />
-            <VnLv :label="t('order.field.salesPersonFk')">
+            <VnLv :label="t('customer.summary.team')">
                 <template #value>
                     <span class="link">
-                        {{ entity?.client?.salesPersonUser?.name || '-' }}
-                        <WorkerDescriptorProxy :id="entity?.client?.salesPersonFk" />
+                        {{ entity?.client?.department?.name || '-' }}
+                        <DepartmentDescriptorProxy :id="entity?.client?.departmentFk" />
                     </span>
                 </template>
             </VnLv>
diff --git a/src/pages/Order/Card/OrderDescriptorProxy.vue b/src/pages/Order/Card/OrderDescriptorProxy.vue
index 04ebb054a..1dff1b620 100644
--- a/src/pages/Order/Card/OrderDescriptorProxy.vue
+++ b/src/pages/Order/Card/OrderDescriptorProxy.vue
@@ -12,6 +12,11 @@ const $props = defineProps({
 
 <template>
     <QPopupProxy>
-        <OrderDescriptor v-if="$props.id" :id="$props.id" :summary="OrderSummary" />
+        <OrderDescriptor
+            v-if="$props.id"
+            :id="$props.id"
+            :summary="OrderSummary"
+            data-key="OrderDescriptor"
+        />
     </QPopupProxy>
 </template>
diff --git a/src/pages/Order/Card/OrderFilter.js b/src/pages/Order/Card/OrderFilter.js
index 3e521b92c..d45578529 100644
--- a/src/pages/Order/Card/OrderFilter.js
+++ b/src/pages/Order/Card/OrderFilter.js
@@ -10,14 +10,14 @@ export default {
             relation: 'client',
             scope: {
                 fields: [
-                    'salesPersonFk',
+                    'departmentFk',
                     'name',
                     'isActive',
                     'isFreezed',
                     'isTaxDataChecked',
                 ],
                 include: {
-                    relation: 'salesPersonUser',
+                    relation: 'department',
                     scope: { fields: ['id', 'name'] },
                 },
             },
diff --git a/src/pages/Order/Card/OrderFilter.vue b/src/pages/Order/Card/OrderFilter.vue
index c387be241..5f91153ac 100644
--- a/src/pages/Order/Card/OrderFilter.vue
+++ b/src/pages/Order/Card/OrderFilter.vue
@@ -6,7 +6,6 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
 import VnSelect from 'components/common/VnSelect.vue';
 import VnInputDate from 'components/common/VnInputDate.vue';
 import VnInput from 'components/common/VnInput.vue';
-import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
 
 const { t } = useI18n();
 const props = defineProps({
@@ -50,8 +49,7 @@ const sourceList = ref([]);
                     v-model="params.clientFk"
                     lazy-rules
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnSelect
                     :label="t('agency')"
@@ -59,38 +57,29 @@ const sourceList = ref([]);
                     :options="agencyList"
                     :input-debounce="0"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
-                <VnSelectWorker
-                    :label="t('globals.salesPerson')"
-                    v-model="params.workerFk"
-                    :params="{
-                        departmentCodes: ['VT'],
-                    }"
+                <VnSelect
                     dense
-                    outlined
-                    rounded
+                    filled
+                    :label="t('globals.params.departmentFk')"
+                    v-model="params.departmentFk"
+                    option-value="id"
+                    option-label="name"
+                    url="Departments"
                 />
                 <VnInputDate
                     v-model="params.from"
                     :label="t('fromLanded')"
                     dense
-                    outlined
-                    rounded
-                />
-                <VnInputDate
-                    v-model="params.to"
-                    :label="t('toLanded')"
-                    dense
-                    outlined
-                    rounded
+                    filled
                 />
+                <VnInputDate v-model="params.to" :label="t('toLanded')" dense filled />
                 <VnInput
                     :label="t('orderId')"
                     v-model="params.orderFk"
                     lazy-rules
-                    is-outlined
+                    filled
                 />
                 <VnSelect
                     :label="t('application')"
@@ -99,8 +88,7 @@ const sourceList = ref([]);
                     option-label="value"
                     option-value="value"
                     dense
-                    outlined
-                    rounded
+                    filled
                     :input-debounce="0"
                 />
                 <QCheckbox
@@ -125,7 +113,6 @@ en:
         search: Includes
         clientFk: Client
         agencyModeFk: Agency
-        salesPersonFk: Sales Person
         from: From
         to: To
         orderFk: Order
@@ -136,7 +123,6 @@ en:
         showEmpty: Show Empty
     customerId: Customer ID
     agency: Agency
-    salesPerson: Sales Person
     fromLanded: From Landed
     toLanded: To Landed
     orderId: Order ID
@@ -144,12 +130,13 @@ en:
     myTeam: My Team
     isConfirmed: Order Confirmed
     showEmpty: Show Empty
+    departmentFk: Department
 es:
     params:
+        departmentFk: Departamento
         search: Búsqueda
         clientFk: Cliente
         agencyModeFk: Agencia
-        salesPersonFk: Comercial
         from: Desde
         to: Hasta
         orderFk: Cesta
@@ -160,7 +147,6 @@ es:
         showEmpty: Mostrar vacías
     customerId: ID Cliente
     agency: Agencia
-    salesPerson: Comercial
     fromLanded: Desde F. entrega
     toLanded: Hasta F. entrega
     orderId: ID Cesta
diff --git a/src/pages/Order/Card/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue
index 1b864de6f..231efbcd9 100644
--- a/src/pages/Order/Card/OrderLines.vue
+++ b/src/pages/Order/Card/OrderLines.vue
@@ -295,13 +295,11 @@ watch(
         :user-filter="lineFilter"
     >
         <template #column-image="{ row }">
-            <div class="image-wrapper">
-                <VnImg
-                    :id="parseInt(row?.item?.image)"
-                    class="rounded"
-                    zoom-resolution="1600x900"
-                />
-            </div>
+            <VnImg
+                :id="parseInt(row?.item?.image)"
+                class="rounded"
+                zoom-resolution="1600x900"
+            />
         </template>
         <template #column-id="{ row }">
             <span class="link" @click.stop>
@@ -361,12 +359,6 @@ watch(
     }
 }
 
-.image-wrapper {
-    height: 50px;
-    width: 50px;
-    margin-left: 30%;
-}
-
 .header {
     color: $primary;
     font-weight: bold;
diff --git a/src/pages/Order/Card/OrderSummary.vue b/src/pages/Order/Card/OrderSummary.vue
index a4bdb2881..10a458bfb 100644
--- a/src/pages/Order/Card/OrderSummary.vue
+++ b/src/pages/Order/Card/OrderSummary.vue
@@ -71,180 +71,174 @@ async function handleConfirm() {
 </script>
 
 <template>
-    <div class="q-pa-md">
-        <CardSummary
-            ref="summary"
-            :url="`Orders/${entityId}/summary`"
-            data-key="OrderSummary"
-        >
-            <template #header="{ entity }">
-                {{ t('order.summary.basket') }} #{{ entity?.id }} -
-                {{ entity?.client?.name }} ({{ entity?.clientFk }})
-            </template>
-            <template #header-right>
-                <QBtn
-                    flat
-                    text-color="white"
-                    :disabled="isConfirmed"
-                    :label="t('order.summary.confirm')"
-                    @click="handleConfirm()"
-                >
-                    <QTooltip>{{ t('order.summary.confirmLines') }}</QTooltip>
-                </QBtn>
-            </template>
-            <template #menu="{ entity }">
-                <OrderDescriptorMenu :order="entity" />
-            </template>
-            <template #body="{ entity }">
-                <QCard class="vn-one">
-                    <VnTitle
-                        :url="`#/order/${entity.id}/basic-data`"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                    <VnLv label="ID" :value="entity.id" />
-                    <VnLv :label="t('globals.alias')" dash>
-                        <template #value>
-                            <span class="link">
-                                {{ dashIfEmpty(entity?.address?.nickname) }}
-                                <CustomerDescriptorProxy :id="entity?.clientFk" />
-                            </span>
-                        </template>
-                    </VnLv>
-                    <VnLv
-                        :label="t('globals.company')"
-                        :value="entity?.address?.companyFk"
-                    />
-                    <VnLv
-                        :label="t('globals.confirmed')"
-                        :value="Boolean(entity?.isConfirmed)"
-                    />
-                </QCard>
-                <QCard class="vn-one">
-                    <VnTitle
-                        :url="`#/order/${entity.id}/basic-data`"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                    <VnLv
-                        :label="t('order.summary.created')"
-                        :value="toDateHourMinSec(entity?.created)"
-                    />
-                    <VnLv
-                        :label="t('globals.confirmed')"
-                        :value="toDateHourMinSec(entity?.confirmed)"
-                    />
-                    <VnLv
-                        :label="t('globals.landed')"
-                        :value="toDateHourMinSec(entity?.landed)"
-                    />
-                    <VnLv :label="t('globals.phone')">
-                        <template #value>
-                            {{ dashIfEmpty(entity?.address?.phone) }}
-                            <a
-                                v-if="entity?.address?.phone"
-                                :href="`tel:${entity?.address?.phone}`"
-                                class="text-primary"
-                            >
-                                <QIcon name="phone" />
-                            </a>
-                        </template>
-                    </VnLv>
-                    <VnLv
-                        :label="t('order.summary.createdFrom')"
-                        :value="entity?.sourceApp"
-                    />
-                    <VnLv
-                        :label="t('order.summary.address')"
-                        :value="`${entity?.address?.street} - ${entity?.address?.city} (${entity?.address?.province?.name})`"
-                        class="order-summary-address"
-                    />
-                </QCard>
-                <QCard class="vn-one">
-                    <VnTitle :text="t('globals.pageTitles.notes')" />
-                    <p v-if="entity?.note" class="no-margin">
-                        {{ entity?.note }}
-                    </p>
-                </QCard>
-                <QCard class="vn-one">
-                    <VnTitle :text="t('order.summary.total')" />
-                    <VnLv>
-                        <template #label>
-                            <span class="text-h6">{{ t('globals.subtotal') }}</span>
-                        </template>
-                        <template #value>
-                            <span class="text-h6">{{
-                                toCurrency(entity?.subTotal)
-                            }}</span>
-                        </template>
-                    </VnLv>
-                    <VnLv>
-                        <template #label>
-                            <span class="text-h6">{{ t('globals.vat') }}</span>
-                        </template>
-                        <template #value>
-                            <span class="text-h6">{{ toCurrency(entity?.VAT) }}</span>
-                        </template>
-                    </VnLv>
-                    <VnLv>
-                        <template #label>
-                            <span class="text-h6">{{ t('order.summary.total') }}</span>
-                        </template>
-                        <template #value>
-                            <span class="text-h6">{{ toCurrency(entity?.total) }}</span>
-                        </template>
-                    </VnLv>
-                </QCard>
-                <QCard>
-                    <VnTitle :text="t('globals.details')" />
-                    <QTable :columns="detailsColumns" :rows="entity?.rows" flat>
-                        <template #header="props">
-                            <QTr :props="props">
-                                <QTh auto-width>{{ t('globals.item') }}</QTh>
-                                <QTh>{{ t('globals.description') }}</QTh>
-                                <QTh auto-width>{{ t('globals.quantity') }}</QTh>
-                                <QTh auto-width>{{ t('globals.price') }}</QTh>
-                                <QTh auto-width>{{ t('order.summary.amount') }}</QTh>
-                            </QTr>
-                        </template>
-                        <template #body="props">
-                            <QTr :props="props">
-                                <QTd key="item" :props="props" class="item">
-                                    <span class="link">
-                                        {{ props.row.item?.id }}
-                                        <ItemDescriptorProxy :id="props.row.item?.id" />
-                                    </span>
-                                </QTd>
-                                <QTd key="description" :props="props">
-                                    <div class="description">
-                                        <div class="name">
-                                            {{ props.row.item.name }}
-                                            <span
-                                                v-if="props.row.item.subName"
-                                                class="subName"
-                                            >
-                                                {{ props.row.item.subName }}
-                                            </span>
-                                        </div>
+    <CardSummary
+        ref="summary"
+        :url="`Orders/${entityId}/summary`"
+        data-key="OrderSummary"
+    >
+        <template #header="{ entity }">
+            {{ t('order.summary.basket') }} #{{ entity?.id }} -
+            {{ entity?.client?.name }} ({{ entity?.clientFk }})
+        </template>
+        <template #header-right>
+            <QBtn
+                flat
+                text-color="white"
+                :disabled="isConfirmed"
+                :label="t('order.summary.confirm')"
+                @click="handleConfirm()"
+            >
+                <QTooltip>{{ t('order.summary.confirmLines') }}</QTooltip>
+            </QBtn>
+        </template>
+        <template #menu="{ entity }">
+            <OrderDescriptorMenu :order="entity" />
+        </template>
+        <template #body="{ entity }">
+            <QCard class="vn-two">
+                <VnTitle
+                    :url="`#/order/${entity.id}/basic-data`"
+                    :text="t('globals.pageTitles.basicData')"
+                />
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
+                        <VnLv label="ID" :value="entity.id" />
+                        <VnLv :label="t('globals.alias')" dash>
+                            <template #value>
+                                <span class="link">
+                                    {{ dashIfEmpty(entity?.address?.nickname) }}
+                                    <CustomerDescriptorProxy :id="entity?.clientFk" />
+                                </span>
+                            </template>
+                        </VnLv>
+                        <VnLv
+                            :label="t('globals.company')"
+                            :value="entity?.address?.companyFk"
+                        />
+                        <VnLv
+                            :label="t('globals.confirmed')"
+                            :value="Boolean(entity?.isConfirmed)"
+                        />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('order.summary.created')"
+                            :value="toDateHourMinSec(entity?.created)"
+                        />
+                        <VnLv
+                            :label="t('globals.confirmed')"
+                            :value="toDateHourMinSec(entity?.confirmed)"
+                        />
+                        <VnLv
+                            :label="t('globals.landed')"
+                            :value="toDateHourMinSec(entity?.landed)"
+                        />
+                        <VnLv :label="t('globals.phone')">
+                            <template #value>
+                                {{ dashIfEmpty(entity?.address?.phone) }}
+                                <a
+                                    v-if="entity?.address?.phone"
+                                    :href="`tel:${entity?.address?.phone}`"
+                                    class="text-primary"
+                                >
+                                    <QIcon name="phone" />
+                                </a>
+                            </template>
+                        </VnLv>
+                        <VnLv
+                            :label="t('order.summary.createdFrom')"
+                            :value="entity?.sourceApp"
+                        />
+                        <VnLv
+                            :label="t('order.summary.address')"
+                            :value="`${entity?.address?.street} - ${entity?.address?.city} (${entity?.address?.province?.name})`"
+                            class="order-summary-address"
+                        />
+                    </div>
+                </div>
+            </QCard>
+            <QCard class="vn-one">
+                <VnTitle :text="t('globals.pageTitles.notes')" />
+                <p v-if="entity?.note" class="no-margin">
+                    {{ entity?.note }}
+                </p>
+            </QCard>
+            <QCard class="vn-one">
+                <VnTitle :text="t('order.summary.total')" />
+                <VnLv>
+                    <template #label>
+                        <span class="text-h6">{{ t('globals.subtotal') }}</span>
+                    </template>
+                    <template #value>
+                        <span class="text-h6">{{ toCurrency(entity?.subTotal) }}</span>
+                    </template>
+                </VnLv>
+                <VnLv>
+                    <template #label>
+                        <span class="text-h6">{{ t('globals.vat') }}</span>
+                    </template>
+                    <template #value>
+                        <span class="text-h6">{{ toCurrency(entity?.VAT) }}</span>
+                    </template>
+                </VnLv>
+                <VnLv>
+                    <template #label>
+                        <span class="text-h6">{{ t('order.summary.total') }}</span>
+                    </template>
+                    <template #value>
+                        <span class="text-h6">{{ toCurrency(entity?.total) }}</span>
+                    </template>
+                </VnLv>
+            </QCard>
+            <QCard>
+                <VnTitle :text="t('globals.details')" />
+                <QTable :columns="detailsColumns" :rows="entity?.rows" flat>
+                    <template #header="props">
+                        <QTr :props="props">
+                            <QTh auto-width>{{ t('globals.item') }}</QTh>
+                            <QTh>{{ t('globals.description') }}</QTh>
+                            <QTh auto-width>{{ t('globals.quantity') }}</QTh>
+                            <QTh auto-width>{{ t('globals.price') }}</QTh>
+                            <QTh auto-width>{{ t('order.summary.amount') }}</QTh>
+                        </QTr>
+                    </template>
+                    <template #body="props">
+                        <QTr :props="props">
+                            <QTd key="item" :props="props" class="item">
+                                <span class="link">
+                                    {{ props.row.item?.id }}
+                                    <ItemDescriptorProxy :id="props.row.item?.id" />
+                                </span>
+                            </QTd>
+                            <QTd key="description" :props="props">
+                                <div class="description">
+                                    <div class="name">
+                                        {{ props.row.item.name }}
+                                        <span
+                                            v-if="props.row.item.subName"
+                                            class="subName"
+                                        >
+                                            {{ props.row.item.subName }}
+                                        </span>
                                     </div>
-                                    <FetchedTags :item="props.row.item" :columns="3" />
-                                </QTd>
-                                <QTd key="quantity" :props="props">
-                                    {{ props.row.quantity }}
-                                </QTd>
-                                <QTd key="price" :props="props">
-                                    {{ toCurrency(props.row.price) }}
-                                </QTd>
-                                <QTd key="amount" :props="props">
-                                    {{
-                                        toCurrency(props.row?.quantity * props.row?.price)
-                                    }}
-                                </QTd>
-                            </QTr>
-                        </template>
-                    </QTable>
-                </QCard>
-            </template>
-        </CardSummary>
-    </div>
+                                </div>
+                                <FetchedTags :item="props.row.item" :columns="3" />
+                            </QTd>
+                            <QTd key="quantity" :props="props">
+                                {{ props.row.quantity }}
+                            </QTd>
+                            <QTd key="price" :props="props">
+                                {{ toCurrency(props.row.price) }}
+                            </QTd>
+                            <QTd key="amount" :props="props">
+                                {{ toCurrency(props.row?.quantity * props.row?.price) }}
+                            </QTd>
+                        </QTr>
+                    </template>
+                </QTable>
+            </QCard>
+        </template>
+    </CardSummary>
 </template>
 <style lang="scss">
 .cardSummary .summaryBody .vn-label-value.order-summary-address {
diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue
index 091275e32..f59ce6585 100644
--- a/src/pages/Order/OrderList.vue
+++ b/src/pages/Order/OrderList.vue
@@ -10,12 +10,12 @@ import axios from 'axios';
 import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
 import OrderFilter from './Card/OrderFilter.vue';
 import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
-import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
 
 import VnTable from 'src/components/VnTable/VnTable.vue';
 import VnInputDate from 'src/components/common/VnInputDate.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnSection from 'src/components/common/VnSection.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import { getAddresses } from '../Customer/composables/getAddresses';
 
 const { t } = useI18n();
@@ -59,22 +59,16 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        name: 'salesPersonFk',
-        label: t('module.salesPerson'),
-        columnFilter: {
-            component: 'select',
-            inWhere: true,
-            attrs: {
-                url: 'Workers/activeWithInheritedRole',
-                fields: ['id', 'name'],
-                where: { role: 'salesPerson' },
-                useLike: false,
-                optionValue: 'id',
-                optionLabel: 'name',
-                optionFilter: 'firstName',
-            },
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
+        component: 'select',
+        attrs: {
+            url: 'Departments',
         },
-        format: (row) => row?.name,
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
     {
         align: 'center',
@@ -147,7 +141,7 @@ const columns = computed(() => [
             {
                 title: t('globals.pageTitles.summary'),
                 icon: 'preview',
-                action: (row) => viewSummary(row.id, OrderSummary),
+                action: (row) => viewSummary(row.id, OrderSummary, 'lg-width'),
                 isPrimary: true,
             },
         ],
@@ -156,9 +150,7 @@ const columns = computed(() => [
 onMounted(async () => {
     if (!route.query) return;
     if (route.query?.createForm) {
-        const query = JSON.parse(route.query?.createForm);
-        formInitialData.value = query;
-        await onClientSelected({ ...formInitialData.value, clientFk: query?.clientFk });
+        await onClientSelected(JSON.parse(route.query?.createForm));
     } else if (route.query?.table) {
         const query = JSON.parse(route.query?.table);
         const clientFk = query?.clientFk;
@@ -177,7 +169,6 @@ watch(
                 tableRef.value.create.formInitialData = formInitialData.value;
         }
     },
-    { immediate: true },
 );
 
 async function onClientSelected({ clientFk }, formData = {}) {
@@ -191,13 +182,17 @@ async function onClientSelected({ clientFk }, formData = {}) {
     addressOptions.value = data;
     formData.defaultAddressFk = data[0].client.defaultAddressFk;
     formData.addressId = formData.defaultAddressFk;
-
-    formInitialData.value = { addressId: formData.addressId, clientFk };
+    formInitialData.value = { ...formData, clientFk };
     await fetchAgencies(formData);
 }
 
-async function fetchAgencies({ landed, addressId }) {
-    if (!landed || !addressId) return (agencyList.value = []);
+async function fetchAgencies(formData) {
+    const { landed, addressId } = formData;
+    if (!landed || !addressId) {
+        formData.defaultAddressFk = formInitialData.value.defaultAddressFk;
+
+        return (agencyList.value = []);
+    }
 
     const { data } = await axios.get('Agencies/landsThatDay', {
         params: {
@@ -220,6 +215,11 @@ const getDateColor = (date) => {
     if (difference == 0) return 'bg-warning';
     if (difference < 0) return 'bg-success';
 };
+
+const isDefaultAddress = (opt, data) => {
+    const addressId = data.defaultAddressFk ?? data.addressId;
+    return addressId === opt.id && opt.isActive;
+};
 </script>
 
 <template>
@@ -258,10 +258,10 @@ const getDateColor = (date) => {
                         <CustomerDescriptorProxy :id="row?.clientFk" />
                     </span>
                 </template>
-                <template #column-salesPersonFk="{ row }">
+                <template #column-departmentFk="{ row }">
                     <span class="link" @click.stop>
-                        {{ row?.name }}
-                        <WorkerDescriptorProxy :id="row?.salesPersonFk" />
+                        {{ row?.departmentName }}
+                        <DepartmentDescriptorProxy :id="row?.departmentFk" />
                     </span>
                 </template>
                 <template #column-landed="{ row }">
@@ -310,10 +310,7 @@ const getDateColor = (date) => {
                             >
                                 <QItemSection style="min-width: min-content" avatar>
                                     <QIcon
-                                        v-if="
-                                            scope.opt.isActive &&
-                                            data.defaultAddressFk === scope.opt.id
-                                        "
+                                        v-if="isDefaultAddress(scope.opt, data)"
                                         size="sm"
                                         color="grey"
                                         name="star"
diff --git a/src/pages/Order/locale/en.yml b/src/pages/Order/locale/en.yml
index 14e41c559..877a3c380 100644
--- a/src/pages/Order/locale/en.yml
+++ b/src/pages/Order/locale/en.yml
@@ -8,7 +8,6 @@ module:
     hour: Hour
     agency: Agency
     total: Total
-    salesPerson: Sales Person
     address: Address
     cerateOrder: Create order
 lines:
@@ -22,8 +21,6 @@ lines:
 params:
     tagGroups: Tags
 order:
-    field:
-        salesPersonFk: Sales Person
     form:
         clientFk: Client
         addressFk: Address
diff --git a/src/pages/Order/locale/es.yml b/src/pages/Order/locale/es.yml
index 44e243ad1..f7528ec28 100644
--- a/src/pages/Order/locale/es.yml
+++ b/src/pages/Order/locale/es.yml
@@ -8,7 +8,6 @@ module:
     hour: Hora
     agency: Agencia
     total: Total
-    salesPerson: Comercial
     address: Dirección
     cerateOrder: Crear cesta
 lines:
@@ -22,8 +21,6 @@ lines:
 params:
     tagGroups: Tags
 order:
-    field:
-        salesPersonFk: Comercial
     form:
         clientFk: Cliente
         addressFk: Dirección
diff --git a/src/pages/Route/Agency/AgencyList.vue b/src/pages/Route/Agency/AgencyList.vue
index 5c2904bf3..c01dd272c 100644
--- a/src/pages/Route/Agency/AgencyList.vue
+++ b/src/pages/Route/Agency/AgencyList.vue
@@ -2,10 +2,13 @@
 import { computed } from 'vue';
 import { useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
+import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 import VnTable from 'components/VnTable/VnTable.vue';
 import VnSection from 'src/components/common/VnSection.vue';
+import AgencySummary from 'pages/Route/Agency/Card/AgencySummary.vue';
 
 const { t } = useI18n();
+const { viewSummary } = useSummaryDialog();
 const router = useRouter();
 const dataKey = 'AgencyList';
 function navigate(id) {
@@ -40,16 +43,22 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        label: t('isOwn'),
+        label: t('agency.isOwn'),
         name: 'isOwn',
         component: 'checkbox',
+        columnFilter: {
+            inWhere: true,
+        },
         cardVisible: true,
     },
     {
         align: 'left',
-        label: t('isAnyVolumeAllowed'),
+        label: t('agency.isAnyVolumeAllowed'),
         name: 'isAnyVolumeAllowed',
         component: 'checkbox',
+        columnFilter: {
+            inWhere: true,
+        },
         cardVisible: true,
     },
     {
@@ -58,9 +67,10 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('Client ticket list'),
+                title: t('globals.pageTitles.summary'),
                 icon: 'preview',
-                action: (row) => navigate(row.id),
+                action: (row) => viewSummary(row?.id, AgencySummary),
+                isPrimary: true,
             },
         ],
     },
@@ -82,7 +92,7 @@ const columns = computed(() => [
             <VnTable
                 :data-key
                 :columns="columns"
-                is-editable="false"
+                :is-editable="false"
                 :right-search="false"
                 :use-model="true"
                 redirect="route/agency"
@@ -103,11 +113,3 @@ const columns = computed(() => [
     justify-content: center;
 }
 </style>
-<i18n>
-    es:
-        isOwn: Tiene propietario
-        isAnyVolumeAllowed: Permite cualquier volumen
-    en:
-        isOwn: Has owner
-        isAnyVolumeAllowed: Allows any volume
-</i18n>
diff --git a/src/pages/Route/Agency/Card/AgencyBasicData.vue b/src/pages/Route/Agency/Card/AgencyBasicData.vue
index 4270b136c..4f8f17163 100644
--- a/src/pages/Route/Agency/Card/AgencyBasicData.vue
+++ b/src/pages/Route/Agency/Card/AgencyBasicData.vue
@@ -21,7 +21,7 @@ const warehouses = ref([]);
         @on-fetch="(data) => (warehouses = data)"
         auto-load
     />
-    <FormModel :update-url="`Agencies/${routeId}`" model="Agency" auto-load>
+    <FormModel :url-update="`Agencies/${routeId}`" model="Agency" auto-load>
         <template #form="{ data }">
             <VnRow>
                 <VnInput v-model="data.name" :label="t('globals.name')" />
diff --git a/src/pages/Route/Agency/Card/AgencyCard.vue b/src/pages/Route/Agency/Card/AgencyCard.vue
index 7dc31f8ba..9fd3fe5e5 100644
--- a/src/pages/Route/Agency/Card/AgencyCard.vue
+++ b/src/pages/Route/Agency/Card/AgencyCard.vue
@@ -1,7 +1,7 @@
 <script setup>
 import AgencyDescriptor from 'pages/Route/Agency/Card/AgencyDescriptor.vue';
-import VnCardBeta from 'src/components/common/VnCardBeta.vue';
+import VnCard from 'src/components/common/VnCard.vue';
 </script>
 <template>
-    <VnCardBeta data-key="Agency" url="Agencies" :descriptor="AgencyDescriptor" />
+    <VnCard data-key="Agency" url="Agencies" :descriptor="AgencyDescriptor" :filter="{ where: { id: $route.params.id } }" />
 </template>
diff --git a/src/pages/Route/Agency/Card/AgencyDescriptor.vue b/src/pages/Route/Agency/Card/AgencyDescriptor.vue
index a0472c6c3..64b33cc06 100644
--- a/src/pages/Route/Agency/Card/AgencyDescriptor.vue
+++ b/src/pages/Route/Agency/Card/AgencyDescriptor.vue
@@ -3,7 +3,7 @@ import { computed } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
 import { useArrayData } from 'src/composables/useArrayData';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'components/ui/VnLv.vue';
 
 const props = defineProps({
@@ -17,18 +17,19 @@ const props = defineProps({
 const { t } = useI18n();
 const route = useRoute();
 const entityId = computed(() => props.id || route.params.id);
-const { store } = useArrayData('Parking');
+const { store } = useArrayData();
 const card = computed(() => store.data);
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         data-key="Agency"
         :url="`Agencies/${entityId}`"
         :title="card?.name"
         :subtitle="props.id"
+        :to-module="{ name: 'RouteAgency' }"
     >
         <template #body="{ entity: agency }">
             <VnLv :label="t('globals.name')" :value="agency.name" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
diff --git a/src/pages/Route/Agency/Card/AgencyDescriptorProxy.vue b/src/pages/Route/Agency/Card/AgencyDescriptorProxy.vue
new file mode 100644
index 000000000..e5c1249b2
--- /dev/null
+++ b/src/pages/Route/Agency/Card/AgencyDescriptorProxy.vue
@@ -0,0 +1,20 @@
+<script setup>
+import AgencyDescriptor from 'pages/Route/Agency/Card/AgencyDescriptor.vue';
+import AgencySummary from './AgencySummary.vue';
+
+const $props = defineProps({
+    id: {
+        type: Number,
+        required: true,
+    },
+    summary: {
+        type: Object,
+        default: null,
+    },
+});
+</script>
+<template>
+    <QPopupProxy>
+        <AgencyDescriptor v-if="$props.id" :id="$props.id" :summary="AgencySummary" />
+    </QPopupProxy>
+</template>
diff --git a/src/pages/Route/Agency/Card/AgencySummary.vue b/src/pages/Route/Agency/Card/AgencySummary.vue
index 71a6d1066..ab274939a 100644
--- a/src/pages/Route/Agency/Card/AgencySummary.vue
+++ b/src/pages/Route/Agency/Card/AgencySummary.vue
@@ -6,29 +6,31 @@ import { useI18n } from 'vue-i18n';
 import CardSummary from 'components/ui/CardSummary.vue';
 import VnLv from 'components/ui/VnLv.vue';
 import VnTitle from 'src/components/common/VnTitle.vue';
+import VnCheckbox from 'components/common/VnCheckbox.vue';
 
+const route = useRoute();
 const $props = defineProps({ id: { type: Number, default: 0 } });
 const { t } = useI18n();
-const entityId = computed(() => $props.id || useRoute().params.id);
+const entityId = computed(() => $props.id || route.params.id);
 </script>
 
 <template>
     <div class="q-pa-md">
-        <CardSummary :url="`Agencies/${entityId}`" data-key="Agency">
+        <CardSummary :url="`Agencies/${entityId}`" data-key="Agency" module-name="Agency">
             <template #header="{ entity: agency }">{{ agency.name }}</template>
             <template #body="{ entity: agency }">
                 <QCard class="vn-one">
                     <VnTitle
-                        :url="`#/agency/${entityId}/basic-data`"
+                        :url="`#/${route.meta.moduleName.toLowerCase()}/agency/${entityId}/basic-data`"
                         :text="t('globals.pageTitles.basicData')"
                     />
                     <VnLv :label="t('globals.name')" :value="agency.name" />
-                    <QCheckbox
+                    <VnCheckbox
                         :label="t('agency.isOwn')"
                         v-model="agency.isOwn"
                         :disable="true"
                     />
-                    <QCheckbox
+                    <VnCheckbox
                         :label="t('agency.isAnyVolumeAllowed')"
                         v-model="agency.isAnyVolumeAllowed"
                         :disable="true"
diff --git a/src/pages/Route/Agency/Card/AgencyWorkcenter.vue b/src/pages/Route/Agency/Card/AgencyWorkcenter.vue
index 9a9213868..d33c9f753 100644
--- a/src/pages/Route/Agency/Card/AgencyWorkcenter.vue
+++ b/src/pages/Route/Agency/Card/AgencyWorkcenter.vue
@@ -80,6 +80,7 @@ async function deleteWorCenter(id) {
                                 color="primary"
                                 round
                                 flat
+                                data-cy="removeWorkCenterBtn"
                             />
                         </QItemSection>
                     </QItem>
diff --git a/src/pages/Route/Agency/locale/en.yml b/src/pages/Route/Agency/locale/en.yml
index 93f8b4aaa..78a687f2e 100644
--- a/src/pages/Route/Agency/locale/en.yml
+++ b/src/pages/Route/Agency/locale/en.yml
@@ -1,11 +1,12 @@
 agency:
     search: Search agency
-    searchInfo:    You can search by name
+    searchInfo: You can search by name and by id
     isOwn: Own
     isAnyVolumeAllowed: Any volume allowed
+    removeItem: Agency removed successfully
     notification:
-        removeItemError: Error removing agency
-        removeItem: WorkCenter removed successfully
+        removeItemError: Error removing work center
+        removeItem: Work center removed successfully
     pageTitles:
         agency: Agency
     searchBar:
diff --git a/src/pages/Route/Agency/locale/es.yml b/src/pages/Route/Agency/locale/es.yml
index 1efed0e9c..b6237a9f7 100644
--- a/src/pages/Route/Agency/locale/es.yml
+++ b/src/pages/Route/Agency/locale/es.yml
@@ -1,15 +1,14 @@
 agency:
     search: Buscar agencia
-    searchInfo: Puedes buscar por nombre
+    searchInfo: Puedes buscar por nombre y por id
     isOwn: Propio
     isAnyVolumeAllowed: Cualquier volumen
     removeItem: Agencia eliminada correctamente
     notification:
-        removeItemError: Error al eliminar la agencia
+        removeItemError: Error al eliminar la el centro de trabajo
         removeItem: Centro de trabajo eliminado correctamente
     pageTitles:
         agency: Agencia
     searchBar:
         info: Puedes buscar por nombre o id
         label: Buscar agencia...
-
diff --git a/src/pages/Route/Card/RouteAutonomousFilter.vue b/src/pages/Route/Card/RouteAutonomousFilter.vue
index f70f60e1c..fe631a0be 100644
--- a/src/pages/Route/Card/RouteAutonomousFilter.vue
+++ b/src/pages/Route/Card/RouteAutonomousFilter.vue
@@ -71,7 +71,7 @@ const exprBuilder = (param, value) => {
             <QList dense>
                 <QItem class="q-my-sm">
                     <QItemSection>
-                        <VnInput v-model="params.routeFk" :label="t('ID')" is-outlined />
+                        <VnInput v-model="params.routeFk" :label="t('ID')" filled />
                     </QItemSection>
                 </QItem>
                 <QItem class="q-my-sm" v-if="agencyList">
@@ -83,8 +83,7 @@ const exprBuilder = (param, value) => {
                             option-value="id"
                             option-label="name"
                             dense
-                            outlined
-                            rounded
+                            filled
                             emit-value
                             map-options
                             use-input
@@ -102,8 +101,7 @@ const exprBuilder = (param, value) => {
                             option-value="id"
                             option-label="name"
                             dense
-                            outlined
-                            rounded
+                            filled
                             emit-value
                             map-options
                             use-input
@@ -123,8 +121,7 @@ const exprBuilder = (param, value) => {
                             option-value="name"
                             option-label="name"
                             dense
-                            outlined
-                            rounded
+                            filled
                             emit-value
                             map-options
                             use-input
@@ -135,20 +132,12 @@ const exprBuilder = (param, value) => {
                 </QItem>
                 <QItem class="q-my-sm">
                     <QItemSection>
-                        <VnInputDate
-                            v-model="params.dated"
-                            :label="t('Date')"
-                            is-outlined
-                        />
+                        <VnInputDate v-model="params.dated" :label="t('Date')" filled />
                     </QItemSection>
                 </QItem>
                 <QItem class="q-my-sm">
                     <QItemSection>
-                        <VnInputDate
-                            v-model="params.from"
-                            :label="t('From')"
-                            is-outlined
-                        />
+                        <VnInputDate v-model="params.from" :label="t('From')" filled />
                     </QItemSection>
                 </QItem>
                 <QItem class="q-my-sm">
@@ -156,7 +145,7 @@ const exprBuilder = (param, value) => {
                         <VnInputDate
                             v-model="params.to"
                             :label="t('To')"
-                            is-outlined
+                            filled
                             is-clearable
                         />
                     </QItemSection>
@@ -166,23 +155,23 @@ const exprBuilder = (param, value) => {
                         <VnInput
                             v-model="params.packages"
                             :label="t('Packages')"
-                            is-outlined
+                            filled
                         />
                     </QItemSection>
                 </QItem>
                 <QItem class="q-my-sm">
                     <QItemSection>
-                        <VnInput v-model="params.m3" :label="t('m3')" is-outlined />
+                        <VnInput v-model="params.m3" :label="t('m3')" filled />
                     </QItemSection>
                 </QItem>
                 <QItem class="q-my-sm">
                     <QItemSection>
-                        <VnInput v-model="params.kmTotal" :label="t('Km')" is-outlined />
+                        <VnInput v-model="params.kmTotal" :label="t('Km')" filled />
                     </QItemSection>
                 </QItem>
                 <QItem class="q-my-sm">
                     <QItemSection>
-                        <VnInput v-model="params.price" :label="t('Price')" is-outlined />
+                        <VnInput v-model="params.price" :label="t('Price')" filled />
                     </QItemSection>
                 </QItem>
                 <QItem class="q-my-sm">
@@ -190,7 +179,7 @@ const exprBuilder = (param, value) => {
                         <VnInput
                             v-model="params.invoiceInFk"
                             :label="t('Received')"
-                            is-outlined
+                            filled
                         />
                     </QItemSection>
                 </QItem>
diff --git a/src/pages/Route/Card/RouteCard.vue b/src/pages/Route/Card/RouteCard.vue
index c178dc6bf..b71f7d088 100644
--- a/src/pages/Route/Card/RouteCard.vue
+++ b/src/pages/Route/Card/RouteCard.vue
@@ -1,10 +1,10 @@
 <script setup>
 import RouteDescriptor from 'pages/Route/Card/RouteDescriptor.vue';
-import VnCardBeta from 'src/components/common/VnCardBeta.vue';
+import VnCard from 'src/components/common/VnCard.vue';
 import filter from './RouteFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Route"
         url="Routes"
         :filter="filter"
diff --git a/src/pages/Route/Card/RouteDescriptor.vue b/src/pages/Route/Card/RouteDescriptor.vue
index 503cd1941..ee42d8e76 100644
--- a/src/pages/Route/Card/RouteDescriptor.vue
+++ b/src/pages/Route/Card/RouteDescriptor.vue
@@ -1,12 +1,12 @@
 <script setup>
 import { ref, computed, onMounted } from 'vue';
 import { useRoute } from 'vue-router';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
+import useCardDescription from 'composables/useCardDescription';
 import VnLv from 'components/ui/VnLv.vue';
 import { dashIfEmpty, toDate } from 'src/filters';
 import RouteDescriptorMenu from 'pages/Route/Card/RouteDescriptorMenu.vue';
 import filter from './RouteFilter.js';
-import useCardDescription from 'src/composables/useCardDescription';
 import axios from 'axios';
 
 const $props = defineProps({
@@ -27,23 +27,26 @@ const getZone = async () => {
     const filter = {
         where: { routeFk: $props.id ? $props.id : route.params.id },
     };
-    const { data } = await axios.get('Tickets/findOne', {
+    const { data } = await axios.get('Tickets/filter', {
         params: {
             filter: JSON.stringify(filter),
         },
     });
-    zoneId.value = data.zoneFk;
+
+    if (!data.length) return;
+    const firstRecord = data[0];
+
+    zoneId.value = firstRecord.zoneFk;
     const { data: zoneData } = await axios.get(`Zones/${zoneId.value}`);
     zone.value = zoneData.name;
 };
 const data = ref(useCardDescription());
-const setData = (entity) => (data.value = useCardDescription(entity.code, entity.id));
 onMounted(async () => {
     getZone();
 });
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         :url="`Routes/${entityId}`"
         :filter="filter"
         :title="null"
@@ -65,7 +68,7 @@ onMounted(async () => {
         <template #menu="{ entity }">
             <RouteDescriptorMenu :route="entity" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <i18n>
 es:
diff --git a/src/pages/Route/Card/RouteDescriptorProxy.vue b/src/pages/Route/Card/RouteDescriptorProxy.vue
index 1ff39a51e..7553469f3 100644
--- a/src/pages/Route/Card/RouteDescriptorProxy.vue
+++ b/src/pages/Route/Card/RouteDescriptorProxy.vue
@@ -7,6 +7,10 @@ const $props = defineProps({
         type: Number,
         required: true,
     },
+    summary: {
+        type: Object,
+        default: null,
+    },
 });
 </script>
 <template>
diff --git a/src/pages/Route/Card/RouteFilter.vue b/src/pages/Route/Card/RouteFilter.vue
index 21858102b..f830b83e2 100644
--- a/src/pages/Route/Card/RouteFilter.vue
+++ b/src/pages/Route/Card/RouteFilter.vue
@@ -25,7 +25,7 @@ const emit = defineEmits(['search']);
     >
         <template #tags="{ tag, formatFn }">
             <div class="q-gutter-x-xs">
-                <strong>{{ t(`params.${tag.label}`) }}: </strong>
+                <strong>{{ t(`route.params.${tag.label}`) }}: </strong>
                 <span>{{ formatFn(tag.value) }}</span>
             </div>
         </template>
@@ -33,10 +33,10 @@ const emit = defineEmits(['search']);
             <QItem class="q-my-sm">
                 <QItemSection>
                     <VnSelectWorker
+                        :label="t('globals.worker')"
                         v-model="params.workerFk"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :input-debounce="0"
                     />
                 </QItemSection>
@@ -44,15 +44,14 @@ const emit = defineEmits(['search']);
             <QItem class="q-my-sm">
                 <QItemSection>
                     <VnSelect
-                        :label="t('Agency')"
+                        :label="t('globals.agency')"
                         v-model="params.agencyModeFk"
                         url="AgencyModes/isActive"
                         sort-by="name ASC"
                         option-value="id"
                         option-label="name"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :input-debounce="0"
                     />
                 </QItemSection>
@@ -61,8 +60,8 @@ const emit = defineEmits(['search']);
                 <QItemSection>
                     <VnInputDate
                         v-model="params.from"
-                        :label="t('From')"
-                        is-outlined
+                        :label="t('globals.from')"
+                        filled
                         :disable="Boolean(params.scopeDays)"
                         @update:model-value="params.scopeDays = null"
                     />
@@ -72,8 +71,8 @@ const emit = defineEmits(['search']);
                 <QItemSection>
                     <VnInputDate
                         v-model="params.to"
-                        :label="t('To')"
-                        is-outlined
+                        :label="t('globals.to')"
+                        filled
                         :disable="Boolean(params.scopeDays)"
                         @update:model-value="params.scopeDays = null"
                     />
@@ -84,8 +83,8 @@ const emit = defineEmits(['search']);
                     <VnInput
                         v-model="params.scopeDays"
                         type="number"
-                        :label="t('Days Onward')"
-                        is-outlined
+                        :label="t('globals.daysOnward')"
+                        filled
                         clearable
                         :disable="Boolean(params.from || params.to)"
                         @update:model-value="
@@ -98,7 +97,7 @@ const emit = defineEmits(['search']);
             <QItem class="q-my-sm">
                 <QItemSection>
                     <VnSelect
-                        :label="t('Vehicle')"
+                        :label="t('globals.vehicle')"
                         v-model="params.vehicleFk"
                         url="Vehicles/active"
                         sort-by="numberPlate ASC"
@@ -106,28 +105,26 @@ const emit = defineEmits(['search']);
                         option-label="numberPlate"
                         option-filter-value="numberPlate"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :input-debounce="0"
                     />
                 </QItemSection>
             </QItem>
             <QItem class="q-my-sm">
                 <QItemSection>
-                    <VnInput v-model="params.m3" label="m³" is-outlined clearable />
+                    <VnInput v-model="params.m3" label="m³" filled clearable />
                 </QItemSection>
             </QItem>
             <QItem class="q-my-sm">
                 <QItemSection>
                     <VnSelect
-                        :label="t('Warehouse')"
+                        :label="t('globals.warehouse')"
                         v-model="params.warehouseFk"
                         url="Warehouses"
                         option-value="id"
                         option-label="name"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :input-debounce="0"
                     />
                 </QItemSection>
@@ -136,8 +133,8 @@ const emit = defineEmits(['search']);
                 <QItemSection>
                     <VnInput
                         v-model="params.description"
-                        :label="t('Description')"
-                        is-outlined
+                        :label="t('globals.description')"
+                        filled
                         clearable
                     />
                 </QItemSection>
@@ -146,7 +143,7 @@ const emit = defineEmits(['search']);
                 <QItemSection>
                     <QCheckbox
                         v-model="params.isOk"
-                        :label="t('Served')"
+                        :label="t('route.filter.Served')"
                         toggle-indeterminate
                     />
                 </QItemSection>
@@ -154,38 +151,3 @@ const emit = defineEmits(['search']);
         </template>
     </VnFilterPanel>
 </template>
-
-<i18n>
-en:
-    params:
-        warehouseFk: Warehouse
-        description: Description
-        m3: m³
-        scopeDays: Days Onward
-        vehicleFk: Vehicle
-        agencyModeFk: Agency
-        workerFk: Worker
-        from: From
-        to: To
-        Served: Served
-es:
-    params:
-        warehouseFk: Almacén
-        description: Descripción
-        m3: m³
-        scopeDays: Días en adelante
-        vehicleFk: Vehículo
-        agencyModeFk: Agencia
-        workerFk: Trabajador
-        from: Desde
-        to: Hasta
-    Warehouse: Almacén
-    Description: Descripción
-    Vehicle: Vehículo
-    Agency: Agencia
-    Worker: Trabajador
-    From: Desde
-    To: Hasta
-    Served: Servida
-    Days Onward: Días en adelante
-</i18n>
diff --git a/src/pages/Route/Card/RouteSummary.vue b/src/pages/Route/Card/RouteSummary.vue
index 3051972b2..86bdbb5c5 100644
--- a/src/pages/Route/Card/RouteSummary.vue
+++ b/src/pages/Route/Card/RouteSummary.vue
@@ -135,77 +135,82 @@ const ticketColumns = ref([
             <template #body="{ entity }">
                 <QCard class="vn-max">
                     <VnTitle
-                        :url="`#/route/${entityId}/basic-data`"
+                        :url="`#/${route.meta.moduleName.toLowerCase()}/${entityId}/basic-data`"
                         :text="t('globals.pageTitles.basicData')"
                     />
-                </QCard>
-
-                <QCard class="vn-one">
-                    <VnLv
-                        :label="t('route.summary.date')"
-                        :value="toDate(entity?.route.dated)"
-                    />
-                    <VnLv
-                        :label="t('route.summary.agency')"
-                        :value="entity?.route?.agencyMode?.name"
-                    />
-                    <VnLv
-                        :label="t('route.summary.vehicle')"
-                        :value="entity.route?.vehicle?.numberPlate"
-                    />
-                    <VnLv :label="t('route.summary.driver')">
-                        <template #value>
-                            <span class="link">
-                                {{ dashIfEmpty(entity?.route?.worker?.user?.name) }}
-                                <WorkerDescriptorProxy :id="entity.route?.workerFk" />
-                            </span>
-                        </template>
-                    </VnLv>
-                    <VnLv
-                        :label="t('route.summary.cost')"
-                        :value="toCurrency(entity.route?.cost)"
-                    />
-                    <VnLv
-                        :label="t('route.summary.volume')"
-                        :value="`${dashIfEmpty(entity?.route?.m3)} / ${dashIfEmpty(
-                            entity?.route?.vehicle?.m3
-                        )} m³`"
-                    />
-                    <VnLv
-                        :label="t('route.summary.packages')"
-                        :value="getTotalPackages(entity.tickets)"
-                    />
-                    <QCheckbox
-                        :label="
-                            entity.route.isOk
-                                ? t('route.summary.closed')
-                                : t('route.summary.open')
-                        "
-                        v-model="entity.route.isOk"
-                        :disable="true"
-                    />
-                </QCard>
-                <QCard class="vn-one">
-                    <VnLv
-                        :label="t('route.summary.started')"
-                        :value="toHour(entity?.route.started)"
-                    />
-                    <VnLv
-                        :label="t('route.summary.finished')"
-                        :value="toHour(entity?.route.finished)"
-                    />
-                    <VnLv
-                        :label="t('route.summary.kmStart')"
-                        :value="dashIfEmpty(entity?.route?.kmStart)"
-                    />
-                    <VnLv
-                        :label="t('route.summary.kmEnd')"
-                        :value="dashIfEmpty(entity?.route?.kmEnd)"
-                    />
-                    <VnLv
-                        :label="t('globals.description')"
-                        :value="dashIfEmpty(entity?.route?.description)"
-                    />
+                    <div class="vn-card-group">
+                        <div class="vn-card-content">
+                            <VnLv
+                                :label="t('route.summary.date')"
+                                :value="toDate(entity?.route.dated)"
+                            />
+                            <VnLv
+                                :label="t('route.summary.agency')"
+                                :value="entity?.route?.agencyMode?.name"
+                            />
+                            <VnLv
+                                :label="t('route.summary.vehicle')"
+                                :value="entity.route?.vehicle?.numberPlate"
+                            />
+                            <VnLv :label="t('route.summary.driver')">
+                                <template #value>
+                                    <span class="link">
+                                        {{
+                                            dashIfEmpty(entity?.route?.worker?.user?.name)
+                                        }}
+                                        <WorkerDescriptorProxy
+                                            :id="entity.route?.workerFk"
+                                        />
+                                    </span>
+                                </template>
+                            </VnLv>
+                            <VnLv
+                                :label="t('route.summary.cost')"
+                                :value="toCurrency(entity.route?.cost)"
+                            />
+                            <VnLv
+                                :label="t('route.summary.volume')"
+                                :value="`${dashIfEmpty(entity?.route?.m3)} / ${dashIfEmpty(
+                                    entity?.route?.vehicle?.m3,
+                                )} m³`"
+                            />
+                            <VnLv
+                                :label="t('route.summary.packages')"
+                                :value="getTotalPackages(entity.tickets)"
+                            />
+                            <QCheckbox
+                                :label="
+                                    entity.route.isOk
+                                        ? t('route.summary.closed')
+                                        : t('route.summary.open')
+                                "
+                                v-model="entity.route.isOk"
+                                :disable="true"
+                            />
+                        </div>
+                        <div class="vn-card-content">
+                            <VnLv
+                                :label="t('route.summary.started')"
+                                :value="toHour(entity?.route.started)"
+                            />
+                            <VnLv
+                                :label="t('route.summary.finished')"
+                                :value="toHour(entity?.route.finished)"
+                            />
+                            <VnLv
+                                :label="t('route.summary.kmStart')"
+                                :value="dashIfEmpty(entity?.route?.kmStart)"
+                            />
+                            <VnLv
+                                :label="t('route.summary.kmEnd')"
+                                :value="dashIfEmpty(entity?.route?.kmEnd)"
+                            />
+                            <VnLv
+                                :label="t('globals.description')"
+                                :value="dashIfEmpty(entity?.route?.description)"
+                            />
+                        </div>
+                    </div>
                 </QCard>
                 <QCard class="vn-max">
                     <VnTitle
@@ -221,7 +226,7 @@ const ticketColumns = ref([
                         <template #body-cell-city="{ value, row }">
                             <QTd auto-width>
                                 <span
-                                    class="link cursor-pointer"
+                                    class="link"
                                     @click="openBuscaman(entity?.route?.vehicleFk, [row])"
                                 >
                                     {{ value }}
@@ -230,7 +235,7 @@ const ticketColumns = ref([
                         </template>
                         <template #body-cell-client="{ value, row }">
                             <QTd auto-width>
-                                <span class="link cursor-pointer">
+                                <span class="link">
                                     {{ value }}
                                     <CustomerDescriptorProxy :id="row?.clientFk" />
                                 </span>
@@ -238,7 +243,7 @@ const ticketColumns = ref([
                         </template>
                         <template #body-cell-ticket="{ value, row }">
                             <QTd auto-width class="text-center">
-                                <span class="link cursor-pointer">
+                                <span class="link">
                                     {{ value }}
                                     <TicketDescriptorProxy :id="row?.id" />
                                 </span>
diff --git a/src/pages/Route/Cmr/CmrList.vue b/src/pages/Route/Cmr/CmrList.vue
index b3eaf3b48..170f73bc0 100644
--- a/src/pages/Route/Cmr/CmrList.vue
+++ b/src/pages/Route/Cmr/CmrList.vue
@@ -2,28 +2,37 @@
 import { onBeforeMount, onMounted, computed, ref } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { Notify } from 'quasar';
+import { useRoute } from 'vue-router';
 import { useSession } from 'src/composables/useSession';
 import { toDateHourMin } from 'filters/index';
 import { useStateStore } from 'src/stores/useStateStore';
 
-import axios from 'axios';
 import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
 import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
 
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
+import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 
+const route = useRoute();
 const { t } = useI18n();
 const { getTokenMultimedia } = useSession();
 const token = getTokenMultimedia();
 const state = useStateStore();
-const warehouses = ref([]);
 const selectedRows = ref([]);
+const dataKey = 'CmrList';
+const shipped = Date.vnNew();
+shipped.setHours(0, 0, 0, 0);
+shipped.setDate(shipped.getDate() - 1);
+const userParams = {
+    shipped: null,
+};
+
 const columns = computed(() => [
     {
         align: 'left',
         name: 'cmrFk',
-        label: t('route.cmr.list.cmrFk'),
+        label: t('route.cmr.params.cmrFk'),
         chip: {
             condition: () => true,
         },
@@ -32,62 +41,67 @@ const columns = computed(() => [
     {
         align: 'center',
         name: 'hasCmrDms',
-        label: t('route.cmr.list.hasCmrDms'),
+        label: t('route.cmr.params.hasCmrDms'),
         component: 'checkbox',
         cardVisible: true,
     },
     {
         align: 'left',
-        label: t('route.cmr.list.ticketFk'),
+        label: t('route.cmr.params.ticketFk'),
         name: 'ticketFk',
     },
     {
         align: 'left',
-        label: t('route.cmr.list.routeFk'),
+        label: t('route.cmr.params.routeFk'),
         name: 'routeFk',
     },
     {
         align: 'left',
-        label: t('route.cmr.list.clientFk'),
+        label: t('route.cmr.params.clientFk'),
         name: 'clientFk',
     },
     {
         align: 'right',
-        label: t('route.cmr.list.country'),
+        label: t('route.cmr.params.countryFk'),
         name: 'countryFk',
-        cardVisible: true,
+        component: 'select',
         attrs: {
             url: 'countries',
             fields: ['id', 'name'],
-            optionLabel: 'name',
-            optionValue: 'id',
         },
         columnFilter: {
-            inWhere: true,
-            component: 'select',
+            name: 'countryFk',
+            attrs: {
+                url: 'countries',
+                fields: ['id', 'name'],
+            },
         },
         format: ({ countryName }) => countryName,
     },
     {
         align: 'right',
-        label: t('route.cmr.list.shipped'),
+        label: t('route.cmr.params.shipped'),
         name: 'shipped',
         cardVisible: true,
-        columnFilter: {
-            component: 'date',
-            inWhere: true,
-        },
+        component: 'date',
         format: ({ shipped }) => toDateHourMin(shipped),
     },
     {
         align: 'right',
+        label: t('route.cmr.params.warehouseFk'),
         name: 'warehouseFk',
-        label: t('globals.warehouse'),
-        columnFilter: {
-            component: 'select',
-        },
+        component: 'select',
         attrs: {
-            options: warehouses.value,
+            url: 'warehouses',
+            fields: ['id', 'name'],
+        },
+        columnFilter: {
+            inWhere: true,
+            name: 'warehouseFk',
+            attrs: {
+                url: 'warehouses',
+                fields: ['id', 'name'],
+            },
         },
         format: ({ warehouseName }) => warehouseName,
     },
@@ -96,7 +110,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('Ver cmr'),
+                title: t('route.cmr.params.viewCmr'),
                 icon: 'visibility',
                 isPrimary: true,
                 action: (row) => window.open(getCmrUrl(row?.cmrFk), '_blank'),
@@ -105,13 +119,17 @@ const columns = computed(() => [
     },
 ]);
 
-onBeforeMount(async () => {
-    const { data } = await axios.get('Warehouses');
-    warehouses.value = data;
+onBeforeMount(() => {
+    initializeFromQuery();
 });
 
 onMounted(() => (state.rightDrawer = true));
 
+const initializeFromQuery = () => {
+    const query = route.query.table ? JSON.parse(route.query.table) : {};
+    shipped.value = query.shipped || shipped.toISOString();
+    Object.assign(userParams, { shipped });
+};
 function getApiUrl() {
     return new URL(window.location).origin;
 }
@@ -133,6 +151,11 @@ function downloadPdfs() {
 }
 </script>
 <template>
+    <VnSearchbar
+        :data-key
+        :label="t('route.cmr.search')"
+        :info="t('route.cmr.searchInfo')"
+    />
     <VnSubToolbar>
         <template #st-actions>
             <QBtn
@@ -142,16 +165,17 @@ function downloadPdfs() {
                 :disable="!selectedRows?.length"
                 @click="downloadPdfs"
             >
-                <QTooltip>{{ t('route.cmr.list.downloadCmrs') }}</QTooltip>
+                <QTooltip>{{ t('route.cmr.params.downloadCmrs') }}</QTooltip>
             </QBtn>
         </template>
     </VnSubToolbar>
     <VnTable
         ref="tableRef"
-        data-key="CmrList"
+        :data-key
         url="Cmrs/filter"
         :columns="columns"
-        :right-search="true"
+        :order="['shipped DESC', 'cmrFk ASC']"
+        :user-params="userParams"
         default-mode="table"
         v-model:selected="selectedRows"
         table-height="85vh"
diff --git a/src/pages/Route/Roadmap/RoadmapBasicData.vue b/src/pages/Route/Roadmap/RoadmapBasicData.vue
index a9e6059c3..3e9b8df6c 100644
--- a/src/pages/Route/Roadmap/RoadmapBasicData.vue
+++ b/src/pages/Route/Roadmap/RoadmapBasicData.vue
@@ -17,7 +17,7 @@ const onSave = (data, response) => {
 </script>
 <template>
     <FormModel
-        :update-url="`Roadmaps/${$route.params?.id}`"
+        :url-update="`Roadmaps/${$route.params?.id}`"
         :url="`Roadmaps/${$route.params?.id}`"
         observe-form-changes
         model="Roadmap"
diff --git a/src/pages/Route/Roadmap/RoadmapCard.vue b/src/pages/Route/Roadmap/RoadmapCard.vue
index 48ba516a1..af08bc9d4 100644
--- a/src/pages/Route/Roadmap/RoadmapCard.vue
+++ b/src/pages/Route/Roadmap/RoadmapCard.vue
@@ -1,7 +1,7 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import RoadmapDescriptor from 'pages/Route/Roadmap/RoadmapDescriptor.vue';
 </script>
 <template>
-    <VnCardBeta data-key="Roadmap" url="Roadmaps" :descriptor="RoadmapDescriptor" />
+    <VnCard data-key="Roadmap" url="Roadmaps" :descriptor="RoadmapDescriptor" />
 </template>
diff --git a/src/pages/Route/Roadmap/RoadmapDescriptor.vue b/src/pages/Route/Roadmap/RoadmapDescriptor.vue
index baa864a15..dfa692feb 100644
--- a/src/pages/Route/Roadmap/RoadmapDescriptor.vue
+++ b/src/pages/Route/Roadmap/RoadmapDescriptor.vue
@@ -2,7 +2,7 @@
 import { computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'components/ui/VnLv.vue';
 import { dashIfEmpty, toDateHourMin } from 'src/filters';
 import SupplierDescriptorProxy from 'pages/Supplier/Card/SupplierDescriptorProxy.vue';
@@ -15,6 +15,10 @@ const $props = defineProps({
         required: false,
         default: null,
     },
+    summary: {
+        type: Object,
+        default: null,
+    },
 });
 
 const route = useRoute();
@@ -26,7 +30,13 @@ const entityId = computed(() => {
 </script>
 
 <template>
-    <CardDescriptor :url="`Roadmaps/${entityId}`" :filter="filter" data-key="Roadmap">
+    <EntityDescriptor
+        :url="`Roadmaps/${entityId}`"
+        :filter="filter"
+        data-key="Roadmap"
+        :summary="summary"
+        :to-module="{ name: 'RouteRoadmap' }"
+    >
         <template #body="{ entity }">
             <VnLv :label="t('Roadmap')" :value="entity?.name" />
             <VnLv :label="t('ETD')" :value="toDateHourMin(entity?.etd)" />
@@ -42,7 +52,7 @@ const entityId = computed(() => {
         <template #menu="{ entity }">
             <RoadmapDescriptorMenu :route="entity" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <i18n>
 es:
diff --git a/src/pages/Route/Roadmap/RoadmapFilter.vue b/src/pages/Route/Roadmap/RoadmapFilter.vue
index 982f1efba..9acbfb740 100644
--- a/src/pages/Route/Roadmap/RoadmapFilter.vue
+++ b/src/pages/Route/Roadmap/RoadmapFilter.vue
@@ -31,12 +31,12 @@ const emit = defineEmits(['search']);
         <template #body="{ params }">
             <QItem class="q-my-sm">
                 <QItemSection>
-                    <VnInputDate v-model="params.from" :label="t('From')" is-outlined />
+                    <VnInputDate v-model="params.from" :label="t('From')" filled />
                 </QItemSection>
             </QItem>
             <QItem class="q-my-sm">
                 <QItemSection>
-                    <VnInputDate v-model="params.to" :label="t('To')" is-outlined />
+                    <VnInputDate v-model="params.to" :label="t('To')" filled />
                 </QItemSection>
             </QItem>
             <QItem class="q-my-sm">
@@ -44,7 +44,7 @@ const emit = defineEmits(['search']);
                     <VnInput
                         v-model="params.tractorPlate"
                         :label="t('Tractor Plate')"
-                        is-outlined
+                        filled
                         clearable
                     />
                 </QItemSection>
@@ -54,7 +54,7 @@ const emit = defineEmits(['search']);
                     <VnInput
                         v-model="params.trailerPlate"
                         :label="t('Trailer Plate')"
-                        is-outlined
+                        filled
                         clearable
                     />
                 </QItemSection>
@@ -66,8 +66,7 @@ const emit = defineEmits(['search']);
                         :fields="['id', 'nickname']"
                         v-model="params.supplierFk"
                         dense
-                        outlined
-                        rounded
+                        filled
                         emit-value
                         map-options
                         use-input
@@ -81,7 +80,7 @@ const emit = defineEmits(['search']);
                         v-model="params.price"
                         :label="t('Price')"
                         type="number"
-                        is-outlined
+                        filled
                         clearable
                     />
                 </QItemSection>
@@ -91,7 +90,7 @@ const emit = defineEmits(['search']);
                     <VnInput
                         v-model="params.driverName"
                         :label="t('Driver name')"
-                        is-outlined
+                        filled
                         clearable
                     />
                 </QItemSection>
@@ -101,7 +100,7 @@ const emit = defineEmits(['search']);
                     <VnInput
                         v-model="params.phone"
                         :label="t('Phone')"
-                        is-outlined
+                        filled
                         clearable
                     />
                 </QItemSection>
diff --git a/src/pages/Route/Roadmap/RoadmapSummary.vue b/src/pages/Route/Roadmap/RoadmapSummary.vue
index 0c1c2b903..dcd02d98e 100644
--- a/src/pages/Route/Roadmap/RoadmapSummary.vue
+++ b/src/pages/Route/Roadmap/RoadmapSummary.vue
@@ -112,12 +112,9 @@ const filter = {
                         :label="t('Trailer Plate')"
                         :value="dashIfEmpty(entity?.trailerPlate)"
                     />
-                    <VnLv :label="t('Phone')" :value="dashIfEmpty(entity?.phone)">
+                    <VnLv :label="t('Phone')">
                         <template #value>
-                            <span>
-                                {{ dashIfEmpty(entity?.phone) }}
-                                <VnLinkPhone :phone-number="entity?.phone" />
-                            </span>
+                            <VnLinkPhone :phone-number="entity?.phone" />
                         </template>
                     </VnLv>
                     <VnLv
diff --git a/src/pages/Route/RouteAutonomous.vue b/src/pages/Route/RouteAutonomous.vue
index 3047cdf86..15db2a55f 100644
--- a/src/pages/Route/RouteAutonomous.vue
+++ b/src/pages/Route/RouteAutonomous.vue
@@ -13,6 +13,7 @@ import RouteSummary from 'pages/Route/Card/RouteSummary.vue';
 import RouteDescriptorProxy from 'pages/Route/Card/RouteDescriptorProxy.vue';
 import InvoiceInDescriptorProxy from 'pages/InvoiceIn/Card/InvoiceInDescriptorProxy.vue';
 import SupplierDescriptorProxy from 'pages/Supplier/Card/SupplierDescriptorProxy.vue';
+import AgencyDescriptorProxy from 'pages/Route/Agency/Card/AgencyDescriptorProxy.vue';
 import VnSearchbar from 'components/ui/VnSearchbar.vue';
 import VnDms from 'components/common/VnDms.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
@@ -236,10 +237,16 @@ onUnmounted(() => (stateStore.rightDrawer = false));
             selection: 'multiple',
         }"
     >
-        <template #column-id="{ row }">
+        <template #column-agencyModeName="{ row }">
             <span class="link" @click.stop>
-                {{ row.routeFk }}
-                <RouteDescriptorProxy :id="row.route.id" />
+                {{ row?.agencyModeName }}
+                <AgencyDescriptorProxy :id="row?.agencyModeFk" v-if="row?.agencyModeFk" />
+            </span>
+        </template>
+        <template #column-agencyAgreement="{ row }">
+            <span class="link" @click.stop>
+                {{ row?.agencyAgreement }}
+                <AgencyDescriptorProxy :id="row?.agencyFk" v-if="row?.agencyFk" />
             </span>
         </template>
         <template #column-invoiceInFk="{ row }">
diff --git a/src/pages/Route/RouteExtendedList.vue b/src/pages/Route/RouteExtendedList.vue
index a7e192765..c69492836 100644
--- a/src/pages/Route/RouteExtendedList.vue
+++ b/src/pages/Route/RouteExtendedList.vue
@@ -38,7 +38,7 @@ const routeFilter = {
 };
 const columns = computed(() => [
     {
-        align: 'center',
+        align: 'right',
         name: 'id',
         label: 'Id',
         chip: {
@@ -48,9 +48,8 @@ const columns = computed(() => [
         columnFilter: false,
     },
     {
-        align: 'center',
         name: 'workerFk',
-        label: t('route.Worker'),
+        label: t('globals.worker'),
         create: true,
         component: 'select',
         attrs: {
@@ -71,9 +70,8 @@ const columns = computed(() => [
         format: (row, dashIfEmpty) => dashIfEmpty(row.workerUserName),
     },
     {
-        align: 'center',
         name: 'agencyModeFk',
-        label: t('route.Agency'),
+        label: t('globals.agency'),
         isTitle: true,
         cardVisible: true,
         create: true,
@@ -90,9 +88,8 @@ const columns = computed(() => [
         format: (row, dashIfEmpty) => dashIfEmpty(row.agencyName),
     },
     {
-        align: 'center',
         name: 'vehicleFk',
-        label: t('route.Vehicle'),
+        label: t('globals.vehicle'),
         cardVisible: true,
         create: true,
         component: 'select',
@@ -111,9 +108,8 @@ const columns = computed(() => [
         format: (row, dashIfEmpty) => dashIfEmpty(row.vehiclePlateNumber),
     },
     {
-        align: 'center',
         name: 'dated',
-        label: t('route.Date'),
+        label: t('globals.date'),
         columnFilter: false,
         cardVisible: true,
         create: true,
@@ -122,9 +118,8 @@ const columns = computed(() => [
             dated === '0000-00-00' ? dashIfEmpty(null) : toDate(dated),
     },
     {
-        align: 'center',
         name: 'from',
-        label: t('route.From'),
+        label: t('globals.from'),
         visible: false,
         cardVisible: true,
         create: true,
@@ -132,9 +127,8 @@ const columns = computed(() => [
         format: ({ from }) => toDate(from),
     },
     {
-        align: 'center',
         name: 'to',
-        label: t('route.To'),
+        label: t('globals.to'),
         visible: false,
         cardVisible: true,
         create: true,
@@ -142,14 +136,13 @@ const columns = computed(() => [
         format: ({ date }) => toDate(date),
     },
     {
-        align: 'center',
+        align: 'right',
         name: 'm3',
         label: 'm3',
         cardVisible: true,
         columnClass: 'shrink',
     },
     {
-        align: 'center',
         name: 'started',
         label: t('route.hourStarted'),
         component: 'time',
@@ -157,7 +150,6 @@ const columns = computed(() => [
         format: ({ started }) => toHour(started),
     },
     {
-        align: 'center',
         name: 'finished',
         label: t('route.hourFinished'),
         component: 'time',
@@ -165,7 +157,7 @@ const columns = computed(() => [
         format: ({ finished }) => toHour(finished),
     },
     {
-        align: 'center',
+        align: 'right',
         name: 'kmStart',
         label: t('route.KmStart'),
         columnClass: 'shrink',
@@ -173,7 +165,7 @@ const columns = computed(() => [
         visible: false,
     },
     {
-        align: 'center',
+        align: 'right',
         name: 'kmEnd',
         label: t('route.KmEnd'),
         columnClass: 'shrink',
@@ -181,16 +173,15 @@ const columns = computed(() => [
         visible: false,
     },
     {
-        align: 'center',
+        align: 'left',
         name: 'description',
-        label: t('route.Description'),
+        label: t('globals.description'),
         isTitle: true,
         create: true,
         component: 'input',
         field: 'description',
     },
     {
-        align: 'center',
         name: 'isOk',
         label: t('route.Served'),
         component: 'checkbox',
@@ -202,7 +193,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('route.Add tickets'),
+                title: t('route.addTicket'),
                 icon: 'vn:ticketAdd',
                 action: (row) => openTicketsDialog(row?.id),
                 isPrimary: true,
@@ -214,7 +205,7 @@ const columns = computed(() => [
                 isPrimary: true,
             },
             {
-                title: t('route.Route summary'),
+                title: t('route.routeSummary'),
                 icon: 'arrow_forward',
                 action: (row) => navigate(row?.id),
                 isPrimary: true,
@@ -276,11 +267,13 @@ const openTicketsDialog = (id) => {
     <QDialog v-model="confirmationDialog">
         <QCard style="min-width: 350px">
             <QCardSection>
-                <p class="text-h6 q-ma-none">{{ t('route.Select the starting date') }}</p>
+                <p class="text-h6 q-ma-none">
+                    {{ t('route.extendedList.selectStartingDate') }}
+                </p>
             </QCardSection>
             <QCardSection class="q-pt-none">
                 <VnInputDate
-                    :label="t('route.Starting date')"
+                    :label="t('route.extendedList.startingDate')"
                     v-model="startingDate"
                     autofocus
                 />
@@ -288,7 +281,7 @@ const openTicketsDialog = (id) => {
             <QCardActions align="right">
                 <QBtn
                     flat
-                    :label="t('route.Cancel')"
+                    :label="t('globals.cancel')"
                     v-close-popup
                     class="text-primary"
                 />
@@ -335,29 +328,34 @@ const openTicketsDialog = (id) => {
                 <QBtn
                     icon="vn:clone"
                     color="primary"
+                    flat
                     class="q-mr-sm"
                     :disable="!selectedRows?.length"
                     @click="confirmationDialog = true"
                 >
-                    <QTooltip>{{ t('route.Clone Selected Routes') }}</QTooltip>
+                    <QTooltip>{{ t('route.extendedList.cloneSelectedRoutes') }}</QTooltip>
                 </QBtn>
                 <QBtn
                     icon="cloud_download"
                     color="primary"
+                    flat
                     class="q-mr-sm"
                     :disable="!selectedRows?.length"
                     @click="showRouteReport"
                 >
-                    <QTooltip>{{ t('route.Download selected routes as PDF') }}</QTooltip>
+                    <QTooltip>{{
+                        t('route.extendedList.downloadSelectedRoutes')
+                    }}</QTooltip>
                 </QBtn>
                 <QBtn
                     icon="check"
                     color="primary"
+                    flat
                     class="q-mr-sm"
                     :disable="!selectedRows?.length"
                     @click="markAsServed()"
                 >
-                    <QTooltip>{{ t('route.Mark as served') }}</QTooltip>
+                    <QTooltip>{{ t('route.extendedList.markServed') }}</QTooltip>
                 </QBtn>
             </template>
         </VnTable>
diff --git a/src/pages/Route/RouteList.vue b/src/pages/Route/RouteList.vue
index 5723e2f0d..810157683 100644
--- a/src/pages/Route/RouteList.vue
+++ b/src/pages/Route/RouteList.vue
@@ -3,14 +3,18 @@ import { computed, ref, markRaw } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 import { toHour } from 'src/filters';
+import { useRouter } from 'vue-router';
 import RouteSummary from 'pages/Route/Card/RouteSummary.vue';
 import RouteFilter from 'pages/Route/Card/RouteFilter.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import AgencyDescriptorProxy from 'src/pages/Route/Agency/Card/AgencyDescriptorProxy.vue';
+import VehicleDescriptorProxy from 'src/pages/Route/Vehicle/Card/VehicleDescriptorProxy.vue';
 import VnSection from 'src/components/common/VnSection.vue';
 import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
 
 const { t } = useI18n();
+const router = useRouter();
 const { viewSummary } = useSummaryDialog();
 const tableRef = ref([]);
 const dataKey = 'RouteList';
@@ -24,6 +28,14 @@ const routeFilter = {
         },
     ],
 };
+
+function redirectToTickets(id) {
+    router.push({
+        name: 'RouteTickets',
+        params: { id },
+    });
+}
+
 const columns = computed(() => [
     {
         align: 'right',
@@ -38,7 +50,7 @@ const columns = computed(() => [
     {
         align: 'left',
         name: 'workerFk',
-        label: t('route.Worker'),
+        label: t('globals.worker'),
         component: markRaw(VnSelectWorker),
         create: true,
         cardVisible: true,
@@ -46,13 +58,7 @@ const columns = computed(() => [
         columnFilter: false,
     },
     {
-        align: 'left',
-        name: 'agencyName',
-        label: t('route.Agency'),
-        cardVisible: true,
-    },
-    {
-        label: t('route.Agency'),
+        label: t('globals.agency'),
         name: 'agencyModeFk',
         component: 'select',
         attrs: {
@@ -64,19 +70,12 @@ const columns = computed(() => [
             },
         },
         create: true,
-        columnFilter: false,
-        visible: false,
-    },
-    {
-        align: 'left',
-        name: 'vehiclePlateNumber',
-        label: t('route.Vehicle'),
+        columnFilter: true,
         cardVisible: true,
     },
     {
         name: 'vehicleFk',
-        label: t('route.Vehicle'),
-        cardVisible: true,
+        label: t('globals.vehicle'),
         component: 'select',
         attrs: {
             url: 'vehicles',
@@ -89,29 +88,29 @@ const columns = computed(() => [
             },
         },
         create: true,
-        columnFilter: false,
-        visible: false,
+        columnFilter: true,
+        cardVisible: true,
     },
     {
-        align: 'left',
+        align: 'center',
         name: 'started',
         label: t('route.hourStarted'),
         cardVisible: true,
         columnFilter: false,
-        format: (row) => toHour(row.started),
+        format: ({ started }) => toHour(started),
     },
     {
-        align: 'left',
+        align: 'center',
         name: 'finished',
         label: t('route.hourFinished'),
         cardVisible: true,
         columnFilter: false,
-        format: (row) => toHour(row.started),
+        format: ({ finished }) => toHour(finished),
     },
     {
         align: 'left',
         name: 'description',
-        label: t('route.Description'),
+        label: t('globals.description'),
         cardVisible: true,
         isTitle: true,
         create: true,
@@ -119,7 +118,6 @@ const columns = computed(() => [
         columnFilter: false,
     },
     {
-        align: 'left',
         name: 'isOk',
         label: t('route.Served'),
         component: 'checkbox',
@@ -130,6 +128,12 @@ const columns = computed(() => [
         align: 'right',
         name: 'tableActions',
         actions: [
+            {
+                title: t('globals.pageTitles.tickets'),
+                icon: 'vn:ticket',
+                action: (row) => redirectToTickets(row?.id),
+                isPrimary: true,
+            },
             {
                 title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
@@ -155,9 +159,10 @@ const columns = computed(() => [
         </template>
         <template #body>
             <VnTable
+                :with-filters="false"
                 :data-key
-                :columns="columns"
                 ref="tableRef"
+                :columns="columns"
                 :right-search="false"
                 redirect="route"
                 :create="{
@@ -174,6 +179,24 @@ const columns = computed(() => [
                         <WorkerDescriptorProxy :id="row?.workerFk" v-if="row?.workerFk" />
                     </span>
                 </template>
+                <template #column-agencyModeFk="{ row }">
+                    <span class="link" @click.stop>
+                        {{ row?.agencyName }}
+                        <AgencyDescriptorProxy
+                            :id="row?.agencyModeFk"
+                            v-if="row?.agencyModeFk"
+                        />
+                    </span>
+                </template>
+                <template #column-vehicleFk="{ row }">
+                    <span class="link" @click.stop>
+                        {{ row?.vehiclePlateNumber }}
+                        <VehicleDescriptorProxy
+                            :id="row?.vehicleFk"
+                            v-if="row?.vehicleFk"
+                        />
+                    </span>
+                </template>
             </VnTable>
         </template>
     </VnSection>
diff --git a/src/pages/Route/RouteRoadmap.vue b/src/pages/Route/RouteRoadmap.vue
index 23b1b1d5b..bdb3d12c4 100644
--- a/src/pages/Route/RouteRoadmap.vue
+++ b/src/pages/Route/RouteRoadmap.vue
@@ -2,13 +2,11 @@
 import { useI18n } from 'vue-i18n';
 import { computed, ref } from 'vue';
 import { dashIfEmpty } from 'src/filters';
-import { toDate, toDateHourMin } from 'filters/index';
+import { toDate, toDateHourMin, toCurrency } from 'filters/index';
 import { useQuasar } from 'quasar';
 import { useSummaryDialog } from 'composables/useSummaryDialog';
-import toCurrency from 'filters/toCurrency';
 import axios from 'axios';
 
-import VnSearchbar from 'components/ui/VnSearchbar.vue';
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import RoadmapSummary from 'pages/Route/Roadmap/RoadmapSummary.vue';
@@ -17,6 +15,8 @@ import VnInputDate from 'components/common/VnInputDate.vue';
 import VnInputTime from 'src/components/common/VnInputTime.vue';
 import VnSection from 'src/components/common/VnSection.vue';
 import RoadmapFilter from './Roadmap/RoadmapFilter.vue';
+import VehicleDescriptorProxy from 'src/pages/Route/Vehicle/Card/VehicleDescriptorProxy.vue';
+import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
 
 const { viewSummary } = useSummaryDialog();
 const { t } = useI18n();
@@ -33,7 +33,7 @@ const columns = computed(() => [
     {
         align: 'left',
         name: 'name',
-        label: t('Roadmap'),
+        label: t('route.roadmap.roadmap'),
         create: true,
         cardVisible: true,
         columnFilter: {
@@ -41,9 +41,9 @@ const columns = computed(() => [
         },
     },
     {
-        align: 'left',
+        align: 'center',
         name: 'etd',
-        label: t('ETD'),
+        label: t('route.roadmap.etd'),
         component: 'date',
         columnFilter: {
             inWhere: true,
@@ -54,7 +54,7 @@ const columns = computed(() => [
     {
         align: 'left',
         name: 'supplierFk',
-        label: t('Carrier'),
+        label: t('route.roadmap.carrier'),
         component: 'select',
         attrs: {
             url: 'suppliers',
@@ -65,21 +65,21 @@ const columns = computed(() => [
     },
     {
         name: 'tractorPlate',
-        label: t('Plate'),
+        label: t('route.roadmap.vehicle'),
         field: (row) => row.tractorPlate,
         sortable: true,
         align: 'left',
     },
     {
         name: 'price',
-        label: t('Price'),
-        field: (row) => toCurrency(row.price),
+        label: t('route.roadmap.price'),
+        format: ({ price }) => toCurrency(price),
         sortable: true,
-        align: 'left',
+        align: 'right',
     },
     {
         name: 'observations',
-        label: t('Observations'),
+        label: t('route.roadmap.observations'),
         field: (row) => dashIfEmpty(row.observations),
         sortable: true,
         align: 'left',
@@ -89,7 +89,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('Ver cmr'),
+                title: t('route.roadmap.seeCmr'),
                 icon: 'preview',
                 isPrimary: true,
                 action: (row) => viewSummary(row?.id, RoadmapSummary),
@@ -124,8 +124,8 @@ function confirmRemove() {
         .dialog({
             component: VnConfirm,
             componentProps: {
-                title: t('Selected roadmaps will be removed'),
-                message: t('Are you sure you want to continue?'),
+                title: t('route.roadmap.selectedRoadmapsRemoved'),
+                message: t('route.roadmap.areYouSure'),
                 promise: removeSelection,
             },
         })
@@ -157,15 +157,24 @@ function exprBuilder(param, value) {
         <QCard style="min-width: 350px">
             <QCardSection>
                 <p class="text-h6 q-ma-none">
-                    {{ t('Select the estimated date of departure (ETD)') }}
+                    {{ t('route.roadmap.selectEtd') }}
                 </p>
             </QCardSection>
 
             <QCardSection class="q-pt-none">
-                <VnInputDate :label="t('ETD')" v-model="etdDate" autofocus />
+                <VnInputDate
+                    :label="t('route.roadmap.etd')"
+                    v-model="etdDate"
+                    autofocus
+                />
             </QCardSection>
             <QCardActions align="right">
-                <QBtn flat :label="t('Cancel')" v-close-popup class="text-primary" />
+                <QBtn
+                    flat
+                    :label="t('globals.cancel')"
+                    v-close-popup
+                    class="text-primary"
+                />
                 <QBtn color="primary" v-close-popup @click="cloneSelection">
                     {{ t('globals.clone') }}
                 </QBtn>
@@ -181,7 +190,7 @@ function exprBuilder(param, value) {
                 :disable="!selectedRows?.length"
                 @click="isCloneDialogOpen = true"
             >
-                <QTooltip>{{ t('Clone Selected Routes') }}</QTooltip>
+                <QTooltip>{{ t('route.roadmap.cloneSelected') }}</QTooltip>
             </QBtn>
             <QBtn
                 icon="delete"
@@ -190,7 +199,7 @@ function exprBuilder(param, value) {
                 :disable="!selectedRows?.length"
                 @click="confirmRemove"
             >
-                <QTooltip>{{ t('Delete roadmap(s)') }}</QTooltip>
+                <QTooltip>{{ t('route.roadmap.deleteRoadmap') }}</QTooltip>
             </QBtn>
         </template>
     </VnSubToolbar>
@@ -204,7 +213,7 @@ function exprBuilder(param, value) {
         }"
     >
         <template #advanced-menu>
-            <RoadmapFilter :dataKey />
+            <RoadmapFilter :data-key />
         </template>
         <template #body>
             <VnTable
@@ -222,7 +231,7 @@ function exprBuilder(param, value) {
                 redirect="route/roadmap"
                 :create="{
                     urlCreate: 'Roadmaps',
-                    title: t('Create routemap'),
+                    title: t('route.roadmap.createRoadmap'),
                     onDataSaved: ({ id }) => tableRef.redirect(id),
                     formInitialData: {},
                 }"
@@ -232,7 +241,10 @@ function exprBuilder(param, value) {
                     {{ toDateHourMin(row.etd) }}
                 </template>
                 <template #column-supplierFk="{ row }">
-                    {{ row.supplierFk }}
+                    <span class="link" @click.stop>
+                        {{ row.driverName }}
+                        <SupplierDescriptorProxy :id="row.supplierFk" />
+                    </span>
                 </template>
                 <template #more-create-dialog="{ data }">
                     <VnInputDate v-model="data.etd" />
@@ -251,21 +263,3 @@ function exprBuilder(param, value) {
     gap: 12px;
 }
 </style>
-<i18n>
-es:
-    Create routemap: Crear troncal
-    Search roadmaps: Buscar troncales
-    You can search by roadmap reference: Puedes buscar por referencia del troncal
-    Delete roadmap(s): Eliminar troncal(es)
-    Selected roadmaps will be removed: Los troncales seleccionadas serán eliminados
-    Are you sure you want to continue?: ¿Seguro que quieres continuar?
-    The date can't be empty: La fecha no puede estar vacía
-    Clone Selected Routes: Clonar rutas seleccionadas
-    Create roadmap: Crear troncal
-    Roadmap: Troncal
-    Carrier: Transportista
-    Plate: Matrícula
-    Price: Precio
-    Observations: Observaciones
-    Select the estimated date of departure (ETD): Selecciona la fecha estimada de salida
-</i18n>
diff --git a/src/pages/Route/RouteTickets.vue b/src/pages/Route/RouteTickets.vue
index adc7dfdaa..5e28bb689 100644
--- a/src/pages/Route/RouteTickets.vue
+++ b/src/pages/Route/RouteTickets.vue
@@ -30,16 +30,16 @@ const columns = computed(() => [
         align: 'center',
     },
     {
-        name: 'street',
-        label: t('Street'),
-        field: (row) => row?.street,
+        name: 'client',
+        label: t('Client'),
+        field: (row) => row?.nickname,
         sortable: false,
         align: 'left',
     },
     {
-        name: 'city',
-        label: t('City'),
-        field: (row) => row?.city,
+        name: 'street',
+        label: t('Street'),
+        field: (row) => row?.street,
         sortable: false,
         align: 'left',
     },
@@ -51,9 +51,9 @@ const columns = computed(() => [
         align: 'center',
     },
     {
-        name: 'client',
-        label: t('Client'),
-        field: (row) => row?.nickname,
+        name: 'city',
+        label: t('City'),
+        field: (row) => row?.city,
         sortable: false,
         align: 'left',
     },
@@ -199,12 +199,22 @@ const confirmRemove = (ticket) => {
 const openSmsDialog = async () => {
     const clientsId = [];
     const clientsPhone = [];
-
+    const clientWithoutPhone = [];
     for (let ticket of selectedRows.value) {
         clientsId.push(ticket?.clientFk);
         const { data: client } = await axios.get(`Clients/${ticket?.clientFk}`);
+        if (!client.phone) {
+            clientWithoutPhone.push(ticket?.clientFk);
+            continue;
+        }
         clientsPhone.push(client.phone);
     }
+    if (clientWithoutPhone.length) {
+        quasar.notify({
+            type: 'warning',
+            message: t('components.VnNotes.clientWithoutPhone', { clientWithoutPhone }),
+        });
+    }
 
     quasar.dialog({
         component: SendSmsDialog,
@@ -319,7 +329,7 @@ const openSmsDialog = async () => {
                             selection="multiple"
                         >
                             <template #body-cell-order="{ row }">
-                                <QTd class="order-field">
+                                <QTd class="order-field" auto-width>
                                     <div class="flex no-wrap items-center">
                                         <QIcon
                                             name="low_priority"
@@ -341,7 +351,7 @@ const openSmsDialog = async () => {
                                 </QTd>
                             </template>
                             <template #body-cell-city="{ value, row }">
-                                <QTd auto-width>
+                                <QTd>
                                     <span class="link" @click="goToBuscaman(row)">
                                         {{ value }}
                                         <QTooltip>{{ t('Open buscaman') }}</QTooltip>
@@ -349,7 +359,7 @@ const openSmsDialog = async () => {
                                 </QTd>
                             </template>
                             <template #body-cell-client="{ value, row }">
-                                <QTd auto-width>
+                                <QTd>
                                     <span class="link">
                                         {{ value }}
                                         <CustomerDescriptorProxy :id="row?.clientFk" />
diff --git a/src/pages/Route/Vehicle/Card/VehicleCard.vue b/src/pages/Route/Vehicle/Card/VehicleCard.vue
index f59420aa2..b6038c24c 100644
--- a/src/pages/Route/Vehicle/Card/VehicleCard.vue
+++ b/src/pages/Route/Vehicle/Card/VehicleCard.vue
@@ -1,10 +1,10 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import VehicleDescriptor from './VehicleDescriptor.vue';
 import VehicleFilter from '../VehicleFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Vehicle"
         url="Vehicles"
         :filter="VehicleFilter"
diff --git a/src/pages/Route/Vehicle/Card/VehicleDescriptor.vue b/src/pages/Route/Vehicle/Card/VehicleDescriptor.vue
index d9a2434ab..bab7fa998 100644
--- a/src/pages/Route/Vehicle/Card/VehicleDescriptor.vue
+++ b/src/pages/Route/Vehicle/Card/VehicleDescriptor.vue
@@ -1,17 +1,30 @@
 <script setup>
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
 import VnLv from 'src/components/ui/VnLv.vue';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import axios from 'axios';
 import useNotify from 'src/composables/useNotify.js';
 
 const { notify } = useNotify();
+
+const props = defineProps({
+    id: {
+        type: Number,
+        required: false,
+        default: null,
+    },
+});
+
+const route = useRoute();
+const entityId = computed(() => props.id || route.params.id);
 </script>
 <template>
-    <CardDescriptor
-        :url="`Vehicles/${$route.params.id}`"
+    <EntityDescriptor
+        :url="`Vehicles/${entityId}`"
         data-key="Vehicle"
         title="numberPlate"
-        :to-module="{ name: 'VehicleList' }"
+        :to-module="{ name: 'RouteVehicle' }"
     >
         <template #menu="{ entity }">
             <QItem
@@ -41,7 +54,7 @@ const { notify } = useNotify();
             <VnLv :label="$t('globals.model')" :value="entity.model" />
             <VnLv :label="$t('globals.country')" :value="entity.countryCodeFk" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 <i18n>
 es:
diff --git a/src/pages/Route/Vehicle/Card/VehicleDescriptorProxy.vue b/src/pages/Route/Vehicle/Card/VehicleDescriptorProxy.vue
new file mode 100644
index 000000000..cc0943cb8
--- /dev/null
+++ b/src/pages/Route/Vehicle/Card/VehicleDescriptorProxy.vue
@@ -0,0 +1,20 @@
+<script setup>
+import VehicleDescriptor from 'pages/Route/Vehicle/Card/VehicleDescriptor.vue';
+import VehicleSummary from './VehicleSummary.vue';
+
+const $props = defineProps({
+    id: {
+        type: Number,
+        required: true,
+    },
+    summary: {
+        type: Object,
+        default: null,
+    },
+});
+</script>
+<template>
+    <QPopupProxy>
+        <VehicleDescriptor v-if="$props.id" :id="$props.id" :summary="VehicleSummary" />
+    </QPopupProxy>
+</template>
diff --git a/src/pages/Route/Vehicle/Card/VehicleNotes.vue b/src/pages/Route/Vehicle/Card/VehicleNotes.vue
new file mode 100644
index 000000000..0afc3c3ed
--- /dev/null
+++ b/src/pages/Route/Vehicle/Card/VehicleNotes.vue
@@ -0,0 +1,35 @@
+<script setup>
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
+import { useState } from 'src/composables/useState';
+import VnNotes from 'src/components/ui/VnNotes.vue';
+
+const route = useRoute();
+const state = useState();
+const user = state.getUser();
+const vehicleId = computed(() => route.params.id);
+
+const noteFilter = computed(() => {
+    return {
+        order: 'created DESC',
+        where: { vehicleFk: vehicleId.value },
+    };
+});
+
+const body = {
+    vehicleFk: vehicleId.value,
+    workerFk: user.value.id,
+};
+</script>
+
+<template>
+    <VnNotes
+        url="vehicleObservations"
+        :add-note="true"
+        :filter="noteFilter"
+        :body="body"
+        style="overflow-y: auto"
+        required
+        deletable
+    />
+</template>
diff --git a/src/pages/Route/Vehicle/Card/VehicleSummary.vue b/src/pages/Route/Vehicle/Card/VehicleSummary.vue
index e4b0a9497..13d4bbc9d 100644
--- a/src/pages/Route/Vehicle/Card/VehicleSummary.vue
+++ b/src/pages/Route/Vehicle/Card/VehicleSummary.vue
@@ -13,12 +13,13 @@ const props = defineProps({ id: { type: [Number, String], default: null } });
 
 const route = useRoute();
 const entityId = computed(() => props.id || +route.params.id);
+const baseLink = `#/${route.meta.moduleName.toLowerCase()}/vehicle/${entityId.value}`;
 const links = {
-    'basic-data': `#/vehicle/${entityId.value}/basic-data`,
-    notes: `#/vehicle/${entityId.value}/notes`,
-    dms: `#/vehicle/${entityId.value}/dms`,
-    'invoice-in': `#/vehicle/${entityId.value}/invoice-in`,
-    events: `#/vehicle/${entityId.value}/events`,
+    'basic-data': `${baseLink}/basic-data`,
+    notes: `${baseLink}/notes`,
+    dms: `${baseLink}/dms`,
+    'invoice-in': `${baseLink}/invoice-in`,
+    events: `${baseLink}/events`,
 };
 </script>
 <template>
@@ -54,7 +55,10 @@ const links = {
                             <template #value>
                                 <span class="link">
                                     {{ entity.supplier?.name }}
-                                    <SupplierDescriptorProxy :id="entity.supplierFk" />
+                                    <SupplierDescriptorProxy
+                                        v-if="entity.supplierFk"
+                                        :id="entity.supplierFk"
+                                    />
                                 </span>
                             </template>
                         </VnLv>
@@ -63,6 +67,7 @@ const links = {
                                 <span class="link">
                                     {{ entity.supplierCooler?.name }}
                                     <SupplierDescriptorProxy
+                                        v-if="entity.supplierCoolerFk"
                                         :id="entity.supplierCoolerFk"
                                     />
                                 </span>
diff --git a/src/pages/Route/Vehicle/VehicleList.vue b/src/pages/Route/Vehicle/VehicleList.vue
index e5b945010..a79cc2e35 100644
--- a/src/pages/Route/Vehicle/VehicleList.vue
+++ b/src/pages/Route/Vehicle/VehicleList.vue
@@ -116,6 +116,7 @@ const columns = computed(() => [
                 title: t('components.smartCard.openSummary'),
                 icon: 'preview',
                 action: (row) => viewSummary(row.id, VehicleSummary),
+                isPrimary: true,
             },
         ],
     },
diff --git a/src/pages/Route/locale/en.yml b/src/pages/Route/locale/en.yml
index cc445f412..e7e2d691e 100644
--- a/src/pages/Route/locale/en.yml
+++ b/src/pages/Route/locale/en.yml
@@ -1,48 +1,79 @@
 route:
+    filter:
+        Served: Served
+    extendedList:
+        selectStartingDate: Select the starting date
+        startingDate: Starting date
+        cloneSelectedRoutes: Clone selected routes
+        downloadSelectedRoutes: Download selected routes as PDF
+        markServed: Mark as served
     roadmap:
+        roadmap: Roadmap
+        carrier: Carrier
+        vehicle: Vehicle
+        price: Price
+        observations: Observations
+        etd: ETD
+        dateCantEmpty: The date can't be empty
+        createRoadmap: Create roadmap
+        deleteRoadmap: Delete roadmap(s)
+        cloneSelected: Clone selected routes
+        selectedRoadmapsRemoved: Selected roadmaps will be removed
+        areYouSure: Are you sure you want to continue?
+        selectEtd: Select the estimated date of departure (ETD)
         search: Search roadmap
         searchInfo: You can search by roadmap reference
     params:
+        warehouseFk: Warehouse
+        description: Description
+        m3: m³
+        scopeDays: Days Onward
+        vehicleFk: Vehicle
+        agencyModeFk: Agency
+        workerFk: Worker
+        from: From
+        to: To
+        isOk: Served
         etd: ETD
         tractorPlate: Plate
         price: Price
         observations: Observations
-        id: ID
+        id: Id
         name: Name
         cmrFk: CMR id
         hasCmrDms: Attached in gestdoc
         ticketFk: Ticketd id
         routeFk: Route id
+        clientFk: Client id
+        countryFk: Country
         shipped: Shipped
         agencyAgreement: Agency agreement
         agencyModeName: Agency route
+        isOwn: Own
+        isAnyVolumeAllowed: Any volume allowed
     Worker: Worker
     Agency: Agency
     Vehicle: Vehicle
     Description: Description
     hourStarted: H.Start
     hourFinished: H.End
-    dated: Dated
-    From: From
-    To: To
+    createRoute: Create route
     Date: Date
     KmStart: Km start
     KmEnd: Km end
     Served: Served
-    Clone Selected Routes: Clone selected routes
-    Select the starting date: Select the starting date
-    Stating date: Starting date
-    Cancel: Cancel
-    Mark as served: Mark as served
-    Download selected routes as PDF: Download selected routes as PDF
-    Add ticket: Add ticket
-    Summary: Summary
+    addTicket: Add ticket
+    routeSummary: Go to summary
     Route is closed: Route is closed
     Route is not served: Route is not served
     search: Search route
     searchInfo: You can search by route reference
+    dated: Dated
+    preview: Preview
     cmr:
-        list:
+        search: Search Cmr
+        searchInfo: You can search Cmr by Id
+        params:
             results: results
             cmrFk: CMR id
             hasCmrDms: Attached in gestdoc
@@ -50,8 +81,10 @@ route:
             'false': 'No'
             ticketFk: Ticketd id
             routeFk: Route id
-            country: Country
+            countryFk: Country
             clientFk: Client id
+            warehouseFk: Warehouse
             shipped: Preparation date
             viewCmr: View CMR
-            downloadCmrs: Download CMRs
\ No newline at end of file
+            downloadCmrs: Download CMRs
+            search: General search
diff --git a/src/pages/Route/locale/es.yml b/src/pages/Route/locale/es.yml
index 51d43774a..2785ded31 100644
--- a/src/pages/Route/locale/es.yml
+++ b/src/pages/Route/locale/es.yml
@@ -1,21 +1,57 @@
 route:
+    filter:
+        Served: Servida
+    extendedList:
+        selectStartingDate: Seleccione la fecha de inicio
+        statingDate: Fecha de inicio
+        cloneSelectedRoutes: Clonar rutas seleccionadas
+        downloadSelectedRoutes: Descargar rutas seleccionadas como PDF
+        markServed: Marcar como servidas
     roadmap:
+        roadmap: Troncal
+        carrier: Transportista
+        vehicle: Vehículo
+        price: Precio
+        observations: Observaciones
+        etd: ETD
+        dateCantEmpty: La fecha no puede estar vacía
+        createRoadmap: Crear troncal
+        deleteRoadmap: Eliminar troncal(es)
+        cloneSelected: Clonar rutas seleccionadas
+        selectedRoadmapsRemoved: Los troncales seleccionadas serán eliminados
+        areYouSure: ¿Seguro que quieres continuar?
+        selectEtd: Selecciona la fecha estimada de salida
         search: Buscar troncales
         searchInfo: Puedes buscar por referencia del troncal
     params:
-        agencyModeName: Agencia Ruta
-        agencyAgreement: Agencia Acuerdo
-        id: Id
-        name: Troncal
+        warehouseFk: Almacén
+        description: Descripción
+        m3: m³
+        scopeDays: Días adelante
+        vehicleFk: Vehículo
+        agencyModeFk: Agencia
+        workerFk: Trabajador
+        from: Desde
+        to: Hasta
+        isOk: Servida
         etd: ETD
         tractorPlate: Matrícula
         price: Precio
         observations: Observaciones
+        id: Id
+        name: Troncal
         cmrFk: Id CMR
         hasCmrDms: Gestdoc
+        search: Búsqueda general
         ticketFk: Id ticket
-        routeFK: Id ruta
+        routeFk: Id ruta
+        clientFk: Id cliente
+        countryFk: Pais
         shipped: Fecha preparación
+        agencyModeName: Agencia Ruta
+        agencyAgreement: Agencia Acuerdo
+        isOwn: Propio
+        isAnyVolumeAllowed: Cualquier volumen
     Worker: Trabajador
     Agency: Agencia
     Vehicle: Vehículo
@@ -23,25 +59,18 @@ route:
     hourStarted: H.Inicio
     hourFinished: H.Fin
     createRoute: Crear ruta
-    From: Desde
-    To: Hasta
     Date: Fecha
     KmStart: Km inicio
     KmEnd: Km fin
     Served: Servida
-    Clone Selected Routes: Clonar rutas seleccionadas
-    Select the starting date: Seleccione la fecha de inicio
-    Stating date: Fecha de inicio
-    Cancel: Cancelar
-    Mark as served: Marcar como servidas
-    Download selected routes as PDF: Descargar rutas seleccionadas como PDF
-    Add ticket: Añadir tickets
-    preview: Vista previa
-    Summary: Resumen
+    addTicket: Añadir tickets
+    routeSummary: Ir a vista previa
     Route is closed: La ruta está cerrada
     Route is not served: La ruta no está servida
     search: Buscar rutas
     searchInfo: Puedes buscar por referencia de la ruta
+    dated: Fecha
+    preview: Vista previa
     cmr:
         list:
             results: resultados
@@ -55,4 +84,4 @@ route:
             clientFk: Id cliente
             shipped: Fecha preparación
             viewCmr: Ver CMR
-            downloadCmrs: Descargar CMRs
\ No newline at end of file
+            downloadCmrs: Descargar CMRs
diff --git a/src/pages/Shelving/Card/ShelvingCard.vue b/src/pages/Shelving/Card/ShelvingCard.vue
index 9e0ac8ad2..e2fb79fb0 100644
--- a/src/pages/Shelving/Card/ShelvingCard.vue
+++ b/src/pages/Shelving/Card/ShelvingCard.vue
@@ -1,11 +1,11 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import ShelvingDescriptor from 'pages/Shelving/Card/ShelvingDescriptor.vue';
 import filter from './ShelvingFilter.js';
 </script>
 
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Shelving"
         url="Shelvings"
         :filter="filter"
diff --git a/src/pages/Shelving/Card/ShelvingDescriptor.vue b/src/pages/Shelving/Card/ShelvingDescriptor.vue
index 5e618aa7f..2405467da 100644
--- a/src/pages/Shelving/Card/ShelvingDescriptor.vue
+++ b/src/pages/Shelving/Card/ShelvingDescriptor.vue
@@ -2,7 +2,7 @@
 import { computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'components/ui/VnLv.vue';
 import ShelvingDescriptorMenu from 'pages/Shelving/Card/ShelvingDescriptorMenu.vue';
 import VnUserLink from 'src/components/ui/VnUserLink.vue';
@@ -24,7 +24,7 @@ const entityId = computed(() => {
 });
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         :url="`Shelvings/${entityId}`"
         :filter="filter"
         title="code"
@@ -45,5 +45,5 @@ const entityId = computed(() => {
         <template #menu="{ entity }">
             <ShelvingDescriptorMenu :shelving="entity" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
diff --git a/src/pages/Shelving/Card/ShelvingFilter.vue b/src/pages/Shelving/Card/ShelvingFilter.vue
index 56cf4f58c..35657a972 100644
--- a/src/pages/Shelving/Card/ShelvingFilter.vue
+++ b/src/pages/Shelving/Card/ShelvingFilter.vue
@@ -2,6 +2,7 @@
 import { useI18n } from 'vue-i18n';
 import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
+import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
 
 const { t } = useI18n();
 const props = defineProps({
@@ -38,27 +39,14 @@ const emit = defineEmits(['search']);
                         option-label="code"
                         :filter-options="['id', 'code']"
                         dense
-                        outlined
-                        rounded
+                        filled
                         sort-by="code ASC"
                     />
                 </QItemSection>
             </QItem>
             <QItem class="q-mb-sm">
                 <QItemSection>
-                    <VnSelect
-                        dense
-                        outlined
-                        rounded
-                        :label="t('params.userFk')"
-                        v-model="params.userFk"
-                        url="Workers/activeWithInheritedRole"
-                        option-value="id"
-                        option-label="firstName"
-                        :where="{ role: 'salesPerson' }"
-                        sort-by="firstName ASC"
-                        :use-like="false"
-                    />
+                    <VnSelectWorker v-model="params.userFk" filled />
                 </QItemSection>
             </QItem>
             <QItem class="q-mb-md">
diff --git a/src/pages/Shelving/Card/ShelvingSummary.vue b/src/pages/Shelving/Card/ShelvingSummary.vue
index f89ff4d78..4a6669624 100644
--- a/src/pages/Shelving/Card/ShelvingSummary.vue
+++ b/src/pages/Shelving/Card/ShelvingSummary.vue
@@ -6,6 +6,7 @@ import VnLv from 'components/ui/VnLv.vue';
 import VnUserLink from 'components/ui/VnUserLink.vue';
 import filter from './ShelvingFilter.js';
 import ShelvingDescriptorMenu from './ShelvingDescriptorMenu.vue';
+import VnTitle from 'src/components/common/VnTitle.vue';
 
 const $props = defineProps({
     id: {
@@ -38,13 +39,10 @@ const entityId = computed(() => $props.id || route.params.id);
             </template>
             <template #body="{ entity }">
                 <QCard class="vn-one">
-                    <RouterLink
-                        class="header header-link"
-                        :to="{ name: 'ShelvingBasicData', params: { id: entityId } }"
-                    >
-                        {{ $t('globals.pageTitles.basicData') }}
-                        <QIcon name="open_in_new" />
-                    </RouterLink>
+                    <VnTitle
+                        :url="`#/shelving/${entityId}/basic-data`"
+                        :text="$t('globals.pageTitles.basicData')"
+                    />
                     <VnLv :label="$t('globals.code')" :value="entity.code" />
                     <VnLv
                         :label="$t('shelving.list.parking')"
diff --git a/src/pages/Shelving/Parking/Card/ParkingCard.vue b/src/pages/Shelving/Parking/Card/ParkingCard.vue
index b32c1b7d3..c8b3c60d7 100644
--- a/src/pages/Shelving/Parking/Card/ParkingCard.vue
+++ b/src/pages/Shelving/Parking/Card/ParkingCard.vue
@@ -1,11 +1,11 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import ParkingDescriptor from 'pages/Shelving/Parking/Card/ParkingDescriptor.vue';
 import filter from './ParkingFilter.js';
 </script>
 
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Parking"
         url="Parkings"
         :filter="filter"
diff --git a/src/pages/Shelving/Parking/Card/ParkingDescriptor.vue b/src/pages/Shelving/Parking/Card/ParkingDescriptor.vue
index 46c9f8ea0..0e01238a0 100644
--- a/src/pages/Shelving/Parking/Card/ParkingDescriptor.vue
+++ b/src/pages/Shelving/Parking/Card/ParkingDescriptor.vue
@@ -1,7 +1,7 @@
 <script setup>
 import { computed } from 'vue';
 import { useRoute } from 'vue-router';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'components/ui/VnLv.vue';
 import filter from './ParkingFilter.js';
 const props = defineProps({
@@ -16,17 +16,17 @@ const route = useRoute();
 const entityId = computed(() => props.id || route.params.id);
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         data-key="Parking"
         :url="`Parkings/${entityId}`"
         title="code"
         :filter="filter"
-        :to-module="{ name: 'ParkingList' }"
+        :to-module="{ name: 'ParkingMain' }"
     >
         <template #body="{ entity }">
             <VnLv :label="$t('globals.code')" :value="entity.code" />
             <VnLv :label="$t('parking.pickingOrder')" :value="entity.pickingOrder" />
             <VnLv :label="$t('parking.sector')" :value="entity.sector?.description" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
diff --git a/src/pages/Shelving/Parking/Card/ParkingDescriptorProxy.vue b/src/pages/Shelving/Parking/Card/ParkingDescriptorProxy.vue
new file mode 100644
index 000000000..e78a2b238
--- /dev/null
+++ b/src/pages/Shelving/Parking/Card/ParkingDescriptorProxy.vue
@@ -0,0 +1,14 @@
+<script setup>
+import ParkingDescriptor from './ParkingDescriptor.vue';
+import ParkingSummary from './ParkingSummary.vue';
+</script>
+<template>
+    <QPopupProxy style="max-width: 10px">
+        <ParkingDescriptor
+            v-if="$attrs.id"
+            v-bind="$attrs.id"
+            :summary="ParkingSummary"
+            :proxy-render="true"
+        />
+    </QPopupProxy>
+</template>
diff --git a/src/pages/Shelving/Parking/Card/ParkingSummary.vue b/src/pages/Shelving/Parking/Card/ParkingSummary.vue
index 7188ebeb6..1365c71ca 100644
--- a/src/pages/Shelving/Parking/Card/ParkingSummary.vue
+++ b/src/pages/Shelving/Parking/Card/ParkingSummary.vue
@@ -4,6 +4,7 @@ import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import CardSummary from 'components/ui/CardSummary.vue';
 import VnLv from 'components/ui/VnLv.vue';
+import VnTitle from 'src/components/common/VnTitle.vue';
 
 const $props = defineProps({
     id: {
@@ -28,13 +29,10 @@ const filter = {
             <template #body="{ entity }">
                 <QCard class="vn-one">
                     <QCardSection class="q-pa-none">
-                        <a
-                            class="header header-link"
-                            :href="`#/parking/${entityId}/basic-data`"
-                        >
-                            {{ t('globals.pageTitles.basicData') }}
-                            <QIcon name="open_in_new" />
-                        </a>
+                        <VnTitle
+                            :url="`#/shelving/parking/${entityId}/basic-data`"
+                            :text="$t('globals.pageTitles.basicData')"
+                        />
                     </QCardSection>
                     <VnLv :label="t('globals.code')" :value="entity.code" />
                     <VnLv
diff --git a/src/pages/Shelving/Parking/ParkingFilter.vue b/src/pages/Shelving/Parking/ParkingFilter.vue
index 1d7c3a4b6..59cb49459 100644
--- a/src/pages/Shelving/Parking/ParkingFilter.vue
+++ b/src/pages/Shelving/Parking/ParkingFilter.vue
@@ -36,11 +36,7 @@ const emit = defineEmits(['search']);
         <template #body="{ params }">
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        :label="t('params.code')"
-                        v-model="params.code"
-                        is-outlined
-                    />
+                    <VnInput :label="t('params.code')" v-model="params.code" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -51,8 +47,7 @@ const emit = defineEmits(['search']);
                         option-label="description"
                         :label="t('params.sectorFk')"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :options="sectors"
                         use-input
                         input-debounce="0"
diff --git a/src/pages/Supplier/Card/SupplierBalanceFilter.vue b/src/pages/Supplier/Card/SupplierBalanceFilter.vue
index c4b63d9c8..c727688ad 100644
--- a/src/pages/Supplier/Card/SupplierBalanceFilter.vue
+++ b/src/pages/Supplier/Card/SupplierBalanceFilter.vue
@@ -33,7 +33,7 @@ defineProps({
                         :label="t('params.from')"
                         v-model="params.from"
                         @update:model-value="searchFn()"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -47,8 +47,7 @@ defineProps({
                         :include="{ relation: 'accountingType' }"
                         sort-by="id"
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                         <template #option="scope">
                             <QItem v-bind="scope.itemProps">
@@ -74,8 +73,7 @@ defineProps({
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
diff --git a/src/pages/Supplier/Card/SupplierCard.vue b/src/pages/Supplier/Card/SupplierCard.vue
index e30f79f96..74b3520bf 100644
--- a/src/pages/Supplier/Card/SupplierCard.vue
+++ b/src/pages/Supplier/Card/SupplierCard.vue
@@ -1,10 +1,10 @@
 <script setup>
 import SupplierDescriptor from './SupplierDescriptor.vue';
-import VnCardBeta from 'src/components/common/VnCardBeta.vue';
+import VnCard from 'src/components/common/VnCard.vue';
 import filter from './SupplierFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Supplier"
         url="Suppliers"
         :descriptor="SupplierDescriptor"
diff --git a/src/pages/Supplier/Card/SupplierConsumption.vue b/src/pages/Supplier/Card/SupplierConsumption.vue
index 718de95dd..259561f4c 100644
--- a/src/pages/Supplier/Card/SupplierConsumption.vue
+++ b/src/pages/Supplier/Card/SupplierConsumption.vue
@@ -203,7 +203,7 @@ onMounted(async () => {
             </QTr>
             <QTr v-for="(buy, index) in row.buys" :key="index">
                 <QTd no-hover>
-                    <QBtn flat color="blue" dense no-caps>{{ buy.itemName }}</QBtn>
+                    <QBtn flat class="link" dense no-caps>{{ buy.itemName }}</QBtn>
                     <ItemDescriptorProxy :id="buy.itemFk" />
                 </QTd>
 
diff --git a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
index 390f7d9ff..e21e37eb3 100644
--- a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
+++ b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
@@ -25,20 +25,12 @@ defineProps({
         <template #body="{ params, searchFn }">
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.search"
-                        :label="t('params.search')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.search" :label="t('params.search')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.itemId"
-                        :label="t('params.itemId')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.itemId" :label="t('params.itemId')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -54,8 +46,7 @@ defineProps({
                         option-label="nickname"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -73,8 +64,7 @@ defineProps({
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                         <template #option="scope">
                             <QItem v-bind="scope.itemProps">
@@ -102,8 +92,7 @@ defineProps({
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -113,7 +102,7 @@ defineProps({
                         :label="t('params.from')"
                         v-model="params.from"
                         @update:model-value="searchFn()"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -123,7 +112,7 @@ defineProps({
                         :label="t('params.to')"
                         v-model="params.to"
                         @update:model-value="searchFn()"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
diff --git a/src/pages/Supplier/Card/SupplierDescriptor.vue b/src/pages/Supplier/Card/SupplierDescriptor.vue
index 462bdf853..2511edf11 100644
--- a/src/pages/Supplier/Card/SupplierDescriptor.vue
+++ b/src/pages/Supplier/Card/SupplierDescriptor.vue
@@ -3,7 +3,7 @@ import { ref, computed, onMounted } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 
 import { toDateString } from 'src/filters';
@@ -61,7 +61,7 @@ const getEntryQueryParams = (supplier) => {
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         :url="`Suppliers/${entityId}`"
         :filter="filter"
         data-key="Supplier"
@@ -106,7 +106,7 @@ const getEntryQueryParams = (supplier) => {
                 <QBtn
                     :to="{
                         name: 'EntryList',
-                        query: { params: JSON.stringify(getEntryQueryParams(entity)) },
+                        query: { table: JSON.stringify(getEntryQueryParams(entity)) },
                     }"
                     size="md"
                     icon="vn:entry"
@@ -136,7 +136,7 @@ const getEntryQueryParams = (supplier) => {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 
 <i18n>
diff --git a/src/pages/Supplier/SupplierList.vue b/src/pages/Supplier/SupplierList.vue
index d1d437a19..ec89d77e0 100644
--- a/src/pages/Supplier/SupplierList.vue
+++ b/src/pages/Supplier/SupplierList.vue
@@ -172,6 +172,7 @@ const filterColumns = computed(() => {
             >
                 <template #more-create-dialog="{ data }">
                     <VnInput
+                        class="col-span-2"
                         :label="t('globals.name')"
                         v-model="data.socialName"
                         :uppercase="true"
diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicData.vue b/src/pages/Ticket/Card/BasicData/TicketBasicData.vue
index 055c9a0ff..83c621b20 100644
--- a/src/pages/Ticket/Card/BasicData/TicketBasicData.vue
+++ b/src/pages/Ticket/Card/BasicData/TicketBasicData.vue
@@ -91,7 +91,7 @@ const totalPrice = computed(() => {
 const totalNewPrice = computed(() => {
     return rows.value.reduce(
         (acc, item) => acc + item.component.newPrice * item.quantity,
-        0
+        0,
     );
 });
 
@@ -210,18 +210,18 @@ onMounted(async () => {
         flat
     >
         <template #body-cell-item="{ row }">
-            <QTd @click.stop class="link">
-                <QBtn flat>
+            <QTd align="center">
+                <span @click.stop class="link">
                     {{ row.itemFk }}
                     <ItemDescriptorProxy :id="row.itemFk" />
-                </QBtn>
+                </span>
             </QTd>
         </template>
         <template #body-cell-description="{ row }">
             <QTd style="min-width: 120px; max-width: 120px">
                 <div class="column q-pb-xs" style="min-width: 120px">
                     <span>{{ row.item.name }}</span>
-                    <FetchedTags :item="row.item" class="full-width" />
+                    <FetchedTags :item="row.item" class="full-width" :columns="6" />
                 </div>
             </QTd>
         </template>
diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
index 9d70fea38..61932468c 100644
--- a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
+++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
@@ -25,9 +25,7 @@ const { validate } = useValidator();
 const { notify } = useNotify();
 const router = useRouter();
 const { t } = useI18n();
-const canEditZone = useAcl().hasAny([
-    { model: 'Ticket', props: 'editZone', accessType: 'WRITE' },
-]);
+const canEditZone = useAcl().hasAcl('Ticket', 'editZone', 'WRITE');
 
 const agencyFetchRef = ref();
 const warehousesOptions = ref([]);
diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue
index ef2eb75d6..76191b099 100644
--- a/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue
+++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue
@@ -45,7 +45,7 @@ const getPriceDifference = async () => {
     };
     const { data } = await axios.post(
         `tickets/${ticket.value.id}/priceDifference`,
-        params
+        params,
     );
     ticket.value.sale = data;
 };
@@ -72,7 +72,7 @@ const submit = async () => {
 
     const { data } = await axios.post(
         `tickets/${ticket.value.id}/componentUpdate`,
-        params
+        params,
     );
 
     if (!data) return;
@@ -99,7 +99,7 @@ const onNextStep = async () => {
             openConfirmationModal(
                 t('basicData.negativesConfirmTitle'),
                 t('basicData.negativesConfirmMessage'),
-                submitWithNegatives
+                submitWithNegatives,
             );
         else submit();
     }
diff --git a/src/pages/Ticket/Card/TicketCard.vue b/src/pages/Ticket/Card/TicketCard.vue
index e22d5799a..19dbd608c 100644
--- a/src/pages/Ticket/Card/TicketCard.vue
+++ b/src/pages/Ticket/Card/TicketCard.vue
@@ -1,10 +1,10 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import TicketDescriptor from './TicketDescriptor.vue';
 import filter from './TicketFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Ticket"
         url="Tickets"
         :descriptor="TicketDescriptor"
diff --git a/src/pages/Ticket/Card/TicketCreateTracking.vue b/src/pages/Ticket/Card/TicketCreateTracking.vue
deleted file mode 100644
index 5c1e916f2..000000000
--- a/src/pages/Ticket/Card/TicketCreateTracking.vue
+++ /dev/null
@@ -1,59 +0,0 @@
-<script setup>
-import { ref } from 'vue';
-import { useRoute } from 'vue-router';
-import { useI18n } from 'vue-i18n';
-
-import FormModelPopup from 'components/FormModelPopup.vue';
-import VnRow from 'components/ui/VnRow.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
-import FetchData from 'components/FetchData.vue';
-
-import { useState } from 'src/composables/useState';
-import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
-
-const emit = defineEmits(['onRequestCreated']);
-
-const route = useRoute();
-const { t } = useI18n();
-const state = useState();
-const user = state.getUser();
-const stateFetchDataRef = ref(null);
-const statesOptions = ref([]);
-
-const onStateFkChange = (formData) => (formData.userFk = user.value.id);
-</script>
-<template>
-    <FetchData
-        ref="stateFetchDataRef"
-        url="States"
-        auto-load
-        @on-fetch="(data) => (statesOptions = data)"
-    />
-    <FormModelPopup
-        :title="t('Create tracking')"
-        url-create="Tickets/state"
-        model="CreateTicketTracking"
-        :form-initial-data="{ ticketFk: route.params.id }"
-        @on-data-saved="() => emit('onRequestCreated')"
-    >
-        <template #form-inputs="{ data }">
-            <VnRow>
-                <VnSelect
-                    v-model="data.stateFk"
-                    :label="t('ticketList.state')"
-                    :options="statesOptions"
-                    @update:model-value="onStateFkChange(data)"
-                    hide-selected
-                    option-label="name"
-                    option-value="id"
-                />
-                <VnSelectWorker v-model="data.userFk" :fields="['id', 'name']" />
-            </VnRow>
-        </template>
-    </FormModelPopup>
-</template>
-
-<i18n>
-    es:
-        Create tracking: Crear estado
-</i18n>
diff --git a/src/pages/Ticket/Card/TicketDescriptor.vue b/src/pages/Ticket/Card/TicketDescriptor.vue
index 1e585592f..96920231c 100644
--- a/src/pages/Ticket/Card/TicketDescriptor.vue
+++ b/src/pages/Ticket/Card/TicketDescriptor.vue
@@ -3,14 +3,15 @@ import { ref, computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import DepartmentDescriptorProxy from 'pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import TicketDescriptorMenu from './TicketDescriptorMenu.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
-import VnUserLink from 'src/components/ui/VnUserLink.vue';
 import { toDateTimeFormat } from 'src/filters/date';
 import filter from './TicketFilter.js';
 import FetchData from 'src/components/FetchData.vue';
 import TicketProblems from 'src/components/TicketProblems.vue';
+import axios from 'axios';
 
 const $props = defineProps({
     id: {
@@ -31,23 +32,37 @@ const entityId = computed(() => {
     return $props.id || route.params.id;
 });
 const problems = ref({});
+const originalTicket = ref();
 
 function ticketFilter(ticket) {
     return JSON.stringify({ clientFk: ticket.clientFk });
 }
+async function getClaims() {
+    const userFilter = { where: { refundTicketFk: entityId.value } };
+    const { data } = await axios.get(`TicketRefunds`, {
+        params: { filter: JSON.stringify(userFilter) },
+    });
+    if (!data) return;
+    originalTicket.value = data[0]?.originalTicketFk;
+}
+async function getProblems() {
+    const { data } = await axios.get(`Tickets/${entityId.value}/getTicketProblems`);
+    if (!data) return;
+    problems.value = data[0];
+}
+function getInfo() {
+    getClaims();
+    getProblems();
+}
 </script>
 
 <template>
-    <FetchData
-        :url="`Tickets/${entityId}/getTicketProblems`"
-        auto-load
-        @on-fetch="(data) => ([problems] = data)"
-    />
-    <CardDescriptor
+    <EntityDescriptor
         :url="`Tickets/${entityId}`"
         :filter="filter"
         data-key="Ticket"
         :summary="$props.summary"
+        @on-fetch="getInfo"
         width="lg-width"
     >
         <template #menu="{ entity }">
@@ -73,12 +88,12 @@ function ticketFilter(ticket) {
                     </QBadge>
                 </template>
             </VnLv>
-            <VnLv :label="t('globals.salesPerson')">
+            <VnLv :label="t('customer.summary.team')">
                 <template #value>
-                    <VnUserLink
-                        :name="entity.client?.salesPersonUser?.name"
-                        :worker-id="entity.client?.salesPersonFk"
-                    />
+                    <span class="link">
+                        {{ entity?.client?.department?.name || '-' }}
+                        <DepartmentDescriptorProxy :id="entity?.client?.departmentFk" />
+                    </span>
                 </template>
             </VnLv>
             <VnLv
@@ -95,7 +110,7 @@ function ticketFilter(ticket) {
         </template>
         <template #icons="{ entity }">
             <QCardActions class="q-gutter-x-xs">
-                <TicketProblems :row="{ ...entity?.client, ...problems }" />
+                <TicketProblems :row="{ ...entity?.client, ...problems, ...entity }" />
             </QCardActions>
         </template>
         <template #actions="{ entity }">
@@ -129,9 +144,18 @@ function ticketFilter(ticket) {
                 >
                     <QTooltip>{{ t('ticket.card.newOrder') }}</QTooltip>
                 </QBtn>
+                <QBtn
+                    v-if="originalTicket"
+                    size="md"
+                    icon="vn:claims"
+                    color="primary"
+                    :to="{ name: 'TicketCard', params: { id: originalTicket } }"
+                >
+                    <QTooltip>{{ t('ticket.card.ticketClaimed') }}</QTooltip>
+                </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 
 <i18n>
diff --git a/src/pages/Ticket/Card/TicketDescriptorMenu.vue b/src/pages/Ticket/Card/TicketDescriptorMenu.vue
index 63e45c8ab..f7389b592 100644
--- a/src/pages/Ticket/Card/TicketDescriptorMenu.vue
+++ b/src/pages/Ticket/Card/TicketDescriptorMenu.vue
@@ -32,7 +32,7 @@ onMounted(() => {
 
 watch(
     () => props.ticket,
-    () => restoreTicket
+    () => restoreTicket,
 );
 
 const { push, currentRoute } = useRouter();
@@ -58,7 +58,7 @@ const hasDocuwareFile = ref();
 const quasar = useQuasar();
 const canRestoreTicket = ref(false);
 
-const onClientSelected = async(clientId) =>{
+const onClientSelected = async (clientId) => {
     client.value = clientId;
     await fetchClient();
     await fetchAddresses();
@@ -66,10 +66,10 @@ const onClientSelected = async(clientId) =>{
 
 const onAddressSelected = (addressId) => {
     address.value = addressId;
-}
+};
 
 const fetchClient = async () => {
-    const response = await getClient(client.value)
+    const response = await getClient(client.value);
     if (!response) return;
     const [retrievedClient] = response.data;
     selectedClient.value = retrievedClient;
@@ -151,7 +151,7 @@ function openDeliveryNote(type = 'deliveryNote', documentType = 'pdf') {
             recipientId: ticket.value.clientFk,
             type: type,
         },
-        '_blank'
+        '_blank',
     );
 }
 
@@ -297,8 +297,8 @@ async function transferClient() {
         clientFk: client.value,
         addressFk: address.value,
     };
-    
-    await axios.patch( `Tickets/${ticketId.value}/transferClient`, params );
+
+    await axios.patch(`Tickets/${ticketId.value}/transferClient`, params);
     window.location.reload();
 }
 
@@ -339,7 +339,7 @@ async function changeShippedHour(time) {
 
     const { data } = await axios.post(
         `Tickets/${ticketId.value}/updateEditableTicket`,
-        params
+        params,
     );
 
     if (data) window.location.reload();
@@ -405,8 +405,7 @@ async function uploadDocuware(force) {
                 uploadDocuware(true);
             });
 
-    const { data } = await axios.post(`Docuwares/upload`, {
-        fileCabinet: 'deliveryNote',
+    const { data } = await axios.post(`Docuwares/upload-delivery-note`, {
         ticketIds: [parseInt(ticketId.value)],
     });
 
@@ -500,7 +499,7 @@ async function ticketToRestore() {
                         </QItem>
                     </template>
                 </VnSelect>
-                <VnSelect 
+                <VnSelect
                     :disable="!client"
                     :options="addressesOptions"
                     :fields="['id', 'nickname']"
@@ -815,7 +814,7 @@ async function ticketToRestore() {
 en:
     addTurn: Add turn
     invoiceIds: "Invoices have been generated with the following ids: {invoiceIds}"
- 
+
 es:
     Show Delivery Note...: Ver albarán...
     Send Delivery Note...: Enviar albarán...
diff --git a/src/pages/Ticket/Card/TicketEditMana.vue b/src/pages/Ticket/Card/TicketEditMana.vue
index ff40a6592..266c82ccd 100644
--- a/src/pages/Ticket/Card/TicketEditMana.vue
+++ b/src/pages/Ticket/Card/TicketEditMana.vue
@@ -33,7 +33,7 @@ const save = (sale = $props.sale) => {
 };
 
 const getMana = async () => {
-    const { data } = await axios.get(`Tickets/${route.params.id}/getSalesPersonMana`);
+    const { data } = await axios.get(`Tickets/${route.params.id}/getDepartmentMana`);
     mana.value = data;
     await getUsesMana();
 };
diff --git a/src/pages/Ticket/Card/TicketFilter.js b/src/pages/Ticket/Card/TicketFilter.js
index 7846f1658..daa204a7a 100644
--- a/src/pages/Ticket/Card/TicketFilter.js
+++ b/src/pages/Ticket/Card/TicketFilter.js
@@ -12,7 +12,7 @@ export default {
                 fields: [
                     'id',
                     'name',
-                    'salesPersonFk',
+                    'departmentFk',
                     'phone',
                     'mobile',
                     'email',
@@ -29,7 +29,7 @@ export default {
                             fields: ['id', 'lang'],
                         },
                     },
-                    { relation: 'salesPersonUser' },
+                    { relation: 'department' },
                 ],
             },
         },
diff --git a/src/pages/Ticket/Card/TicketSale.vue b/src/pages/Ticket/Card/TicketSale.vue
index e69d489c0..e721e2d1c 100644
--- a/src/pages/Ticket/Card/TicketSale.vue
+++ b/src/pages/Ticket/Card/TicketSale.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { onMounted, ref, computed, watch } from 'vue';
+import { onMounted, ref, computed, watch, inject } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRouter, useRoute } from 'vue-router';
 import { useQuasar } from 'quasar';
@@ -25,7 +25,7 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
 import VnConfirm from 'src/components/ui/VnConfirm.vue';
 import TicketProblems from 'src/components/TicketProblems.vue';
 import RightMenu from 'src/components/common/RightMenu.vue';
-
+const app = inject('app');
 const route = useRoute();
 const router = useRouter();
 const { t } = useI18n();
@@ -99,6 +99,7 @@ const columns = computed(() => [
         align: 'left',
         label: t('globals.quantity'),
         name: 'quantity',
+        class: 'shrink',
         format: (row) => toCurrency(row.quantity),
     },
     {
@@ -174,29 +175,39 @@ const getSaleTotal = (sale) => {
     return price - discount;
 };
 
-const getRowUpdateInputEvents = (sale) => ({
-    'keyup.enter': () => {
-        changeQuantity(sale);
-    },
-    blur: () => {
-        changeQuantity(sale);
-    },
-});
+const getRowUpdateInputEvents = (sale) => {
+    return {
+        'keyup.enter': () => {
+            changeQuantity(sale);
+        },
+        blur: () => {
+            changeQuantity(sale);
+        },
+    };
+};
 
 const resetChanges = async () => {
     arrayData.fetch({ append: false });
-    tableRef.value.reload();
+    tableRef.value.CrudModelRef.hasChanges = false;
+    await tableRef.value.reload();
+
+    selectedRows.value = [];
 };
 const changeQuantity = async (sale) => {
     if (!sale.itemFk || sale.quantity == null || sale?.originalQuantity === sale.quantity)
         return;
-    if (!sale.id) return addSale(sale);
+    else sale.originalQuantity = sale.quantity;
+    try {
+        if (!sale.id) await addSale(sale);
+    } catch (e) {
+        app.config.errorHandler(e);
+        return;
+    }
 
     if (await isSalePrepared(sale)) {
         await confirmUpdate(() => updateQuantity(sale));
     } else await updateQuantity(sale);
 };
-
 const updateQuantity = async (sale) => {
     try {
         let { quantity, id } = sale;
@@ -209,7 +220,7 @@ const updateQuantity = async (sale) => {
             (s) => s.id === sale.id,
         );
         sale.quantity = quantity;
-        throw e;
+        app.config.errorHandler(e);
     }
 };
 
@@ -218,24 +229,27 @@ const addSale = async (sale) => {
         barcode: sale.itemFk,
         quantity: sale.quantity,
     };
+    try {
+        const { data } = await axios.post(`tickets/${route.params.id}/addSale`, params);
 
-    const { data } = await axios.post(`tickets/${route.params.id}/addSale`, params);
+        if (!data) return;
 
-    if (!data) return;
+        const newSale = data;
+        sale.id = newSale.id;
+        sale.image = newSale.item.image;
+        sale.subName = newSale.item.subName;
+        sale.concept = newSale.concept;
+        sale.quantity = newSale.quantity;
+        sale.discount = newSale.discount;
+        sale.price = newSale.price;
+        sale.item = newSale.item;
 
-    const newSale = data;
-    sale.id = newSale.id;
-    sale.image = newSale.item.image;
-    sale.subName = newSale.item.subName;
-    sale.concept = newSale.concept;
-    sale.quantity = newSale.quantity;
-    sale.discount = newSale.discount;
-    sale.price = newSale.price;
-    sale.item = newSale.item;
-
-    notify('globals.dataSaved', 'positive');
-    sale.isNew = false;
-    arrayData.fetch({});
+        notify('globals.dataSaved', 'positive');
+        sale.isNew = false;
+        resetChanges();
+    } catch (e) {
+        app.config.errorHandler(e);
+    }
 };
 const changeConcept = async (sale) => {
     if (await isSalePrepared(sale)) {
@@ -244,10 +258,14 @@ const changeConcept = async (sale) => {
 };
 
 const updateConcept = async (sale) => {
-    const data = { newConcept: sale.concept };
-    await axios.post(`Sales/${sale.id}/updateConcept`, data);
-    notify('globals.dataSaved', 'positive');
-    resetChanges();
+    try {
+        const data = { newConcept: sale.concept };
+        await axios.post(`Sales/${sale.id}/updateConcept`, data);
+        notify('globals.dataSaved', 'positive');
+        resetChanges();
+    } catch (e) {
+        app.config.errorHandler(e);
+    }
 };
 
 const DEFAULT_EDIT = {
@@ -294,11 +312,15 @@ const changePrice = async (sale) => {
     }
 };
 const updatePrice = async (sale, newPrice) => {
-    await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice });
-    sale.price = newPrice;
-    edit.value = { ...DEFAULT_EDIT };
-    notify('globals.dataSaved', 'positive');
-    resetChanges();
+    try {
+        await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice });
+        sale.price = newPrice;
+        edit.value = { ...DEFAULT_EDIT };
+        notify('globals.dataSaved', 'positive');
+        resetChanges();
+    } catch (e) {
+        app.config.errorHandler(e);
+    }
 };
 
 const changeDiscount = async (sale) => {
@@ -310,7 +332,7 @@ const changeDiscount = async (sale) => {
     }
 };
 
-const updateDiscounts = async (sales, newDiscount = null) => {
+const updateDiscounts = async (sales, newDiscount) => {
     const salesTracking = await fetchSalesTracking();
 
     const someSaleIsPrepared = salesTracking.some((sale) =>
@@ -320,17 +342,21 @@ const updateDiscounts = async (sales, newDiscount = null) => {
     else updateDiscount(sales, newDiscount);
 };
 
-const updateDiscount = async (sales, newDiscount = null) => {
-    const saleIds = sales.map((sale) => sale.id);
-    const _newDiscount = newDiscount || edit.value.discount;
-    const params = {
-        salesIds: saleIds,
-        newDiscount: _newDiscount,
-        manaCode: manaCode.value,
-    };
-    await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
-    notify('globals.dataSaved', 'positive');
-    resetChanges();
+const updateDiscount = async (sales, newDiscount = 0) => {
+    try {
+        const salesIds = sales.map(({ id }) => id);
+        const params = {
+            salesIds,
+            newDiscount,
+            manaCode: manaCode.value,
+        };
+        await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
+        notify('globals.dataSaved', 'positive');
+        resetChanges();
+    } catch (e) {
+        app.config.errorHandler(e);
+        return;
+    }
 };
 
 const getNewPrice = computed(() => {
@@ -352,30 +378,40 @@ const getNewPrice = computed(() => {
 });
 
 const newOrderFromTicket = async () => {
-    const { data } = await axios.post(`Orders/newFromTicket`, {
-        ticketFk: Number(route.params.id),
-    });
-    const routeData = router.resolve({ name: 'OrderCatalog', params: { id: data } });
-    window.open(routeData.href, '_blank');
+    try {
+        const { data } = await axios.post(`Orders/newFromTicket`, {
+            ticketFk: Number(route.params.id),
+        });
+        const routeData = router.resolve({ name: 'OrderCatalog', params: { id: data } });
+        window.open(routeData.href, '_blank');
+    } catch (e) {
+        app.config.errorHandler(e);
+    }
 };
 
 const goToLog = (saleId) => {
     router.push({
         name: 'TicketLog',
-        params: {
-            originId: route.params.id,
-            changedModel: 'Sale',
-            changedModelId: saleId,
+        query: {
+            logs: JSON.stringify({
+                originFk: route.params.id,
+                changedModel: 'Sale',
+                changedModelId: saleId,
+            }),
         },
     });
 };
 
 const changeTicketState = async (val) => {
-    stateBtnDropdownRef.value.hide();
-    const params = { ticketFk: route.params.id, code: val };
-    await axios.post('Tickets/state', params);
-    notify('globals.dataSaved', 'positive');
-    await resetChanges();
+    try {
+        stateBtnDropdownRef.value.hide();
+        const params = { ticketFk: route.params.id, code: val };
+        await axios.post('Tickets/state', params);
+        notify('globals.dataSaved', 'positive');
+        resetChanges();
+    } catch (e) {
+        app.config.errorHandler(e);
+    }
 };
 
 const removeSelectedSales = () => {
@@ -395,10 +431,14 @@ const removeSales = async () => {
         .forEach((sale) => tableRef.value.CrudModelRef.formData.splice(sale.$index, 1));
 
     if (params.sales.length == 0) return;
-    await axios.post('Sales/deleteSales', params);
-    removeSelectedSales();
-    notify('globals.dataSaved', 'positive');
-    resetChanges();
+    try {
+        await axios.post('Sales/deleteSales', params);
+        removeSelectedSales();
+        notify('globals.dataSaved', 'positive');
+        resetChanges();
+    } catch (e) {
+        app.config.errorHandler(e);
+    }
 };
 
 const setTransferParams = async () => {
@@ -474,7 +514,7 @@ const endNewRow = (row) => {
 };
 
 async function confirmUpdate(cb) {
-    await quasar
+    quasar
         .dialog({
             component: VnConfirm,
             componentProps: {
@@ -664,6 +704,7 @@ watch(
             selection: 'multiple',
         }"
         :right-search="false"
+        :search-url="false"
         :column-search="false"
         :disable-option="{ card: true }"
         auto-load
@@ -703,7 +744,7 @@ watch(
         </template>
         <template #column-image="{ row }">
             <div class="image-wrapper">
-                <VnImg :id="parseInt(row?.item?.id)" class="rounded" />
+                <VnImg v-if="row.item" :id="parseInt(row?.item?.id)" class="rounded" />
             </div>
         </template>
         <template #column-visible="{ row }">
@@ -751,7 +792,7 @@ watch(
                     {{ row?.item?.subName.toUpperCase() }}
                 </div>
             </div>
-            <FetchedTags :item="row.item" :max-length="6" />
+            <FetchedTags v-if="row.item" :item="row.item" :columns="6" :max-length="6" />
             <QPopupProxy v-if="row.id && isTicketEditable">
                 <VnInput
                     v-model="row.concept"
diff --git a/src/pages/Ticket/Card/TicketSaleMoreActions.vue b/src/pages/Ticket/Card/TicketSaleMoreActions.vue
index 840b62507..37441b44f 100644
--- a/src/pages/Ticket/Card/TicketSaleMoreActions.vue
+++ b/src/pages/Ticket/Card/TicketSaleMoreActions.vue
@@ -55,14 +55,11 @@ const isClaimable = computed(() => {
     if (ticket.value) {
         const landedPlusWeek = new Date(ticket.value.landed);
         landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
-        const createAfterDeadline = acl.hasAny([
-            { model: 'Claim', props: 'createAfterDeadline', accessType: 'WRITE' },
-        ]);
+        const createAfterDeadline = acl.hasAcl('Claim', 'createAfterDeadline', 'WRITE');
         return landedPlusWeek >= Date.vnNew() || createAfterDeadline;
     }
     return false;
 });
-const hasReserves = computed(() => props.sales.some((sale) => sale.reserved == true));
 
 const sendSms = async (params) => {
     await axios.post(`Tickets/${ticket.value.id}/sendSms`, params);
@@ -144,14 +141,6 @@ const onCreateClaimAccepted = async () => {
     push({ name: 'ClaimBasicData', params: { id: data.id } });
 };
 
-const setReserved = async (reserved) => {
-    const params = { ticketId: ticket.value.id, sales: props.sales, reserved: reserved };
-    await axios.post(`Sales/reserve`, params);
-    props.sales.forEach((sale) => {
-        sale.reserved = reserved;
-    });
-};
-
 const createRefund = async (withWarehouse) => {
     if (!props.ticket) return;
 
@@ -240,30 +229,6 @@ const createRefund = async (withWarehouse) => {
                     <QItemLabel>{{ t('Add claim') }}</QItemLabel>
                 </QItemSection>
             </QItem>
-            <QItem
-                v-if="isTicketEditable"
-                clickable
-                v-close-popup
-                v-ripple
-                @click="setReserved(true)"
-                data-cy="markAsReservedItem"
-            >
-                <QItemSection>
-                    <QItemLabel>{{ t('Mark as reserved') }}</QItemLabel>
-                </QItemSection>
-            </QItem>
-            <QItem
-                v-if="isTicketEditable && hasReserves"
-                clickable
-                v-close-popup
-                v-ripple
-                @click="setReserved(false)"
-                data-cy="unmarkAsReservedItem"
-            >
-                <QItemSection>
-                    <QItemLabel>{{ t('Unmark as reserved') }}</QItemLabel>
-                </QItemSection>
-            </QItem>
             <QItem clickable v-ripple data-cy="ticketSaleRefundItem">
                 <QItemSection>
                     <QItemLabel>{{ t('Refund') }}</QItemLabel>
@@ -309,8 +274,6 @@ es:
     Recalculate price: Recalcular precio
     Update discount: Actualizar descuento
     Add claim: Crear reclamación
-    Mark as reserved: Marcar como reservado
-    Unmark as reserved: Desmarcar como reservado
     Refund: Abono
     with warehouse: con almacén
     without warehouse: sin almacén
diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue
index 5838efa88..119b867ed 100644
--- a/src/pages/Ticket/Card/TicketSummary.vue
+++ b/src/pages/Ticket/Card/TicketSummary.vue
@@ -13,14 +13,15 @@ import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
 import { getUrl } from 'src/composables/getUrl';
 import useNotify from 'src/composables/useNotify.js';
 import { useArrayData } from 'composables/useArrayData';
-import VnUserLink from 'src/components/ui/VnUserLink.vue';
 import VnTitle from 'src/components/common/VnTitle.vue';
 import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnToSummary from 'src/components/ui/VnToSummary.vue';
 import TicketDescriptorMenu from './TicketDescriptorMenu.vue';
 import TicketProblems from 'src/components/TicketProblems.vue';
+import VnDropdown from 'src/components/common/VnDropdown.vue';
 
 const route = useRoute();
 const { notify } = useNotify();
@@ -40,7 +41,7 @@ const ticket = computed(() => summary.value?.entity);
 const editableStates = ref([]);
 const ticketUrl = ref();
 const grafanaUrl = 'https://grafana.verdnatura.es';
-const stateBtnDropdownRef = ref();
+
 const descriptorData = useArrayData('Ticket');
 
 onMounted(async () => {
@@ -67,7 +68,6 @@ function isEditable() {
 }
 
 async function changeState(value) {
-    stateBtnDropdownRef.value?.hide();
     const formData = {
         ticketFk: entityId.value,
         code: value,
@@ -113,142 +113,139 @@ onMounted(async () => {
             </div>
         </template>
         <template #header-right>
-            <div>
-                <QBtnDropdown
-                    ref="stateBtnDropdownRef"
-                    color="black"
-                    text-color="white"
-                    :label="t('globals.changeState')"
-                    :disable="!isEditable()"
-                >
-                    <VnSelect
-                        :options="editableStates"
-                        hide-selected
-                        option-label="name"
-                        option-value="code"
-                        hide-dropdown-icon
-                        focus-on-mount
-                        @update:model-value="changeState"
-                    />
-                </QBtnDropdown>
-            </div>
+            <VnDropdown
+                :disable="!isEditable()"
+                :options="editableStates"
+                option-value="code"
+                @change-state="changeState"
+            />
         </template>
         <template #menu="{ entity }">
             <TicketDescriptorMenu :ticket="entity" />
         </template>
         <template #body="{ entity }">
-            <QCard class="vn-one">
+            <QCard class="vn-two">
                 <VnTitle
                     :url="toTicketUrl('basic-data')"
                     :text="t('globals.summary.basicData')"
                 />
-                <VnLv v-if="entity.ticketState" :label="t('globals.state')">
-                    <template #value>
-                        <QBadge
-                            text-color="black"
-                            :color="entity.ticketState.state.classColor"
-                        >
-                            {{ entity.ticketState.state.name }}
-                        </QBadge>
-                    </template>
-                </VnLv>
-                <VnLv :label="t('globals.salesPerson')">
-                    <template #value>
-                        <VnUserLink
-                            :name="entity.client?.salesPersonUser?.name"
-                            :worker-id="entity.client?.salesPersonFk"
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
+                        <VnLv v-if="entity.ticketState" :label="t('globals.state')">
+                            <template #value>
+                                <QBadge
+                                    text-color="black"
+                                    :color="entity.ticketState.state.classColor"
+                                >
+                                    {{ entity.ticketState.state.name }}
+                                </QBadge>
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('customer.summary.team')">
+                            <template #value>
+                                <span class="link">
+                                    {{ entity?.client?.department?.name || '-' }}
+                                    <DepartmentDescriptorProxy
+                                        :id="entity?.client?.departmentFk"
+                                    />
+                                </span>
+                            </template>
+                        </VnLv>
+                        <VnLv
+                            :label="t('globals.agency')"
+                            :value="entity.agencyMode?.name"
                         />
-                    </template>
-                </VnLv>
-                <VnLv :label="t('globals.agency')" :value="entity.agencyMode?.name" />
-                <VnLv :label="t('ticket.summary.zone')">
-                    <template #value>
-                        <span class="link" @click.stop>
-                            {{ entity?.zone?.name }}
-                            <ZoneDescriptorProxy :id="entity.zoneFk" />
-                        </span>
-                    </template>
-                </VnLv>
-                <VnLv :label="t('globals.warehouse')" :value="entity.warehouse?.name" />
-                <VnLv
-                    v-if="ticket?.ticketCollections?.length > 0"
-                    :label="t('ticket.summary.collection')"
-                    :value="ticket?.ticketCollections[0]?.collectionFk"
-                >
-                    <template #value>
-                        <a
-                            :href="`${grafanaUrl}/d/d552ab74-85b4-4e7f-a279-fab7cd9c6124/control-de-expediciones?orgId=1&var-collectionFk=${entity.ticketCollections[0]?.collectionFk}`"
-                            target="_blank"
-                            class="grafana"
+                        <VnLv :label="t('ticket.summary.zone')">
+                            <template #value>
+                                <span class="link" @click.stop>
+                                    {{ entity?.zone?.name }}
+                                    <ZoneDescriptorProxy :id="entity.zoneFk" />
+                                </span>
+                            </template>
+                        </VnLv>
+                        <VnLv
+                            :label="t('globals.warehouse')"
+                            :value="entity.warehouse?.name"
+                        />
+                        <VnLv
+                            v-if="ticket?.ticketCollections?.length > 0"
+                            :label="t('ticket.summary.collection')"
+                            :value="ticket?.ticketCollections[0]?.collectionFk"
                         >
-                            {{ entity.ticketCollections[0]?.collectionFk }}
-                        </a>
-                    </template>
-                </VnLv>
-                <VnLv :label="t('ticket.summary.route')">
-                    <template #value>
-                        <span class="link">
-                            {{ entity.routeFk }}
-                            <RouteDescriptorProxy :id="entity.routeFk" />
-                        </span>
-                    </template>
-                </VnLv>
-                <VnLv :label="t('ticket.summary.invoice')">
-                    <template #value>
-                        <span :class="{ link: entity.refFk }">
-                            {{ dashIfEmpty(entity.refFk) }}
-                            <InvoiceOutDescriptorProxy
-                                :id="entity.invoiceOut.id"
-                                v-if="entity.refFk"
-                            />
-                        </span>
-                    </template>
-                </VnLv>
-                <VnLv :label="t('globals.weight')" :value="dashIfEmpty(entity.weight)" />
-            </QCard>
-            <QCard class="vn-one">
-                <VnTitle
-                    :url="toTicketUrl('basic-data')"
-                    :text="t('globals.summary.basicData')"
-                />
-                <VnLv
-                    :label="t('ticket.summary.shipped')"
-                    :value="toDate(entity.shipped)"
-                />
-                <VnLv :label="t('globals.landed')" :value="toDate(entity.landed)" />
-                <VnLv :label="t('globals.packages')" :value="entity.packages" />
-                <VnLv :value="entity.address.phone">
-                    <template #label>
-                        {{ t('ticket.summary.consigneePhone') }}
-                        <VnLinkPhone :phone-number="entity.address.phone" />
-                    </template>
-                </VnLv>
-                <VnLv :value="entity.address.mobile">
-                    <template #label>
-                        {{ t('ticket.summary.consigneeMobile') }}
-                        <VnLinkPhone :phone-number="entity.address.mobile" />
-                    </template>
-                </VnLv>
-                <VnLv :value="entity.client.phone">
-                    <template #label>
-                        {{ t('ticket.summary.clientPhone') }}
-                        <VnLinkPhone :phone-number="entity.client.phone" />
-                    </template>
-                </VnLv>
-                <VnLv :value="entity.client.mobile">
-                    <template #label>
-                        {{ t('ticket.summary.clientMobile') }}
-                        <VnLinkPhone :phone-number="entity.client.mobile" />
-                    </template>
-                </VnLv>
-                <VnLv
-                    :label="t('ticket.summary.consignee')"
-                    :value="`${entity.address?.nickname} #${entity.address?.id}`"
-                />
-                <VnLv
-                    :label="t('ticket.summary.consigneeStreet')"
-                    :value="formattedAddress"
-                />
+                            <template #value>
+                                <a
+                                    :href="`${grafanaUrl}/d/d552ab74-85b4-4e7f-a279-fab7cd9c6124/control-de-expediciones?orgId=1&var-collectionFk=${entity.ticketCollections[0]?.collectionFk}`"
+                                    target="_blank"
+                                    class="grafana"
+                                >
+                                    {{ entity.ticketCollections[0]?.collectionFk }}
+                                </a>
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('ticket.summary.route')">
+                            <template #value>
+                                <span class="link">
+                                    {{ entity.routeFk }}
+                                    <RouteDescriptorProxy :id="entity.routeFk" />
+                                </span>
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('ticket.summary.invoice')">
+                            <template #value>
+                                <span :class="{ link: entity.refFk }">
+                                    {{ dashIfEmpty(entity.refFk) }}
+                                    <InvoiceOutDescriptorProxy
+                                        :id="entity.invoiceOut.id"
+                                        v-if="entity.refFk"
+                                    />
+                                </span>
+                            </template>
+                        </VnLv>
+                        <VnLv
+                            :label="t('globals.weight')"
+                            :value="dashIfEmpty(entity.weight)"
+                        />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('ticket.summary.shipped')"
+                            :value="toDate(entity.shipped)"
+                        />
+                        <VnLv
+                            :label="t('globals.landed')"
+                            :value="toDate(entity.landed)"
+                        />
+                        <VnLv :label="t('globals.packages')" :value="entity.packages" />
+                        <VnLv :label="t('ticket.summary.consigneePhone')">
+                            <template #value>
+                                <VnLinkPhone :phone-number="entity.address.phone" />
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('ticket.summary.consigneeMobile')">
+                            <template #value>
+                                <VnLinkPhone :phone-number="entity.address.mobile" />
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('ticket.summary.clientPhone')">
+                            <template #value>
+                                <VnLinkPhone :phone-number="entity.client.phone" />
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('ticket.summary.clientMobile')">
+                            <template #value>
+                                <VnLinkPhone :phone-number="entity.client.mobile" />
+                            </template>
+                        </VnLv>
+                        <VnLv
+                            :label="t('ticket.summary.consignee')"
+                            :value="`${entity.address?.nickname} #${entity.address?.id}`"
+                        />
+                        <VnLv
+                            :label="t('ticket.summary.consigneeStreet')"
+                            :value="formattedAddress"
+                        />
+                    </div>
+                </div>
             </QCard>
             <QCard class="vn-one" v-if="entity.notes.length">
                 <VnTitle
diff --git a/src/pages/Ticket/Card/TicketTracking.vue b/src/pages/Ticket/Card/TicketTracking.vue
index 00610de44..06171366d 100644
--- a/src/pages/Ticket/Card/TicketTracking.vue
+++ b/src/pages/Ticket/Card/TicketTracking.vue
@@ -1,27 +1,23 @@
 <script setup>
-import { ref, computed, watch, reactive } from 'vue';
+import { ref, reactive, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
 
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
-import TicketCreateTracking from './TicketCreateTracking.vue';
-import VnPaginate from 'components/ui/VnPaginate.vue';
+import VnSelect from 'src/components/common/VnSelect.vue';
+import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
+import { useState } from 'src/composables/useState';
 
 import { toDateTimeFormat } from 'src/filters/date.js';
+import VnTable from 'src/components/VnTable/VnTable.vue';
+const state = useState();
+
+const user = state.getUser();
 
 const route = useRoute();
 const { t } = useI18n();
-const createTrackingDialogRef = ref(null);
-const paginateRef = ref(null);
-
-watch(
-    () => route.params.id,
-    async (val) => {
-        paginateFilter.where.ticketFk = val;
-        paginateRef.value.fetch();
-    },
-);
-
+const tableRef = ref(null);
+const onStateFkChange = (formData) => (formData.userFk = user.value.id);
 const paginateFilter = reactive({
     include: [
         {
@@ -56,75 +52,68 @@ const columns = computed(() => [
         name: 'state',
         field: 'state',
         align: 'left',
-        format: (val) => val.name,
+        format: (row) => row.state?.name,
     },
     {
         label: t('expedition.worker'),
         name: 'worker',
         align: 'left',
+        field: 'user',
     },
     {
         label: t('expedition.created'),
         name: 'created',
         field: 'created',
         align: 'left',
-        format: (val) => toDateTimeFormat(val),
+        format: ({ created }) => toDateTimeFormat(created),
     },
 ]);
-
-const openCreateModal = () => createTrackingDialogRef.value.show();
 </script>
 
 <template>
-    <QPage class="column items-center q-pa-md">
-        <VnPaginate
-            ref="paginateRef"
-            data-key="TicketTracking"
-            :user-filter="paginateFilter"
-            search-url="table"
-            url="TicketTrackings"
-            auto-load
-            order="created DESC"
-            :limit="0"
-        >
-            <template #body="{ rows }">
-                <QTable
-                    :rows="rows"
-                    :columns="columns"
-                    row-key="id"
-                    :pagination="{ rowsPerPage: 0 }"
-                    class="full-width q-mt-md"
-                    :no-data-label="t('globals.noResults')"
-                >
-                    <template #body-cell-worker="{ row }">
-                        <QTd>
-                            <QBtn flat class="link" @click.stop>
-                                {{ row.user?.name }}
-                                <WorkerDescriptorProxy :id="row.user?.worker?.id" />
-                            </QBtn>
-                        </QTd>
-                    </template>
-                </QTable>
-            </template>
-        </VnPaginate>
-        <QDialog
-            ref="createTrackingDialogRef"
-            transition-show="scale"
-            transition-hide="scale"
-        >
-            <TicketCreateTracking @on-request-created="paginateRef.fetch()" />
-        </QDialog>
-        <QPageSticky :offset="[20, 20]">
-            <QBtn
-                @click="openCreateModal()"
-                color="primary"
-                fab
-                icon="add"
-                v-shortcut="'+'"
+    <VnTable
+        ref="tableRef"
+        :right-search="false"
+        :column-search="false"
+        :disable-option="{ card: true, table: true }"
+        :search-url="false"
+        :columns="columns"
+        data-key="TicketTracking"
+        :user-filter="paginateFilter"
+        url="TicketTrackings"
+        auto-load
+        order="created DESC"
+        :limit="0"
+        :without-header="true"
+        :create="{
+            urlCreate: 'Tickets/state',
+            title: t('Create tracking'),
+            onDataSaved: () => tableRef.reload(),
+            formInitialData: {
+                ticketFk: route.params.id,
+            },
+        }"
+    >
+        <template #more-create-dialog="{ data }">
+            <VnSelect
+                url="States"
+                v-model="data.stateFk"
+                :label="t('ticketList.state')"
+                auto-load
+                @update:model-value="onStateFkChange(data)"
+                hide-selected
             />
-            <QTooltip class="text-no-wrap">
-                {{ t('tracking.addState') }}
-            </QTooltip>
-        </QPageSticky>
-    </QPage>
+            <VnSelectWorker v-model="data.userFk" :fields="['id', 'name']" />
+        </template>
+        <template #column-worker="{ row }">
+            <span class="link" @click.stop>
+                {{ row.user.name }}
+                <WorkerDescriptorProxy :id="row.user?.worker?.id" />
+            </span>
+        </template>
+    </VnTable>
 </template>
+<i18n>
+    es:
+        Create tracking: Crear estado
+</i18n>
diff --git a/src/pages/Ticket/Card/TicketVolume.vue b/src/pages/Ticket/Card/TicketVolume.vue
index db78094cf..690ae9063 100644
--- a/src/pages/Ticket/Card/TicketVolume.vue
+++ b/src/pages/Ticket/Card/TicketVolume.vue
@@ -134,7 +134,7 @@ onMounted(() => (stateStore.rightDrawer = true));
         auto-load
     >
         <template #column-itemFk="{ row }">
-            <span class="link">
+            <span class="link" @click.stop>
                 {{ row.itemFk }}
                 <ItemDescriptorProxy :id="row.itemFk" />
             </span>
diff --git a/src/pages/Ticket/Card/__tests__/TicketBoxing.spec.js b/src/pages/Ticket/Card/__tests__/TicketBoxing.spec.js
index 8fd62d8c2..a1dd7775d 100644
--- a/src/pages/Ticket/Card/__tests__/TicketBoxing.spec.js
+++ b/src/pages/Ticket/Card/__tests__/TicketBoxing.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import TicketBoxing from 'pages/Ticket/Card/TicketBoxing.vue';
 
 // #4836 - Investigate how to test q-drawer outside
@@ -21,7 +22,11 @@ describe('TicketBoxing', () => {
                 min: 1,
                 max: 2,
             };
-            const videoList = ['2022-01-01T01-01-00.mp4', '2022-02-02T02-02-00.mp4', '2022-03-03T03-03-00.mp4'];
+            const videoList = [
+                '2022-01-01T01-01-00.mp4',
+                '2022-02-02T02-02-00.mp4',
+                '2022-03-03T03-03-00.mp4',
+            ];
 
             vi.spyOn(axios, 'get').mockResolvedValue({ data: videoList });
             vi.spyOn(vm.quasar, 'notify');
@@ -44,7 +49,9 @@ describe('TicketBoxing', () => {
 
             await vm.getVideoList(expeditionId, timed);
 
-            expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining({ type: 'negative' }));
+            expect(vm.quasar.notify).toHaveBeenCalledWith(
+                expect.objectContaining({ type: 'negative' })
+            );
         });
     });
 });
diff --git a/src/pages/Ticket/Negative/TicketLackFilter.vue b/src/pages/Ticket/Negative/TicketLackFilter.vue
index 3762f453d..73d53b247 100644
--- a/src/pages/Ticket/Negative/TicketLackFilter.vue
+++ b/src/pages/Ticket/Negative/TicketLackFilter.vue
@@ -81,7 +81,7 @@ const setUserParams = (params) => {
                             v-model="params.days"
                             :label="t('negative.days')"
                             dense
-                            is-outlined
+                            filled
                             type="number"
                             @update:model-value="
                                 (value) => {
@@ -97,7 +97,7 @@ const setUserParams = (params) => {
                             v-model="params.id"
                             :label="t('negative.id')"
                             dense
-                            is-outlined
+                            filled
                         />
                     </QItemSection>
                 </QItem>
@@ -107,7 +107,7 @@ const setUserParams = (params) => {
                             v-model="params.producer"
                             :label="t('negative.producer')"
                             dense
-                            is-outlined
+                            filled
                         />
                     </QItemSection>
                 </QItem>
@@ -117,7 +117,7 @@ const setUserParams = (params) => {
                             v-model="params.origen"
                             :label="t('negative.origen')"
                             dense
-                            is-outlined
+                            filled
                         />
                     </QItemSection> </QItem
                 ><QItem>
@@ -133,8 +133,7 @@ const setUserParams = (params) => {
                             option-label="name"
                             hide-selected
                             dense
-                            outlined
-                            rounded
+                            filled
                         /> </QItemSection
                     ><QItemSection v-else>
                         <QSkeleton class="full-width" type="QSelect" />
@@ -151,8 +150,7 @@ const setUserParams = (params) => {
                             option-label="name"
                             hide-selected
                             dense
-                            outlined
-                            rounded
+                            filled
                         >
                             <template #option="scope">
                                 <QItem v-bind="scope.itemProps">
diff --git a/src/pages/Ticket/Negative/TicketLackTable.vue b/src/pages/Ticket/Negative/TicketLackTable.vue
index 176e8f7ad..c9c2a7cad 100644
--- a/src/pages/Ticket/Negative/TicketLackTable.vue
+++ b/src/pages/Ticket/Negative/TicketLackTable.vue
@@ -225,7 +225,7 @@ function onBuysFetched(data) {
                     />
                 </div>
                 <div class="flex column left" style="align-items: flex-start">
-                    <QBtn flat class="link text-blue">
+                    <QBtn flat class="link">
                         {{ item?.longName ?? item.name }}
                         <ItemDescriptorProxy :id="entityId" />
                         <FetchedTags class="q-ml-md" :item="item" :columns="7" />
diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index 94b4623aa..bf3593acd 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -259,7 +259,7 @@ const moveTicketsAdvance = async () => {
             destinationId: ticket.id,
             originShipped: ticket.futureShipped,
             destinationShipped: ticket.shipped,
-            salesPersonFk: ticket.workerFk,
+            departmentFk: ticket.departmentFk,
         });
     }
     const params = { tickets: ticketsToMove };
@@ -285,7 +285,7 @@ const progressAdd = () => {
             t('advanceTickets.moveTicketSuccess', {
                 ticketsNumber: progressLength.value - splitErrors.value.length,
             }),
-            'positive'
+            'positive',
         );
     }
 };
@@ -345,16 +345,16 @@ watch(
         originElRef.value.setAttribute('colspan', '9');
 
         destinationElRef.value.textContent = `${t(
-            'advanceTickets.destination'
+            'advanceTickets.destination',
         )} ${toDateFormat(vnTableRef.value.params.dateToAdvance)}`;
         originElRef.value.textContent = `${t('advanceTickets.origin')} ${toDateFormat(
-            vnTableRef.value.params.dateFuture
+            vnTableRef.value.params.dateFuture,
         )}`;
 
         newRow.append(destinationElRef.value, originElRef.value);
         head.insertBefore(newRow, firstRow);
     },
-    { once: true, inmmediate: true }
+    { once: true, inmmediate: true },
 );
 
 watch(
@@ -362,14 +362,14 @@ watch(
     () => {
         if (originElRef.value && destinationElRef.value) {
             destinationElRef.value.textContent = `${t(
-                'advanceTickets.destination'
+                'advanceTickets.destination',
             )} ${toDateFormat(vnTableRef.value.params.dateToAdvance)}`;
             originElRef.value.textContent = `${t('advanceTickets.origin')} ${toDateFormat(
-                vnTableRef.value.params.dateFuture
+                vnTableRef.value.params.dateFuture,
             )}`;
         }
     },
-    { deep: true }
+    { deep: true },
 );
 </script>
 <template>
@@ -405,7 +405,7 @@ watch(
                         t(`advanceTickets.advanceTitleSubtitle`, {
                             selectedTickets: selectedTickets.length,
                         }),
-                        moveTicketsAdvance
+                        moveTicketsAdvance,
                     )
                 "
             >
@@ -423,7 +423,7 @@ watch(
                         t(`advanceTickets.advanceWithoutNegativeSubtitle`, {
                             selectedTickets: selectedTickets.length,
                         }),
-                        splitTickets
+                        splitTickets,
                     )
                 "
             >
diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index 6d5c7726e..f065eaf2e 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -71,7 +71,7 @@ onMounted(async () => await getItemPackingTypes());
                     <VnInputDate
                         v-model="params.dateFuture"
                         :label="t('params.dateFuture')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -80,7 +80,7 @@ onMounted(async () => await getItemPackingTypes());
                     <VnInputDate
                         v-model="params.dateToAdvance"
                         :label="t('params.dateToAdvance')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -95,8 +95,7 @@ onMounted(async () => await getItemPackingTypes());
                         :info="t('iptInfo')"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :use-like="false"
                     >
                     </VnSelect>
@@ -113,8 +112,7 @@ onMounted(async () => await getItemPackingTypes());
                         :info="t('iptInfo')"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                         :use-like="false"
                     >
                     </VnSelect>
@@ -125,7 +123,7 @@ onMounted(async () => await getItemPackingTypes());
                     <VnInputNumber
                         v-model="params.scopeDays"
                         :label="t('Days onward')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -147,8 +145,7 @@ onMounted(async () => await getItemPackingTypes());
                         url="Departments"
                         :fields="['id', 'name']"
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -162,8 +159,7 @@ onMounted(async () => await getItemPackingTypes());
                         option-label="name"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                     </VnSelect>
                 </QItemSection>
diff --git a/src/pages/Ticket/TicketFilter.vue b/src/pages/Ticket/TicketFilter.vue
index bdf75c826..d84d1c082 100644
--- a/src/pages/Ticket/TicketFilter.vue
+++ b/src/pages/Ticket/TicketFilter.vue
@@ -22,16 +22,6 @@ const states = ref([]);
 const agencies = ref([]);
 const warehouses = ref([]);
 const groupedStates = ref([]);
-
-const getGroupedStates = (data) => {
-    for (const state of data) {
-        groupedStates.value.push({
-            id: state.id,
-            name: t(`${state.code}`),
-            code: state.code,
-        });
-    }
-};
 </script>
 
 <template>
@@ -39,12 +29,11 @@ const getGroupedStates = (data) => {
     <FetchData url="States" @on-fetch="(data) => (states = data)" auto-load />
     <FetchData
         url="AlertLevels"
-        @on-fetch="
-            (data) => {
-                getGroupedStates(data);
-            }
-        "
         auto-load
+        @on-fetch="
+            (data) =>
+                (groupedStates = data.map((x) => Object.assign(x, { code: t(x.code) })))
+        "
     />
     <FetchData
         url="AgencyModes"
@@ -63,18 +52,10 @@ const getGroupedStates = (data) => {
         <template #body="{ params, searchFn }">
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.clientFk"
-                        :label="t('Customer ID')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.clientFk" :label="t('Customer ID')" filled />
                 </QItemSection>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.orderFk"
-                        :label="t('Order ID')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.orderFk" :label="t('Order ID')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -82,7 +63,7 @@ const getGroupedStates = (data) => {
                     <VnInputDate
                         v-model="params.from"
                         :label="t('From')"
-                        is-outlined
+                        filled
                         data-cy="From_date"
                     />
                 </QItemSection>
@@ -90,22 +71,21 @@ const getGroupedStates = (data) => {
                     <VnInputDate
                         v-model="params.to"
                         :label="t('To')"
-                        is-outlined
+                        filled
                         data-cy="To_date"
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnSelectWorker
-                        :label="t('globals.salesPerson')"
-                        v-model="params.salesPersonFk"
-                        :params="{
-                            departmentCodes: ['VT'],
-                        }"
+                    <VnSelect
                         dense
-                        outlined
-                        rounded
+                        filled
+                        :label="t('globals.params.departmentFk')"
+                        v-model="params.departmentFk"
+                        option-value="id"
+                        option-label="name"
+                        url="Departments"
                     />
                 </QItemSection>
             </QItem>
@@ -125,8 +105,7 @@ const getGroupedStates = (data) => {
                         map-options
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -136,29 +115,23 @@ const getGroupedStates = (data) => {
                 </QItemSection>
                 <QItemSection v-if="groupedStates">
                     <VnSelect
-                        :label="t('Grouped state')"
+                        :label="t('params.groupedStates')"
                         v-model="params.groupedStates"
                         @update:model-value="searchFn()"
                         :options="groupedStates"
-                        option-value="id"
-                        option-label="name"
+                        option-label="code"
                         emit-value
                         map-options
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                         sort-by="name ASC"
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.refFk"
-                        :label="t('Invoice Ref.')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.refFk" :label="t('Invoice Ref.')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -166,17 +139,13 @@ const getGroupedStates = (data) => {
                     <VnInput
                         v-model="params.scopeDays"
                         :label="t('Days onward')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        v-model="params.nickname"
-                        :label="t('Nickname')"
-                        is-outlined
-                    />
+                    <VnInput v-model="params.nickname" :label="t('Nickname')" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -241,8 +210,7 @@ const getGroupedStates = (data) => {
                         map-options
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -260,8 +228,7 @@ const getGroupedStates = (data) => {
                         map-options
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -281,8 +248,7 @@ const getGroupedStates = (data) => {
                         map-options
                         use-input
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -291,7 +257,7 @@ const getGroupedStates = (data) => {
                     <VnInput
                         v-model="params.collectionFk"
                         :label="t('Collection')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -308,7 +274,6 @@ en:
         from: From
         shipped: Shipped
         to: To
-        salesPersonFk: Salesperson
         stateFk: State
         groupedStates: Grouped State
         refFk: Invoice Ref.
@@ -327,7 +292,7 @@ en:
     ON_PREPARATION: On preparation
     PACKED: Packed
     DELIVERED: Delivered
-    ON_PREVIOUS: ON_PREVIOUS
+    ON_PREVIOUS: On previous
 es:
     params:
         search: Contiene
@@ -336,7 +301,6 @@ es:
         from: Desde
         shipped: F. envío
         to: Hasta
-        salesPersonFk: Comercial
         stateFk: Estado
         groupedStates: Estado agrupado
         refFk: Ref. Factura
@@ -355,7 +319,6 @@ es:
     Order ID: ID Pedido
     From: Desde
     To: Hasta
-    Salesperson: Comercial
     State: Estado
     Invoice Ref.: Ref. Factura
     My team: Mi equipo
@@ -374,7 +337,7 @@ es:
     ON_PREPARATION: En preparación
     PACKED: Encajado
     DELIVERED: Servido
-    ON_PREVIOUS: ON_PREVIOUS
+    ON_PREVIOUS: En previa
     Collection: Colección
     Nickname: Nombre mostrado
 </i18n>
diff --git a/src/pages/Ticket/TicketFuture.vue b/src/pages/Ticket/TicketFuture.vue
index 92911cd25..588379ed9 100644
--- a/src/pages/Ticket/TicketFuture.vue
+++ b/src/pages/Ticket/TicketFuture.vue
@@ -160,7 +160,7 @@ const moveTicketsFuture = async () => {
             destinationId: ticket.futureId,
             originShipped: ticket.shipped,
             destinationShipped: ticket.futureShipped,
-            salesPersonFk: ticket.salesPersonFk,
+            departmentFk: ticket.departmentFk,
         };
     });
 
diff --git a/src/pages/Ticket/TicketFutureFilter.vue b/src/pages/Ticket/TicketFutureFilter.vue
index 64e060a39..033b47f72 100644
--- a/src/pages/Ticket/TicketFutureFilter.vue
+++ b/src/pages/Ticket/TicketFutureFilter.vue
@@ -73,7 +73,7 @@ onMounted(async () => {
                     <VnInputDate
                         v-model="params.originScopeDays"
                         :label="t('params.originScopeDays')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -82,7 +82,7 @@ onMounted(async () => {
                     <VnInputDate
                         v-model="params.futureScopeDays"
                         :label="t('params.futureScopeDays')"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -91,7 +91,7 @@ onMounted(async () => {
                     <VnInput
                         :label="t('params.litersMax')"
                         v-model="params.litersMax"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -100,7 +100,7 @@ onMounted(async () => {
                     <VnInput
                         :label="t('params.linesMax')"
                         v-model="params.linesMax"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -115,8 +115,7 @@ onMounted(async () => {
                         :info="t('iptInfo')"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                     </VnSelect>
                 </QItemSection>
@@ -132,8 +131,7 @@ onMounted(async () => {
                         :info="t('iptInfo')"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                     </VnSelect>
                 </QItemSection>
@@ -148,8 +146,7 @@ onMounted(async () => {
                         option-label="name"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                     </VnSelect>
                 </QItemSection>
@@ -164,8 +161,7 @@ onMounted(async () => {
                         option-label="name"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                     </VnSelect>
                 </QItemSection>
@@ -191,8 +187,7 @@ onMounted(async () => {
                         option-label="name"
                         @update:model-value="searchFn()"
                         dense
-                        outlined
-                        rounded
+                        filled
                     >
                     </VnSelect>
                 </QItemSection>
diff --git a/src/pages/Ticket/TicketList.vue b/src/pages/Ticket/TicketList.vue
index b2e13fcb6..634b8e50a 100644
--- a/src/pages/Ticket/TicketList.vue
+++ b/src/pages/Ticket/TicketList.vue
@@ -17,6 +17,7 @@ import TicketFilter from './TicketFilter.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import FetchData from 'src/components/FetchData.vue';
 import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
 import { toTimeFormat } from 'src/filters/date';
 import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
@@ -54,8 +55,7 @@ onBeforeMount(() => {
 onMounted(async () => {
     if (!route.query) return;
     if (route.query?.createForm) {
-        formInitialData.value = JSON.parse(route.query?.createForm);
-        await onClientSelected(formInitialData.value);
+        await onClientSelected(JSON.parse(route.query?.createForm));
     } else if (route.query?.table) {
         const query = route.query?.table;
         const clientId = +JSON.parse(query)?.clientFk;
@@ -100,26 +100,20 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        label: t('ticketList.salesPerson'),
-        name: 'salesPersonFk',
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
         component: 'select',
         attrs: {
-            url: 'Workers/activeWithInheritedRole',
-            fields: ['id', 'name'],
-            where: { role: 'salesPerson' },
-            optionFilter: 'firstName',
-            useLike: false,
+            url: 'Departments',
         },
         columnField: {
             component: null,
         },
-        columnClass: 'expand',
-        cardVisible: true,
-        format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson),
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
     {
         align: 'left',
-        name: 'shipped',
+        name: 'shippedDate',
         cardVisible: true,
         label: t('ticketList.shipped'),
         columnFilter: {
@@ -129,7 +123,7 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        name: 'shipped',
+        name: 'shippedHour',
         component: 'time',
         columnFilter: false,
         label: t('ticketList.hour'),
@@ -254,7 +248,7 @@ const columns = computed(() => [
                             name: 'TicketCard',
                         }).href;
                         window.open(url, '_blank');
-                    } else viewSummary(row.id, TicketSummary);
+                    } else viewSummary(row.id, TicketSummary, 'lg-width');
                 },
             },
         ],
@@ -273,12 +267,18 @@ const fetchAddresses = async (formData) => {
         return;
     }
     const { data } = await getAddresses(formData.clientId);
-    formInitialData.value = { clientId: formData.clientId };
-    if (!data) return;
+
+    if (!data) {
+        formInitialData.value = { clientId: formData.clientId };
+        return;
+    }
     addressesOptions.value = data;
     selectedClient.value = data[0].client;
     formData.addressId = selectedClient.value.defaultAddressFk;
-    formInitialData.value.addressId = formData.addressId;
+    formInitialData.value = {
+        clientId: formData.clientId,
+        addressId: formData.addressId,
+    };
 };
 watch(
     () => route.query.table,
@@ -340,25 +340,20 @@ async function makeInvoice(ticket) {
         });
 }
 
-async function sendDocuware(ticket) {
-    try {
-        let ticketIds = ticket.map((item) => item.id);
+async function sendDocuware(tickets) {
+    let ticketIds = tickets.map((item) => item.id);
 
-        const { data } = await axios.post(`Docuwares/upload`, {
-            fileCabinet: 'deliveryNote',
-            ticketIds,
-        });
+    const { data } = await axios.post(`Docuwares/upload-delivery-note`, {
+        ticketIds,
+    });
 
-        for (let ticket of ticketIds) {
-            ticket.stateFk = data.id;
-            ticket.state = data.name;
-            ticket.alertLevel = data.alertLevel;
-            ticket.alertLevelCode = data.code;
-        }
-        notify('globals.dataSaved', 'positive');
-    } catch (err) {
-        console.err('err: ', err);
+    for (let ticket of tickets) {
+        ticket.stateFk = data.id;
+        ticket.state = data.name;
+        ticket.alertLevel = data.alertLevel;
+        ticket.alertLevelCode = data.code;
     }
+    notify('globals.dataSaved', 'positive');
 }
 
 function openBalanceDialog(ticket) {
@@ -514,10 +509,10 @@ function setReference(data) {
                 <template #column-statusIcons="{ row }">
                     <TicketProblems :row="row" />
                 </template>
-                <template #column-salesPersonFk="{ row }">
+                <template #column-departmentFk="{ row }">
                     <span class="link" @click.stop>
-                        {{ dashIfEmpty(row.userName) }}
-                        <CustomerDescriptorProxy :id="row.salesPersonFk" />
+                        {{ dashIfEmpty(row.departmentName) }}
+                        <DepartmentDescriptorProxy :id="row.departmentFk" />
                     </span>
                 </template>
                 <template #column-shippedDate="{ row }">
diff --git a/src/pages/Ticket/TicketWeekly.vue b/src/pages/Ticket/TicketWeekly.vue
index 0e18fe028..d6493550b 100644
--- a/src/pages/Ticket/TicketWeekly.vue
+++ b/src/pages/Ticket/TicketWeekly.vue
@@ -5,7 +5,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
 import VnSelectCache from 'src/components/common/VnSelectCache.vue';
 import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
 import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
-import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { useVnConfirm } from 'composables/useVnConfirm';
@@ -112,23 +112,17 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        name: 'id',
-        label: t('weeklyTickets.salesperson'),
-        columnFilter: {
-            component: 'select',
-            alias: 'u',
-            attrs: {
-                url: 'Workers/activeWithInheritedRole',
-                fields: ['id', 'name'],
-                where: { role: 'salesperson' },
-            },
-            inWhere: true,
+        name: 'departmentFk',
+        label: t('customer.summary.team'),
+        component: 'select',
+        attrs: {
+            url: 'Departments',
         },
+        create: true,
         columnField: {
             component: null,
         },
-        cardVisible: true,
-        format: (row) => row.userName,
+        format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
     },
     {
         align: 'right',
@@ -142,9 +136,9 @@ const columns = computed(() => [
                     openConfirmationModal(
                         t('You are going to delete this weekly ticket'),
                         t(
-                            'This ticket will be removed from weekly tickets! Continue anyway?'
+                            'This ticket will be removed from weekly tickets! Continue anyway?',
                         ),
-                        () => deleteWeekly(row.ticketFk)
+                        () => deleteWeekly(row.ticketFk),
                     ),
                 isPrimary: true,
             },
@@ -219,10 +213,10 @@ onMounted(async () => {
                 <CustomerDescriptorProxy :id="row.clientFk" />
             </span>
         </template>
-        <template #column-id="{ row }">
+        <template #column-departmentFk="{ row }">
             <span class="link" @click.stop>
-                {{ row.userName }}
-                <WorkerDescriptorProxy :id="row.workerFk" />
+                {{ row.departmentName }}
+                <DepartmentDescriptorProxy :id="row.departmentFk" />
             </span>
         </template>
     </VnTable>
diff --git a/src/pages/Ticket/__tests__/TicketAdvance.spec.js b/src/pages/Ticket/__tests__/TicketAdvance.spec.js
index ab1a47544..cfe5f86c5 100644
--- a/src/pages/Ticket/__tests__/TicketAdvance.spec.js
+++ b/src/pages/Ticket/__tests__/TicketAdvance.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, afterEach, beforeEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import TicketAdvance from 'pages/Ticket/TicketAdvance.vue';
 import { Notify } from 'quasar';
 import { nextTick } from 'vue';
diff --git a/src/pages/Ticket/locale/en.yml b/src/pages/Ticket/locale/en.yml
index cdbb22d9b..2e44df7aa 100644
--- a/src/pages/Ticket/locale/en.yml
+++ b/src/pages/Ticket/locale/en.yml
@@ -136,7 +136,6 @@ purchaseRequest:
 weeklyTickets:
     id: Ticket ID
     shipment: Shipment
-    salesperson: Salesperson
     search: Search weekly tickets
     searchInfo: Search weekly tickets by id or client id
 ticketSaleTracking:
@@ -172,7 +171,7 @@ tracking:
     addState: Add state
 package:
     package: Package
-    added: Added
+    added: D. Added
     addPackage: Add package
     removePackage: Remove package
 ticketList:
@@ -181,7 +180,6 @@ ticketList:
     state: State
     shipped: Shipped
     zone: Zone
-    salesPerson: Sales person
     totalWithVat: Total with VAT
     summary: Summary
     client: Customer
@@ -207,6 +205,7 @@ ticketList:
     toLines: Go to lines
     addressNickname: Address nickname
     ref: Reference
+    hour: Hour
     rounding: Rounding
     noVerifiedData: No verified data
     purchaseRequest: Purchase request
diff --git a/src/pages/Ticket/locale/es.yml b/src/pages/Ticket/locale/es.yml
index 75d3c6a2b..62013d9c5 100644
--- a/src/pages/Ticket/locale/es.yml
+++ b/src/pages/Ticket/locale/es.yml
@@ -58,7 +58,6 @@ basicData:
 weeklyTickets:
     id: ID Ticket
     shipment: Salida
-    salesperson: Comercial
     search: Buscar por tickets programados
     searchInfo: Buscar tickets programados por el identificador o el identificador del cliente
 advanceTickets:
@@ -162,7 +161,7 @@ expedition:
     removeExpedition: Eliminar expedición
 package:
     package: Embalaje
-    added: Añadido
+    added: F. Creacion
     addPackage: Añadir embalaje
     removePackage: Quitar embalaje
 ticketSaleTracking:
@@ -186,7 +185,6 @@ ticketList:
     state: Estado
     shipped: F. Envío
     zone: Zona
-    salesPerson: Comercial
     totalWithVat: Total con IVA
     summary: Resumen
     client: Cliente
diff --git a/src/pages/Travel/Card/TravelBasicData.vue b/src/pages/Travel/Card/TravelBasicData.vue
index b1adc8126..a6ef8ad19 100644
--- a/src/pages/Travel/Card/TravelBasicData.vue
+++ b/src/pages/Travel/Card/TravelBasicData.vue
@@ -36,7 +36,7 @@ const warehousesOptionsIn = ref([]);
         auto-load
         :filter="{ where: { isDestiny: TRUE } }"
     />
-    <FormModel :url-update="`Travels/${route.params.id}`" model="Travel" auto-load>
+    <FormModel :url-update="`Travels/${route.params.id}`" model="Travel">
         <template #form="{ data }">
             <VnRow>
                 <VnInput v-model="data.ref" :label="t('globals.reference')" />
@@ -57,8 +57,8 @@ const warehousesOptionsIn = ref([]);
             <VnRow>
                 <VnInputDate
                     v-model="data.availabled"
-                    :label="t('travel.summary.availabled')" 
-                    />
+                    :label="t('travel.summary.availabled')"
+                />
                 <VnInputTime
                     v-model="data.availabled"
                     :label="t('travel.summary.availabledHour')"
@@ -96,6 +96,7 @@ const warehousesOptionsIn = ref([]);
                         </QIcon>
                     </template>
                 </VnInput>
+                <VnInput v-model="data.awbFk" :label="t('travel.awbFk')" />
             </VnRow>
             <VnRow>
                 <QCheckbox v-model="data.isRaid" :label="t('travel.basicData.isRaid')" />
diff --git a/src/pages/Travel/Card/TravelCard.vue b/src/pages/Travel/Card/TravelCard.vue
index cb09eafd6..d452f5287 100644
--- a/src/pages/Travel/Card/TravelCard.vue
+++ b/src/pages/Travel/Card/TravelCard.vue
@@ -1,13 +1,13 @@
 <script setup>
 import TravelDescriptor from './TravelDescriptor.vue';
-import VnCardBeta from 'src/components/common/VnCardBeta.vue';
+import VnCard from 'src/components/common/VnCard.vue';
 import filter from './TravelFilter.js';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Travel"
         url="Travels"
         :descriptor="TravelDescriptor"
-        :filter="filter"
+        :filter="{ ...filter, where: { id: $route.params.id } }"
     />
 </template>
diff --git a/src/pages/Travel/Card/TravelDescriptor.vue b/src/pages/Travel/Card/TravelDescriptor.vue
index 922f89f33..d57046bae 100644
--- a/src/pages/Travel/Card/TravelDescriptor.vue
+++ b/src/pages/Travel/Card/TravelDescriptor.vue
@@ -3,7 +3,7 @@ import { computed, ref } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import useCardDescription from 'src/composables/useCardDescription';
 import TravelDescriptorMenuItems from './TravelDescriptorMenuItems.vue';
@@ -31,7 +31,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
 </script>
 
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         :url="`Travels/${entityId}`"
         :title="data.title"
         :subtitle="data.subtitle"
@@ -66,7 +66,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
                     :to="{
                         name: 'TravelList',
                         query: {
-                            params: JSON.stringify({
+                            table: JSON.stringify({
                                 agencyModeFk: entity.agencyModeFk,
                             }),
                         },
@@ -79,7 +79,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 
 <i18n>
diff --git a/src/pages/Travel/Card/TravelDescriptorMenuItems.vue b/src/pages/Travel/Card/TravelDescriptorMenuItems.vue
index 14d824b86..f8828bffe 100644
--- a/src/pages/Travel/Card/TravelDescriptorMenuItems.vue
+++ b/src/pages/Travel/Card/TravelDescriptorMenuItems.vue
@@ -37,7 +37,7 @@ const cloneTravelWithEntries = async () => {
     router.push({ name: 'TravelBasicData', params: { id: data.id } });
 };
 
-const canDelete = computed(() => useAcl().hasAny('Travel', '*', 'WRITE'));
+const canDelete = computed(() => useAcl().hasAcl('Travel', '*', 'WRITE'));
 
 const openDeleteEntryDialog = (id) => {
     quasar
diff --git a/src/pages/Travel/Card/TravelFilter.js b/src/pages/Travel/Card/TravelFilter.js
index 05436834f..0799e449c 100644
--- a/src/pages/Travel/Card/TravelFilter.js
+++ b/src/pages/Travel/Card/TravelFilter.js
@@ -12,6 +12,7 @@ export default {
         'isRaid',
         'daysInForward',
         'availabled',
+        'awbFk',
     ],
     include: [
         {
diff --git a/src/pages/Travel/Card/TravelSummary.vue b/src/pages/Travel/Card/TravelSummary.vue
index 9f9552611..22e2cff86 100644
--- a/src/pages/Travel/Card/TravelSummary.vue
+++ b/src/pages/Travel/Card/TravelSummary.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 
@@ -7,8 +7,6 @@ import CardSummary from 'components/ui/CardSummary.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import VnTitle from 'src/components/common/VnTitle.vue';
 import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
-import FetchData from 'src/components/FetchData.vue';
-import VnRow from 'components/ui/VnRow.vue';
 import { toDate, toCurrency, toCelsius } from 'src/filters';
 import { toDateTimeFormat } from 'src/filters/date.js';
 import { dashIfEmpty } from 'src/filters';
@@ -91,6 +89,13 @@ const entriesTableColumns = computed(() => {
             showValue: true,
         },
         { label: 'CC', field: 'cc', name: 'cc', align: 'left', showValue: true },
+        {
+            label: t('travel.summary.roundedCc'),
+            field: 'cc',
+            name: 'roundedCc',
+            align: 'left',
+            showValue: true,
+        },
         {
             label: 'Pallet',
             field: 'pallet',
@@ -193,13 +198,18 @@ const entriesTotals = computed(() => {
         freightValue: 0,
         packageValue: 0,
         cc: 0,
+        roundedCc: 0,
         pallet: 0,
         m3: 0,
     };
 
     entriesTableRows.value.forEach((row) => {
         for (const key in totals) {
-            totals[key] += row[key] || 0;
+            if (key === 'roundedCc') {
+                totals['roundedCc'] += Math.ceil(row['cc'] || 0);
+            } else {
+                totals[key] += row[key] || 0;
+            }
         }
     });
 
@@ -208,6 +218,7 @@ const entriesTotals = computed(() => {
         freight: toCurrency(totals.freightValue),
         packageValue: toCurrency(totals.packageValue),
         cc: totals.cc.toFixed(2),
+        roundedCc: totals.roundedCc,
         pallet: totals.pallet.toFixed(2),
         m3: totals.m3.toFixed(2),
     };
@@ -252,16 +263,16 @@ async function setTravelData(travelData) {
 }
 
 const getLink = (param) => `#/travel/${entityId.value}/${param}`;
+
+onMounted(async () => {
+    const { data } = await axios.get('Warehouses', {
+        params: { fields: ['id', 'name'] },
+    });
+    warehouses.value = data;
+});
 </script>
 
 <template>
-    <FetchData
-        url="Warehouses"
-        :filter="{ fields: ['id', 'name'] }"
-        order="name"
-        @on-fetch="(data) => (warehouses = data)"
-        auto-load
-    />
     <CardSummary
         ref="summaryRef"
         :url="`Travels/${entityId}/getTravel`"
@@ -275,72 +286,68 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
             <TravelDescriptorMenuItems :travel="entity" />
         </template>
         <template #body>
-            <QCard class="vn-one">
-                <QCardSection class="q-pa-none">
-                    <VnTitle
-                        :url="getLink('basic-data')"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                </QCardSection>
-                <VnLv :label="t('globals.shipped')" :value="toDate(travel.shipped)" />
-                <VnLv
-                    :label="t('globals.warehouseOut')"
-                    :value="travel.warehouseOut?.name"
-                />
-                <VnRow>
-                    <QCheckbox
-                        :label="t('travel.basicData.isRaid')"
-                        v-model="travel.isRaid"
-                        :disable="true"
-                    />
-                </VnRow>
-                <VnRow>
-                    <QCheckbox
-                        :label="t('travel.summary.delivered')"
-                        v-model="travel.isDelivered"
-                        :disable="true"
-                    />
-                </VnRow>
-            </QCard>
-            <QCard class="vn-one">
-                <QCardSection class="q-pa-none">
-                    <VnTitle
-                        :url="getLink('basic-data')"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                </QCardSection>
-                <VnLv :label="t('globals.landed')" :value="toDate(travel.landed)" />
-                <VnLv
-                    :label="t('globals.warehouseIn')"
-                    :value="travel.warehouseIn?.name"
-                />
-                <VnLv
-                    :label="t('travel.basicData.daysInForward')"
-                    :value="travel?.daysInForward"
-                />
-                <QCheckbox
-                    :label="t('travel.summary.received')"
-                    v-model="travel.isReceived"
-                    :disable="true"
-                />
-            </QCard>
-            <QCard class="vn-one">
-                <QCardSection class="q-pa-none">
-                    <VnTitle
-                        :url="getLink('basic-data')"
-                        :text="t('globals.pageTitles.basicData')"
-                    />
-                </QCardSection>
-                <VnLv :label="t('globals.agency')" :value="travel.agency?.name" />
-                <VnLv :label="t('globals.reference')" :value="travel.ref" />
-                <VnLv label="m³" :value="travel.m3" />
-                <VnLv :label="t('globals.totalEntries')" :value="travel.totalEntries" />
-                <VnLv
-                    :label="t('travel.summary.availabled')"
-                    :value="
-                        dashIfEmpty(toDateTimeFormat(travel.availabled))
-                    "
+            <QCard class="full-width">
+                <VnTitle
+                    :url="getLink('basic-data')"
+                    :text="t('globals.pageTitles.basicData')"
                 />
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('globals.shipped')"
+                            :value="toDate(travel.shipped)"
+                        />
+                        <VnLv
+                            :label="t('globals.warehouseOut')"
+                            :value="travel.warehouseOut?.name"
+                        />
+                        <QCheckbox
+                            :label="t('travel.basicData.isRaid')"
+                            v-model="travel.isRaid"
+                            :disable="true"
+                            size="sm"
+                        />
+                        <QCheckbox
+                            :label="t('travel.summary.delivered')"
+                            v-model="travel.isDelivered"
+                            :disable="true"
+                            size="sm"
+                        />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('globals.landed')"
+                            :value="toDate(travel.landed)"
+                        />
+                        <VnLv
+                            :label="t('globals.warehouseIn')"
+                            :value="travel.warehouseIn?.name"
+                        />
+                        <VnLv
+                            :label="t('travel.basicData.daysInForward')"
+                            :value="travel?.daysInForward"
+                        />
+                        <QCheckbox
+                            :label="t('travel.summary.received')"
+                            v-model="travel.isReceived"
+                            :disable="true"
+                            size="sm"
+                        />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv :label="t('globals.agency')" :value="travel.agency?.name" />
+                        <VnLv :label="t('globals.reference')" :value="travel.ref" />
+                        <VnLv label="m³" :value="travel.m3" />
+                        <VnLv
+                            :label="t('globals.totalEntries')"
+                            :value="travel.totalEntries"
+                        />
+                        <VnLv
+                            :label="t('travel.summary.availabled')"
+                            :value="dashIfEmpty(toDateTimeFormat(travel.availabled))"
+                        />
+                    </div>
+                </div>
             </QCard>
             <QCard class="full-width">
                 <VnTitle :text="t('travel.summary.entries')" />
@@ -376,6 +383,11 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
                             </QBtn>
                         </QTd>
                     </template>
+                    <template #body-cell-roundedCc="{ col, value }">
+                        <QTd>
+                            {{ Math.ceil(value) || 0 }}
+                        </QTd>
+                    </template>
                     <template #body-cell-observation="{ value }">
                         <QTd>
                             <QIcon name="insert_drive_file" color="primary" size="24px">
@@ -392,23 +404,24 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
                         <QTd class="text-bold">{{ entriesTotals.freight }}</QTd>
                         <QTd class="text-bold">{{ entriesTotals.packageValue }}</QTd>
                         <QTd class="text-bold">{{ entriesTotals.cc }}</QTd>
+                        <QTd class="text-bold">{{ entriesTotals.roundedCc }}</QTd>
                         <QTd class="text-bold">{{ entriesTotals.pallet }}</QTd>
                         <QTd class="text-bold">{{ entriesTotals.m3 }}</QTd>
                     </template>
                 </QTable>
             </QCard>
-
             <QCard class="full-width" v-if="thermographs.length > 0">
-                <RouterLink
-                    class="header header-link"
-                    :to="{
-                        name: 'TravelThermographsIndex',
-                        params: { id: travel.id },
-                    }"
-                >
-                    {{ t('travel.summary.thermographs') }}
-                    <QIcon name="open_in_new" />
-                </RouterLink>
+                <FetchData
+                    url="Warehouses"
+                    :filter="{ fields: ['id', 'name'] }"
+                    order="name"
+                    @on-fetch="(data) => (warehouses = data)"
+                    auto-load
+                />
+                <VnTitle
+                    :url="getLink('thermographs')"
+                    :text="t('travel.summary.thermographs')"
+                />
                 <QTable
                     :rows="thermographs"
                     :columns="thermographsTableColumns"
diff --git a/src/pages/Travel/ExtraCommunity.vue b/src/pages/Travel/ExtraCommunity.vue
index ac46caa44..849eeee5b 100644
--- a/src/pages/Travel/ExtraCommunity.vue
+++ b/src/pages/Travel/ExtraCommunity.vue
@@ -18,7 +18,6 @@ import { usePrintService } from 'composables/usePrintService';
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import axios from 'axios';
 import RightMenu from 'src/components/common/RightMenu.vue';
-import VnPopup from 'src/components/common/VnPopup.vue';
 
 const stateStore = useStateStore();
 const { t } = useI18n();
@@ -141,7 +140,6 @@ const columns = computed(() => [
         label: 'id',
         field: 'id',
         name: 'id',
-        align: 'center',
         showValue: true,
         sortable: true,
     },
@@ -165,7 +163,7 @@ const columns = computed(() => [
         label: t('globals.amount'),
         name: 'invoiceAmount',
         field: 'entries',
-        align: 'left',
+        align: 'right',
         showValue: true,
         sortable: true,
         format: (value) =>
@@ -184,13 +182,12 @@ const columns = computed(() => [
         align: 'left',
         showValue: false,
         sortable: true,
-        style: 'min-width: 170px;',
     },
     {
         label: t('globals.packages'),
         field: 'stickers',
         name: 'stickers',
-        align: 'left',
+        align: 'right',
         showValue: true,
         sortable: true,
     },
@@ -198,7 +195,7 @@ const columns = computed(() => [
         label: '%',
         field: '',
         name: 'percentage',
-        align: 'center',
+        align: 'right',
         showValue: false,
         sortable: true,
     },
@@ -214,7 +211,7 @@ const columns = computed(() => [
         label: t('extraCommunity.physicKg'),
         field: 'loadedKg',
         name: 'loadedKg',
-        align: 'left',
+        align: 'right',
         showValue: true,
         sortable: true,
     },
@@ -222,7 +219,7 @@ const columns = computed(() => [
         label: 'KG Vol.',
         field: 'volumeKg',
         name: 'volumeKg',
-        align: 'left',
+        align: 'right',
         showValue: true,
         sortable: true,
     },
@@ -277,7 +274,6 @@ async function getData() {
 const onStoreDataChange = () => {
     const newData = JSON.parse(JSON.stringify(arrayData.store.data)) || [];
     rows.value = newData;
-    // el objetivo de esto es guardar una copia de los valores iniciales de todas las rows para corroborar si la data cambio antes de guardar los cambios
     originalRowDataCopy.value = JSON.parse(JSON.stringify(newData));
 };
 
@@ -300,20 +296,17 @@ const openReportPdf = () => {
 };
 
 const saveFieldValue = async (val, field, index) => {
-    // Evitar la solicitud de guardado si el valor no ha cambiado
     if (originalRowDataCopy.value[index][field] == val) return;
 
     const id = rows.value[index].id;
     const params = { [field]: val };
     await axios.patch(`Travels/${id}`, params);
-    // Actualizar la copia de los datos originales con el nuevo valor
     originalRowDataCopy.value[index][field] = val;
 
     await arrayData.fetch({ append: false });
 };
 
 const stopEventPropagation = (event, col) => {
-    // Detener la propagación del evento de los siguientes elementos para evitar el click sobre la row que dispararía  la función navigateToTravelId
     if (!['ref', 'id', 'cargoSupplierNickname', 'kg'].includes(col.name)) return;
     event.preventDefault();
     event.stopPropagation();
@@ -335,14 +328,12 @@ onMounted(async () => {
     await getData();
 });
 
-// Handler del evento @dragstart (inicio del drag) y guarda información inicial
 const handleDragStart = (event, rowIndex, entryIndex) => {
     draggedRowIndex.value = rowIndex;
     entryRowIndex.value = entryIndex;
     event.dataTransfer.effectAllowed = 'move';
 };
 
-// Handler del evento @dragenter (cuando haces drag sobre une elemento y lo arrastras sobre un posible target de drop) y actualiza el targetIndex
 const handleDragEnter = (_, targetIndex) => {
     targetRowIndex.value = targetIndex;
 };
@@ -356,11 +347,8 @@ const saveRowDrop = async (targetRowIndex) => {
 const moveRow = async (draggedRowIndex, targetRowIndex, entryIndex) => {
     try {
         if (draggedRowIndex === targetRowIndex) return;
-        // Remover entry de la row original
         draggedEntry.value = rows.value[draggedRowIndex].entries.splice(entryIndex, 1)[0];
-        //Si la row de destino por alguna razón no tiene la propiedad entry la creamos
         if (!rows.value[targetRowIndex].entries) rows.value[targetRowIndex].entries = [];
-        // Añadir entry a la row de destino
         rows.value[targetRowIndex].entries.push(draggedEntry.value);
 
         await saveRowDrop(targetRowIndex);
@@ -370,13 +358,11 @@ const moveRow = async (draggedRowIndex, targetRowIndex, entryIndex) => {
     }
 };
 
-// Handler de cuando haces un drop tanto dentro como fuera de la tabla para limpiar acciones y data
 const handleDragEnd = () => {
     stopScroll();
     cleanDragAndDropData();
 };
 
-// Handler del evento @drop (cuando soltas el elemento draggeado sobre un target)
 const handleDrop = () => {
     if (
         !draggedRowIndex.value &&
@@ -399,7 +385,6 @@ const cleanDragAndDropData = () => {
 const scrollInterval = ref(null);
 
 const startScroll = (direction) => {
-    // Iniciar el scroll en la dirección especificada
     if (!scrollInterval.value) {
         scrollInterval.value = requestAnimationFrame(() => scroll(direction));
     }
@@ -413,14 +398,12 @@ const stopScroll = () => {
 };
 
 const scroll = (direction) => {
-    // Controlar el desplazamiento en la dirección especificada
     const yOffset = direction === 'up' ? -2 : 2;
     window.scrollBy(0, yOffset);
 
     const windowHeight = window.innerHeight;
     const documentHeight = document.body.offsetHeight;
 
-    // Verificar si se alcanzaron los límites de la ventana para detener el desplazamiento
     if (
         (direction === 'up' && window.scrollY > 0) ||
         (direction === 'down' && windowHeight + window.scrollY < documentHeight)
@@ -431,13 +414,10 @@ const scroll = (direction) => {
     }
 };
 
-// Handler del scroll mientras se hace el drag de una row
 const handleDragScroll = (event) => {
-    // Obtener la posición y dimensiones del cursor
     const y = event.clientY;
     const windowHeight = window.innerHeight;
 
-    // Verificar si el cursor está cerca del borde superior o inferior de la ventana
     const nearTop = y < 150;
     const nearBottom = y > windowHeight - 100;
 
@@ -547,7 +527,7 @@ watch(route, () => {
                                         ? `${props.row.percentageKg}%`
                                         : '-'
                                 "
-                                class="text-left q-py-xs q-px-sm"
+                                class="text-right q-py-xs q-px-sm"
                                 :color="getColor(props.row.percentageKg)"
                             />
                             <span
@@ -566,7 +546,6 @@ watch(route, () => {
                                 ]"
                                 v-text="col.value"
                             />
-                            <!-- Main Row Descriptors -->
                             <TravelDescriptorProxy
                                 v-if="col.name === 'id'"
                                 :id="props.row.id"
@@ -597,58 +576,46 @@ watch(route, () => {
                             index === props.row.entries.length - 1,
                     }"
                 >
-                    <QTd>
+                    <QTd class="text-right">
                         <QBtn dense flat class="link">{{ entry.id }} </QBtn>
                         <EntryDescriptorProxy :id="entry.id" />
                     </QTd>
-                    <QTd>
-                        <QBtn flat class="link" dense>{{ entry.supplierName }}</QBtn>
-                        <SupplierDescriptorProxy :id="entry.supplierFk" />
+                    <QTd :colspan="2">
+                        <div style="display: flex">
+                            <span class="link">
+                                {{ entry.supplierName }}
+                                <SupplierDescriptorProxy :id="entry.supplierFk" />
+                            </span>
+                            <QIcon
+                                v-if="entry.isCustomInspectionRequired"
+                                name="warning"
+                                color="negative"
+                                size="md"
+                                :title="t('extraCommunity.requiresInspection')"
+                            />
+                        </div>
                     </QTd>
-                    <QTd>
-                        <QIcon
-                            v-if="entry.isCustomInspectionRequired"
-                            name="warning"
-                            color="negative"
-                            size="md"
-                            :title="t('extraCommunity.requiresInspection')"
-                        >
-                        </QIcon>
-                    </QTd>
-                    <QTd>
+                    <QTd class="text-right">
                         <span>{{ toCurrency(entry.invoiceAmount) }}</span>
                     </QTd>
                     <QTd>
                         <span>{{ entry.reference }}</span>
                     </QTd>
-                    <QTd>
+                    <QTd class="text-right">
                         <span>{{ entry.stickers }}</span>
                     </QTd>
                     <QTd />
                     <QTd></QTd>
-                    <QTd>
+                    <QTd class="text-right">
                         <span>{{ entry.loadedkg }}</span>
                     </QTd>
-                    <QTd>
+                    <QTd class="text-right">
                         <span>{{ entry.volumeKg }}</span>
                     </QTd>
-                    <QTd />
-                    <QTd />
-                    <QTd />
-                    <QTd />
-                    <QTd>
-                        <QBtn
-                            v-if="entry.evaNotes"
-                            icon="comment"
-                            size="md"
-                            flat
-                            color="primary"
-                        >
-                            <VnPopup
-                                :title="t('globals.observations')"
-                                :content="entry.evaNotes"
-                            />
-                        </QBtn>
+                    <QTd :colspan="5" class="text-right">
+                        <span>
+                            {{ entry.evaNotes }}
+                        </span>
                     </QTd>
                 </QTr>
             </template>
@@ -662,18 +629,21 @@ watch(route, () => {
 }
 
 :deep(.q-table) {
+    table-layout: auto;
+    width: 100%;
     border-collapse: collapse;
+    overflow: hidden;
+    text-overflow: ellipsis;
 
-    th {
-        padding: 0;
-    }
     tbody tr td {
         &:nth-child(1) {
             max-width: 65px;
         }
-        &:nth-child(4) {
-            padding: 0;
-        }
+        padding: 0 5px 0;
+    }
+    thead > tr > th {
+        padding: 3px;
+        color: var(--vn-label-color);
     }
 }
 
diff --git a/src/pages/Travel/ExtraCommunityFilter.vue b/src/pages/Travel/ExtraCommunityFilter.vue
index ae6e695be..76ffdba20 100644
--- a/src/pages/Travel/ExtraCommunityFilter.vue
+++ b/src/pages/Travel/ExtraCommunityFilter.vue
@@ -87,7 +87,7 @@ warehouses();
         <template #body="{ params, searchFn }">
             <QItem>
                 <QItemSection>
-                    <VnInput label="id" v-model="params.id" is-outlined />
+                    <VnInput label="id" v-model="params.id" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -95,7 +95,7 @@ warehouses();
                     <VnInput
                         :label="t('extraCommunity.filter.reference')"
                         v-model="params.reference"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -106,8 +106,7 @@ warehouses();
                         type="number"
                         :label="t('extraCommunity.filter.totalEntries')"
                         dense
-                        outlined
-                        rounded
+                        filled
                         min="0"
                         class="input-number"
                     >
@@ -141,8 +140,7 @@ warehouses();
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -152,7 +150,7 @@ warehouses();
                         :label="t('extraCommunity.filter.shippedFrom')"
                         v-model="params.shippedFrom"
                         @update:model-value="searchFn()"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -162,7 +160,7 @@ warehouses();
                         :label="t('extraCommunity.filter.landedTo')"
                         v-model="params.landedTo"
                         @update:model-value="searchFn()"
-                        is-outlined
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -176,8 +174,7 @@ warehouses();
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -191,8 +188,7 @@ warehouses();
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -206,8 +202,7 @@ warehouses();
                         option-label="name"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -218,8 +213,7 @@ warehouses();
                         v-model="params.cargoSupplierFk"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -229,8 +223,7 @@ warehouses();
                         v-model="params.entrySupplierFk"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
@@ -245,8 +238,7 @@ warehouses();
                         :filter-options="['code', 'name']"
                         hide-selected
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
diff --git a/src/pages/Travel/TravelFilter.vue b/src/pages/Travel/TravelFilter.vue
index 4a9c80952..5498fd269 100644
--- a/src/pages/Travel/TravelFilter.vue
+++ b/src/pages/Travel/TravelFilter.vue
@@ -33,19 +33,14 @@ defineExpose({ states });
         </template>
         <template #body="{ params, searchFn }">
             <div class="q-pa-sm q-gutter-y-sm">
-                <VnInput
-                    :label="t('travel.Id')"
-                    v-model="params.id"
-                    lazy-rules
-                    is-outlined
-                >
+                <VnInput :label="t('travel.Id')" v-model="params.id" lazy-rules filled>
                     <template #prepend> <QIcon name="badge" size="xs" /></template>
                 </VnInput>
                 <VnInput
                     :label="t('travel.ref')"
                     v-model="params.ref"
                     lazy-rules
-                    is-outlined
+                    filled
                 />
                 <VnSelect
                     :label="t('travel.agency')"
@@ -56,8 +51,7 @@ defineExpose({ states });
                     :use-like="false"
                     option-filter="name"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnSelect
                     :label="t('travel.warehouseInFk')"
@@ -69,27 +63,24 @@ defineExpose({ states });
                     option-label="name"
                     option-filter="name"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnInputDate
                     :label="t('travel.shipped')"
                     v-model="params.shipped"
                     @update:model-value="searchFn()"
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnInputTime
                     v-model="params.shipmentHour"
                     @update:model-value="searchFn()"
                     :label="t('travel.shipmentHour')"
-                    outlined
-                    rounded
+                    filled
                     dense
                 />
                 <VnSelect
                     :label="t('travel.warehouseOut')"
-                    v-model="params.warehouseOut"
+                    v-model="params.warehouseOutFk"
                     @update:model-value="searchFn()"
                     url="warehouses"
                     :use-like="false"
@@ -97,36 +88,33 @@ defineExpose({ states });
                     option-label="name"
                     option-filter="name"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnInputDate
                     :label="t('travel.landed')"
                     v-model="params.landed"
                     @update:model-value="searchFn()"
                     dense
-                    outlined
-                    rounded
+                    filled
                 />
                 <VnInputTime
                     v-model="params.landingHour"
                     @update:model-value="searchFn()"
                     :label="t('travel.landingHour')"
-                    outlined
-                    rounded
+                    filled
                     dense
                 />
                 <VnInput
                     :label="t('travel.totalEntries')"
                     v-model="params.totalEntries"
                     lazy-rules
-                    is-outlined
+                    filled
                 />
                 <VnInput
                     :label="t('travel.daysOnward')"
                     v-model="params.daysOnward"
                     lazy-rules
-                    is-outlined
+                    filled
                 />
             </div>
         </template>
@@ -140,6 +128,7 @@ en:
         ref: Reference
         agency: Agency
         warehouseInFk: Warehouse In
+        warehouseOutFk: Warehouse Out
         shipped: Shipped
         shipmentHour: Shipment Hour
         warehouseOut: Warehouse Out
@@ -153,6 +142,7 @@ es:
         ref: Referencia
         agency: Agencia
         warehouseInFk: Alm.Entrada
+        warehouseOutFk: Alm.Salida
         shipped: F.Envío
         shipmentHour: Hora de envío
         warehouseOut: Alm.Salida
diff --git a/src/pages/Travel/TravelList.vue b/src/pages/Travel/TravelList.vue
index b227afcb2..32ddc639a 100644
--- a/src/pages/Travel/TravelList.vue
+++ b/src/pages/Travel/TravelList.vue
@@ -201,7 +201,7 @@ const columns = computed(() => [
             {
                 title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
-                action: (row) => viewSummary(row.id, TravelSummary),
+                action: (row) => viewSummary(row.id, TravelSummary, 'lg-width'),
                 isPrimary: true,
             },
         ],
diff --git a/src/pages/Wagon/Card/WagonCard.vue b/src/pages/Wagon/Card/WagonCard.vue
index 644a30ffa..19f0a682a 100644
--- a/src/pages/Wagon/Card/WagonCard.vue
+++ b/src/pages/Wagon/Card/WagonCard.vue
@@ -1,6 +1,6 @@
 <script setup>
-import VnCard from 'components/common/VnCard.vue';
+import VnCard from 'src/components/common/VnCard.vue';
 </script>
 <template>
-    <VnCard data-key="Wagon" url="Wagons" />
+    <VnCard data-key="Wagon" url="Wagons" :descriptor="{}" />
 </template>
diff --git a/src/pages/Wagon/WagonList.vue b/src/pages/Wagon/WagonList.vue
index ccfdb89d0..16c5fca63 100644
--- a/src/pages/Wagon/WagonList.vue
+++ b/src/pages/Wagon/WagonList.vue
@@ -8,6 +8,7 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
 import { computed, ref } from 'vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnInput from 'src/components/common/VnInput.vue';
+import VnSection from 'src/components/common/VnSection.vue';
 
 const quasar = useQuasar();
 const arrayData = useArrayData('WagonList');
@@ -15,6 +16,7 @@ const store = arrayData.store;
 const router = useRouter();
 const { t } = useI18n();
 const tableRef = ref();
+const dataKey = 'WagonList';
 const filter = {
     include: {
         relation: 'type',
@@ -75,95 +77,106 @@ function navigate(id) {
 }
 
 async function remove(row) {
-    try {
-        await axios.delete(`Wagons/${row.id}`).then(async () => {
-            quasar.notify({
-                message: t('wagon.list.removeItem'),
-                type: 'positive',
-            });
-            store.data.splice(store.data.indexOf(row), 1);
-            window.location.reload();
+    await axios.delete(`Wagons/${row.id}`).then(async () => {
+        quasar.notify({
+            message: t('wagon.list.removeItem'),
+            type: 'positive',
         });
-    } catch (error) {
-        //
-    }
+        store.data.splice(store.data.indexOf(row), 1);
+        window.location.reload();
+    });
 }
 </script>
-
 <template>
     <QPage class="column items-center q-pa-md">
-        <VnTable
-            ref="tableRef"
-            data-key="WagonList"
-            url="Wagons"
-            :filter="filter"
+        <VnSection
+            :data-key="dataKey"
             :columns="columns"
-            order="id DESC"
-            :column-search="false"
-            :default-mode="'card'"
-            :disable-option="{ table: true }"
-            :create="{
-                urlCreate: 'Wagons',
-                title: t('Create new wagon'),
-                onDataSaved: () => tableRef.reload(),
-                formInitialData: {},
+            prefix="card"
+            :array-data-props="{
+                url: 'Wagons',
+                exprBuilder,
+                order: 'id DESC',
             }"
         >
-            <template #more-create-dialog="{ data }">
-                <VnInput
-                    filled
-                    v-model="data.label"
-                    :label="t('wagon.create.label')"
-                    type="number"
-                    min="0"
-                    :rules="[(val) => !!val || t('wagon.warnings.labelNotEmpty')]"
-                />
-                <VnInput
-                    filled
-                    v-model="data.plate"
-                    :label="t('wagon.list.plate')"
-                    :rules="[(val) => !!val || t('wagon.warnings.plateNotEmpty')]"
-                />
-                <VnInput
-                    filled
-                    v-model="data.volume"
-                    :label="t('wagon.list.volume')"
-                    type="number"
-                    min="0"
-                    :rules="[(val) => !!val || t('wagon.warnings.volumeNotEmpty')]"
-                />
-                <VnSelect
-                    url="WagonTypes"
-                    filled
-                    v-model="data.typeFk"
-                    use-input
-                    fill-input
-                    hide-selected
-                    input-debounce="0"
-                    option-label="name"
-                    option-value="id"
-                    emit-value
-                    map-options
-                    :label="t('globals.type')"
-                    :rules="[(val) => !!val || t('wagon.warnings.typeNotEmpty')]"
+            <template #body>
+                <VnTable
+                    ref="tableRef"
+                    :data-key="dataKey"
+                    :create="{
+                        urlCreate: 'Wagons',
+                        title: t('Create new wagon'),
+                        onDataSaved: () => tableRef.reload(),
+                        formInitialData: {},
+                    }"
+                    :filter="filter"
+                    :columns="columns"
+                    :column-search="false"
+                    :default-mode="'card'"
+                    :disable-option="{ table: true }"
+                    :right-search="false"
                 >
-                    <template v-if="data.typeFk" #append>
-                        <QIcon
-                            name="cancel"
-                            @click.stop.prevent="data.typeFk = null"
-                            class="cursor-pointer"
+                    <template #more-create-dialog="{ data }">
+                        <VnInput
+                            filled
+                            v-model="data.label"
+                            :label="t('wagon.create.label')"
+                            type="number"
+                            min="0"
+                            :rules="[(val) => !!val || t('wagon.warnings.labelNotEmpty')]"
                         />
+                        <VnInput
+                            filled
+                            v-model="data.plate"
+                            :label="t('wagon.list.plate')"
+                            :rules="[(val) => !!val || t('wagon.warnings.plateNotEmpty')]"
+                        />
+                        <VnInput
+                            filled
+                            v-model="data.volume"
+                            :label="t('wagon.list.volume')"
+                            type="number"
+                            min="0"
+                            :rules="[
+                                (val) => !!val || t('wagon.warnings.volumeNotEmpty'),
+                            ]"
+                        />
+                        <VnSelect
+                            url="WagonTypes"
+                            filled
+                            v-model="data.typeFk"
+                            use-input
+                            fill-input
+                            hide-selected
+                            input-debounce="0"
+                            option-label="name"
+                            option-value="id"
+                            emit-value
+                            map-options
+                            :label="t('globals.type')"
+                            :options="filteredWagonTypes"
+                            :rules="[(val) => !!val || t('wagon.warnings.typeNotEmpty')]"
+                            @filter="filterType"
+                        >
+                            <template v-if="data.typeFk" #append>
+                                <QIcon
+                                    name="cancel"
+                                    @click.stop.prevent="data.typeFk = null"
+                                    class="cursor-pointer"
+                                />
+                            </template>
+                            <template #no-option>
+                                <QItem>
+                                    <QItemSection class="text-grey">
+                                        {{ t('wagon.warnings.noData') }}
+                                    </QItemSection>
+                                </QItem>
+                            </template>
+                        </VnSelect>
                     </template>
-                    <template #no-option>
-                        <QItem>
-                            <QItemSection class="text-grey">
-                                {{ t('wagon.warnings.noData') }}
-                            </QItemSection>
-                        </QItem>
-                    </template>
-                </VnSelect>
+                </VnTable>
             </template>
-        </VnTable>
+        </VnSection>
     </QPage>
 </template>
 
diff --git a/src/pages/Wagon/__tests__/WagonCreate.spec.js b/src/pages/Wagon/__tests__/WagonCreate.spec.js
index f195c183f..9be19e027 100644
--- a/src/pages/Wagon/__tests__/WagonCreate.spec.js
+++ b/src/pages/Wagon/__tests__/WagonCreate.spec.js
@@ -1,5 +1,6 @@
 import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import axios from 'axios';
+import { createWrapper } from 'app/test/vitest/helper';
 import WagonCreate from 'pages/Wagon/WagonCreate.vue';
 
 describe('WagonCreate', () => {
diff --git a/src/pages/Worker/Card/WorkerBasicData.vue b/src/pages/Worker/Card/WorkerBasicData.vue
index a78983e5c..f2a16b7e1 100644
--- a/src/pages/Worker/Card/WorkerBasicData.vue
+++ b/src/pages/Worker/Card/WorkerBasicData.vue
@@ -1,5 +1,6 @@
 <script setup>
-import { ref, nextTick } from 'vue';
+import { ref, nextTick, onMounted } from 'vue';
+import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import VnInputDate from 'src/components/common/VnInputDate.vue';
 import FetchData from 'components/FetchData.vue';
@@ -17,12 +18,12 @@ const maritalStatus = [
     { code: 'M', name: t('Married') },
     { code: 'S', name: t('Single') },
 ];
-async function setAdvancedSummary(data) {
-    const advanced = (await useAdvancedSummary('Workers', data.id)) ?? {};
+
+onMounted(async () => {
+    const advanced = await useAdvancedSummary('Workers', useRoute().params.id);
     Object.assign(form.value.formData, advanced);
-    await nextTick();
-    if (form.value) form.value.hasChanges = false;
-}
+    nextTick(() => (form.value.hasChanges = false));
+});
 </script>
 <template>
     <FetchData
@@ -42,7 +43,6 @@ async function setAdvancedSummary(data) {
         :url-update="`Workers/${$route.params.id}`"
         auto-load
         model="Worker"
-        @on-fetch="setAdvancedSummary"
     >
         <template #form="{ data }">
             <VnRow>
@@ -96,6 +96,7 @@ async function setAdvancedSummary(data) {
                     option-label="name"
                     option-value="code"
                     v-model="data.maritalStatus"
+                    data-cy="MaritalStatus"
                 />
             </VnRow>
 
@@ -107,6 +108,7 @@ async function setAdvancedSummary(data) {
                     option-label="name"
                     option-value="id"
                     v-model="data.originCountryFk"
+                    data-cy="country"
                 />
                 <VnSelect
                     :label="t('Education level')"
@@ -132,7 +134,7 @@ async function setAdvancedSummary(data) {
                 <VnInputDate :label="t('seniority')" v-model="data.seniority" />
             </VnRow>
             <VnRow>
-                <VnInput v-model="data.fi" :label="t('fi')" />
+                <VnInput v-model="data.fi" :label="t('fi')" data-cy="fi" />
                 <VnInputDate :label="t('birth')" v-model="data.birth" />
             </VnRow>
             <VnRow wrap>
diff --git a/src/pages/Worker/Card/WorkerCalendar.vue b/src/pages/Worker/Card/WorkerCalendar.vue
index df4616011..05ebb4687 100644
--- a/src/pages/Worker/Card/WorkerCalendar.vue
+++ b/src/pages/Worker/Card/WorkerCalendar.vue
@@ -18,9 +18,7 @@ const router = useRouter();
 const route = useRoute();
 const { t } = useI18n();
 const acl = useAcl();
-const canSeeNotes = computed(() =>
-    acl.hasAny([{ model: 'Worker', props: '__get__business', accessType: 'READ' }]),
-);
+const canSeeNotes = computed(() => acl.hasAcl('Worker', '__get__business', 'READ'));
 const workerIsFreelance = ref();
 const WorkerFreelanceRef = ref();
 const workerCalendarFilterRef = ref(null);
diff --git a/src/pages/Worker/Card/WorkerCalendarFilter.vue b/src/pages/Worker/Card/WorkerCalendarFilter.vue
index 48fc4094b..32edaa6e9 100644
--- a/src/pages/Worker/Card/WorkerCalendarFilter.vue
+++ b/src/pages/Worker/Card/WorkerCalendarFilter.vue
@@ -40,7 +40,7 @@ watch(
     (newValue) => {
         checkHolidays(newValue);
     },
-    { deep: true, immediate: true }
+    { deep: true, immediate: true },
 );
 const emit = defineEmits(['update:businessFk', 'update:year', 'update:absenceType']);
 
@@ -166,52 +166,44 @@ const yearList = ref(generateYears());
             }}
         </QCardSection>
     </div>
-    <QList dense class="list q-gutter-y-sm q-my-lg">
-        <QItem>
-            <QItemSection>
-                <VnSelect
-                    :label="t('Year')"
-                    v-model="selectedYear"
-                    :options="yearList"
-                    dense
-                    outlined
-                    rounded
-                    use-input
-                    :is-clearable="false"
-                />
-            </QItemSection>
-            <QItemSection>
-                <VnSelect
-                    :label="t('Contract')"
-                    v-model="selectedBusinessFk"
-                    :options="contractList"
-                    option-value="businessFk"
-                    option-label="businessFk"
-                    dense
-                    outlined
-                    rounded
-                    use-input
-                    :is-clearable="false"
-                >
-                    <template #option="scope">
-                        <QItem v-bind="scope.itemProps">
-                            <QItemSection>
-                                <QItemLabel># {{ scope.opt?.businessFk }}</QItemLabel>
-                                <QItemLabel caption>
-                                    {{ toDateFormat(scope.opt?.started) }} -
-                                    {{
-                                        scope.opt?.ended
-                                            ? toDateFormat(scope.opt?.ended)
-                                            : 'Indef.'
-                                    }}
-                                </QItemLabel>
-                            </QItemSection>
-                        </QItem>
-                    </template>
-                </VnSelect>
-            </QItemSection>
-        </QItem>
-    </QList>
+    <div dense class="column q-gutter-y-sm q-px-md">
+        <VnSelect
+            :label="t('Year')"
+            v-model="selectedYear"
+            :options="yearList"
+            dense
+            filled
+            use-input
+            :is-clearable="false"
+        />
+        <VnSelect
+            :label="t('Contract')"
+            v-model="selectedBusinessFk"
+            :options="contractList"
+            option-value="businessFk"
+            option-label="businessFk"
+            dense
+            filled
+            use-input
+            :is-clearable="false"
+        >
+            <template #option="scope">
+                <QItem v-bind="scope.itemProps">
+                    <QItemSection>
+                        <QItemLabel># {{ scope.opt?.businessFk }}</QItemLabel>
+                        <QItemLabel caption>
+                            {{ toDateFormat(scope.opt?.started) }} -
+                            {{
+                                scope.opt?.ended
+                                    ? toDateFormat(scope.opt?.ended)
+                                    : 'Indef.'
+                            }}
+                        </QItemLabel>
+                    </QItemSection>
+                </QItem>
+            </template>
+        </VnSelect>
+    </div>
     <QList dense class="list q-gutter-y-xs q-my-md">
         <QItem v-for="type in absenceTypeList" :key="type.id">
             <WorkerEventLabel
diff --git a/src/pages/Worker/Card/WorkerCard.vue b/src/pages/Worker/Card/WorkerCard.vue
index 3b7a62025..591dadcd2 100644
--- a/src/pages/Worker/Card/WorkerCard.vue
+++ b/src/pages/Worker/Card/WorkerCard.vue
@@ -1,9 +1,9 @@
 <script setup>
 import WorkerDescriptor from './WorkerDescriptor.vue';
-import VnCardBeta from 'src/components/common/VnCardBeta.vue';
+import VnCard from 'src/components/common/VnCard.vue';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         data-key="Worker"
         url="Workers/summary"
         :id-in-where="true"
diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue
index dc2c3f197..9576e7e84 100644
--- a/src/pages/Worker/Card/WorkerDescriptor.vue
+++ b/src/pages/Worker/Card/WorkerDescriptor.vue
@@ -2,7 +2,7 @@
 import { computed, ref } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'src/components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
 import VnChangePassword from 'src/components/common/VnChangePassword.vue';
@@ -52,9 +52,10 @@ const handlePhotoUpdated = (evt = false) => {
 };
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         ref="cardDescriptorRef"
         :data-key="dataKey"
+        :summary="$props.summary"
         url="Workers/summary"
         :filter="{ where: { id: entityId } }"
         title="user.nickname"
@@ -115,27 +116,25 @@ const handlePhotoUpdated = (evt = false) => {
         <template #body="{ entity }">
             <VnLv :label="t('globals.user')" :value="entity.user?.name" />
             <VnLv
-                class="ellipsis-text"
+                class="ellipsis"
                 :label="t('globals.params.email')"
                 :value="entity.user?.emailUser?.email"
                 copy
             />
-            <VnLv :label="t('worker.list.department')">
+            <VnLv :label="t('globals.department')">
                 <template #value>
                     <span class="link" v-text="entity.department?.department?.name" />
                     <DepartmentDescriptorProxy :id="entity.department?.department?.id" />
                 </template>
             </VnLv>
 
-            <VnLv :value="entity.phone">
-                <template #label>
-                    {{ t('globals.phone') }}
+            <VnLv :label="t('globals.phone')">
+                <template #value>
                     <VnLinkPhone :phone-number="entity.phone" />
                 </template>
             </VnLv>
-            <VnLv :value="entity?.sip?.extension">
-                <template #label>
-                    {{ t('worker.summary.sipExtension') }}
+            <VnLv :label="t('worker.summary.sipExtension')">
+                <template #value>
                     <VnLinkPhone :phone-number="entity?.sip?.extension" />
                 </template>
             </VnLv>
@@ -166,7 +165,7 @@ const handlePhotoUpdated = (evt = false) => {
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
     <VnChangePassword
         ref="changePassRef"
         :submit-fn="
@@ -189,9 +188,3 @@ const handlePhotoUpdated = (evt = false) => {
     white-space: nowrap;
 }
 </style>
-
-<i18n>
-es:
-    Click to allow the user to be disabled: Marcar para deshabilitar
-    Click to exclude the user from getting disabled: Marcar para no deshabilitar
-</i18n>
diff --git a/src/pages/Worker/Card/WorkerDescriptorMenu.vue b/src/pages/Worker/Card/WorkerDescriptorMenu.vue
index 0dcb4fd71..3b6b144d6 100644
--- a/src/pages/Worker/Card/WorkerDescriptorMenu.vue
+++ b/src/pages/Worker/Card/WorkerDescriptorMenu.vue
@@ -63,3 +63,8 @@ const showChangePasswordDialog = () => {
         </QItemSection>
     </QItem>
 </template>
+<i18n>
+    es:
+        Click to allow the user to be disabled: Marcar para deshabilitar
+        Click to exclude the user from getting disabled: Marcar para no deshabilitar
+    </i18n>
diff --git a/src/pages/Worker/Card/WorkerDescriptorProxy.vue b/src/pages/Worker/Card/WorkerDescriptorProxy.vue
index 5f71abbea..baa9aa571 100644
--- a/src/pages/Worker/Card/WorkerDescriptorProxy.vue
+++ b/src/pages/Worker/Card/WorkerDescriptorProxy.vue
@@ -11,7 +11,7 @@ const $props = defineProps({
 </script>
 
 <template>
-    <QPopupProxy>
+    <QPopupProxy data-cy="WorkerDescriptor">
         <WorkerDescriptor
             v-if="$props.id"
             :id="$props.id"
diff --git a/src/pages/Worker/Card/WorkerLocker.vue b/src/pages/Worker/Card/WorkerLocker.vue
index 015bced35..62891070d 100644
--- a/src/pages/Worker/Card/WorkerLocker.vue
+++ b/src/pages/Worker/Card/WorkerLocker.vue
@@ -9,7 +9,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
 import { useArrayData } from 'src/composables/useArrayData';
 import FetchData from 'components/FetchData.vue';
 
-const { hasAny } = useAcl();
+const { hasAcl } = useAcl();
 const { t } = useI18n();
 const fetchData = ref();
 const originaLockerId = ref();
@@ -58,11 +58,7 @@ const init = async (data) => {
                 option-label="code"
                 option-value="id"
                 hide-selected
-                :readonly="
-                    !hasAny([
-                        { model: 'Worker', props: '__get__locker', accessType: 'READ' },
-                    ])
-                "
+                :readonly="!hasAcl('Worker', '__get__locker', 'READ')"
             />
         </template>
     </FormModel>
diff --git a/src/pages/Worker/Card/WorkerOperator.vue b/src/pages/Worker/Card/WorkerOperator.vue
index 8ab802b9f..34d9ba020 100644
--- a/src/pages/Worker/Card/WorkerOperator.vue
+++ b/src/pages/Worker/Card/WorkerOperator.vue
@@ -98,12 +98,14 @@ watch(
                             <VnInput
                                 :label="t('worker.operator.numberOfWagons')"
                                 v-model="row.numberOfWagons"
+                                data-cy="numberOfWagons"
                             />
                             <VnSelect
                                 :label="t('worker.operator.train')"
                                 :options="trainsData"
                                 hide-selected
                                 v-model="row.trainFk"
+                                data-cy="train"
                                 :required="true"
                             />
                         </VnRow>
@@ -116,6 +118,7 @@ watch(
                                 option-value="code"
                                 v-model="row.itemPackingTypeFk"
                                 :required="true"
+                                data-cy="itemPackingType"
                             />
                             <VnSelect
                                 :label="t('worker.operator.warehouse')"
@@ -123,6 +126,7 @@ watch(
                                 hide-selected
                                 v-model="row.warehouseFk"
                                 :required="true"
+                                data-cy="warehouse"
                             />
                         </VnRow>
                         <VnRow>
@@ -132,6 +136,7 @@ watch(
                                 hide-selected
                                 option-label="description"
                                 v-model="row.sectorFk"
+                                data-cy="sector"
                             />
                             <VnSelect
                                 :label="t('worker.operator.labeler')"
@@ -139,6 +144,7 @@ watch(
                                 hide-selected
                                 option-label="name"
                                 v-model="row.labelerFk"
+                                data-cy="labeler"
                             >
                                 <template #option="scope">
                                     <QItem v-bind="scope.itemProps">
@@ -160,11 +166,13 @@ watch(
                                 :label="t('worker.operator.linesLimit')"
                                 v-model="row.linesLimit"
                                 lazy-rules
+                                data-cy="linesLimit"
                             />
                             <VnInput
                                 :label="t('worker.operator.volumeLimit')"
                                 v-model="row.volumeLimit"
                                 lazy-rules
+                                data-cy="volumeLimit"
                             />
                         </VnRow>
                         <VnRow>
@@ -172,6 +180,7 @@ watch(
                                 :label="t('worker.operator.sizeLimit')"
                                 v-model="row.sizeLimit"
                                 lazy-rules
+                                data-cy="sizeLimit"
                             />
                             <VnInput
                                 :label="t('worker.operator.isOnReservationMode')"
diff --git a/src/pages/Worker/Card/WorkerPda.vue b/src/pages/Worker/Card/WorkerPda.vue
index d32941494..408260256 100644
--- a/src/pages/Worker/Card/WorkerPda.vue
+++ b/src/pages/Worker/Card/WorkerPda.vue
@@ -5,24 +5,26 @@ import { ref, computed } from 'vue';
 
 import axios from 'axios';
 import useNotify from 'src/composables/useNotify.js';
+import { useVnConfirm } from 'composables/useVnConfirm';
+import { useArrayData } from 'src/composables/useArrayData';
+import { downloadDocuware } from 'src/composables/downloadFile';
+
 import FetchData from 'components/FetchData.vue';
 import FormModelPopup from 'src/components/FormModelPopup.vue';
-import { useVnConfirm } from 'composables/useVnConfirm';
-
-import VnPaginate from 'src/components/ui/VnPaginate.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
-import VnInput from 'src/components/common/VnInput.vue';
+import VnTable from 'src/components/VnTable/VnTable.vue';
 
 const { t } = useI18n();
 const { notify } = useNotify();
-
-const paginate = ref();
+const loadingDocuware = ref(true);
+const tableRef = ref();
 const dialog = ref();
+const getAvailablePdaRef = ref();
 const route = useRoute();
 const { openConfirmationModal } = useVnConfirm();
 const routeId = computed(() => route.params.id);
-
+const worker = computed(() => useArrayData('Worker').store.data);
 const initialData = computed(() => {
     return {
         userFk: routeId.value,
@@ -31,154 +33,271 @@ const initialData = computed(() => {
     };
 });
 
-const deallocatePDA = async (deviceProductionFk) => {
-    await axios.post(`Workers/${route.params.id}/deallocatePDA`, {
-        pda: deviceProductionFk,
-    });
-    notify(t('PDA deallocated'), 'positive');
-
-    paginate.value.fetch();
-};
+const columns = computed(() => [
+    {
+        align: 'center',
+        label: t('globals.state'),
+        name: 'state',
+        format: (row) => row?.docuware?.state,
+        columnFilter: false,
+        chip: {
+            condition: (_, row) => !!row.docuware,
+            color: (row) => (isSigned(row) ? 'bg-positive' : 'bg-warning'),
+        },
+        visible: false,
+    },
+    {
+        align: 'right',
+        label: t('worker.pda.currentPDA'),
+        name: 'deviceProductionFk',
+        columnClass: 'shrink',
+        cardVisible: true,
+    },
+    {
+        align: 'left',
+        label: t('Model'),
+        name: 'modelFk',
+        format: ({ deviceProduction }) => deviceProduction.modelFk,
+        cardVisible: true,
+    },
+    {
+        align: 'right',
+        label: t('Serial number'),
+        name: 'serialNumber',
+        format: ({ deviceProduction }) => deviceProduction.serialNumber,
+        cardVisible: true,
+    },
+    {
+        align: 'left',
+        label: t('Current SIM'),
+        name: 'simFk',
+        cardVisible: true,
+    },
+    {
+        align: 'right',
+        name: 'actions',
+        columnFilter: false,
+        cardVisible: true,
+    },
+]);
 
 function reloadData() {
     initialData.value.deviceProductionFk = null;
     initialData.value.simFk = null;
-    paginate.value.fetch();
+    tableRef.value.reload();
+    getAvailablePdaRef.value.fetch();
+}
+
+async function fetchDocuware() {
+    loadingDocuware.value = true;
+
+    const id = `${worker.value?.lastName} ${worker.value?.firstName}`;
+    const rows = tableRef.value.CrudModelRef.formData;
+
+    const promises = rows.map(async (row) => {
+        const { data } = await axios.post(`Docuwares/${id}/checkFile`, {
+            fileCabinet: 'hr',
+            signed: false,
+            mergeFilter: [
+                {
+                    DBName: 'TIPO_DOCUMENTO',
+                    Value: ['PDA'],
+                },
+                {
+                    DBName: 'OBSERVACIONES',
+                    Value: [row.deviceProductionFk],
+                },
+            ],
+        });
+        row.docuware = data;
+    });
+
+    await Promise.allSettled(promises);
+    loadingDocuware.value = false;
+}
+
+async function sendToTablet(rows) {
+    const promises = rows.map(async (row) => {
+        await axios.post(`Docuwares/upload-pda-pdf`, {
+            ids: [row.deviceProductionFk],
+        });
+        row.docuware = true;
+    });
+    await Promise.allSettled(promises);
+    notify(t('PDF sended to signed'), 'positive');
+    tableRef.value.reload();
+}
+
+async function deallocatePDA(deviceProductionFk) {
+    await axios.post(`Workers/${route.params.id}/deallocatePDA`, {
+        pda: deviceProductionFk,
+    });
+    const index = tableRef.value.CrudModelRef.formData.findIndex(
+        (data) => data?.deviceProductionFk == deviceProductionFk,
+    );
+    delete tableRef.value.CrudModelRef.formData[index];
+    notify(t('PDA deallocated'), 'positive');
+    await getAvailablePdaRef.value.fetch();
+}
+
+function isSigned(row) {
+    return row.docuware?.state === 'Firmado';
 }
 </script>
 
 <template>
-    <QPage class="column items-center q-pa-md centerCard">
-        <FetchData
-            url="workers/getAvailablePda"
-            @on-fetch="(data) => (deviceProductions = data)"
-            auto-load
-        />
-        <VnPaginate
-            ref="paginate"
-            data-key="WorkerPda"
-            url="DeviceProductionUsers"
-            :user-filter="{ where: { userFk: routeId } }"
-            order="id"
-            search-url="pda"
-            auto-load
-        >
-            <template #body="{ rows }">
-                <QCard
-                    flat
-                    bordered
-                    :key="row.id"
-                    v-for="row of rows"
-                    class="card q-px-md q-mb-sm container"
-                >
-                    <VnRow>
-                        <VnInput
-                            :label="t('worker.pda.currentPDA')"
-                            :model-value="row?.deviceProductionFk"
-                            disable
-                        />
-                        <VnInput
-                            :label="t('Model')"
-                            :model-value="row?.deviceProduction?.modelFk"
-                            disable
-                        />
-                        <VnInput
-                            :label="t('Serial number')"
-                            :model-value="row?.deviceProduction?.serialNumber"
-                            disable
-                        />
-                        <VnInput
-                            :label="t('Current SIM')"
-                            :model-value="row?.simFk"
-                            disable
-                        />
-                        <QBtn
-                            flat
-                            icon="delete"
-                            color="primary"
-                            class="btn-delete"
-                            @click="
-                                openConfirmationModal(
-                                    t(`Remove PDA`),
-                                    t('Do you want to remove this PDA?'),
-                                    () => deallocatePDA(row.deviceProductionFk),
-                                )
-                            "
-                        >
-                            <QTooltip>
-                                {{ t('worker.pda.removePDA') }}
-                            </QTooltip>
-                        </QBtn>
-                    </VnRow>
-                </QCard>
-            </template>
-        </VnPaginate>
-        <QPageSticky :offset="[18, 18]">
+    <FetchData
+        ref="getAvailablePdaRef"
+        url="workers/getAvailablePda"
+        @on-fetch="(data) => (deviceProductions = data)"
+        auto-load
+    />
+    <VnTable
+        ref="tableRef"
+        data-key="WorkerPda"
+        url="DeviceProductionUsers"
+        :user-filter="{ order: 'id' }"
+        :filter="{ where: { userFk: routeId } }"
+        search-url="pda"
+        auto-load
+        :columns="columns"
+        @onFetch="fetchDocuware"
+        :hasSubToolbar="true"
+        :default-remove="false"
+        :default-reset="false"
+        :default-save="false"
+        :table="{
+            'row-key': 'deviceProductionFk',
+            selection: 'multiple',
+        }"
+        :table-filter="{ hiddenTags: ['userFk'] }"
+    >
+        <template #moreBeforeActions>
             <QBtn
-                @click.stop="dialog.show()"
+                :label="t('globals.refresh')"
+                icon="refresh"
+                @click="tableRef.reload()"
+            />
+            <QBtn
+                :disable="!tableRef?.selected?.length"
+                :label="t('globals.send')"
+                icon="install_mobile"
+                @click="sendToTablet(tableRef?.selected)"
+                class="bg-primary"
+            />
+        </template>
+        <template #column-actions="{ row }">
+            <QBtn
+                flat
+                icon="delete"
                 color="primary"
-                fab
-                icon="add"
-                v-shortcut="'+'"
+                @click="
+                    openConfirmationModal(
+                        t(`Remove PDA`),
+                        t('Do you want to remove this PDA?'),
+                        () => deallocatePDA(row.deviceProductionFk),
+                    )
+                "
+                data-cy="workerPda-remove"
             >
-                <QDialog ref="dialog">
-                    <FormModelPopup
-                        :title="t('Add new device')"
-                        url-create="DeviceProductionUsers"
-                        model="DeviceProductionUser"
-                        :form-initial-data="initialData"
-                        @on-data-saved="reloadData()"
-                    >
-                        <template #form-inputs="{ data }">
-                            <VnRow>
-                                <VnSelect
-                                    :label="t('worker.pda.newPDA')"
-                                    v-model="data.deviceProductionFk"
-                                    :options="deviceProductions"
-                                    option-label="id"
-                                    option-value="id"
-                                    id="deviceProductionFk"
-                                    hide-selected
-                                    data-cy="pda-dialog-select"
-                                    :required="true"
-                                >
-                                    <template #option="scope">
-                                        <QItem v-bind="scope.itemProps">
-                                            <QItemSection>
-                                                <QItemLabel
-                                                    >ID: {{ scope.opt?.id }}</QItemLabel
-                                                >
-                                                <QItemLabel caption>
-                                                    {{ scope.opt?.modelFk }},
-                                                    {{ scope.opt?.serialNumber }}
-                                                </QItemLabel>
-                                            </QItemSection>
-                                        </QItem>
-                                    </template>
-                                </VnSelect>
-                                <VnInput
-                                    v-model="data.simFk"
-                                    :label="t('SIM serial number')"
-                                    id="simSerialNumber"
-                                    use-input
-                                />
-                            </VnRow>
-                        </template>
-                    </FormModelPopup>
-                </QDialog>
+                <QTooltip>
+                    {{ t('worker.pda.removePDA') }}
+                </QTooltip>
             </QBtn>
-            <QTooltip>
-                {{ t('globals.new') }}
-            </QTooltip>
-        </QPageSticky>
-    </QPage>
+            <QBtn
+                v-if="!isSigned(row)"
+                :loading="loadingDocuware"
+                icon="install_mobile"
+                flat
+                color="primary"
+                @click="
+                    openConfirmationModal(
+                        t('Sign PDA'),
+                        t('Are you sure you want to send it?'),
+                        () => sendToTablet([row]),
+                    )
+                "
+                data-cy="workerPda-send"
+            >
+                <QTooltip>
+                    {{ t('worker.pda.sendToTablet') }}
+                </QTooltip>
+            </QBtn>
+            <QBtn
+                v-if="isSigned(row)"
+                :loading="loadingDocuware"
+                icon="cloud_download"
+                flat
+                color="primary"
+                @click="
+                    downloadDocuware('Docuwares/download-pda-pdf', {
+                        file: row.deviceProductionFk + '-pda',
+                        worker: worker?.lastName + ' ' + worker?.firstName,
+                    })
+                "
+                data-cy="workerPda-download"
+            >
+                <QTooltip>
+                    {{ t('globals.downloadPdf') }}
+                </QTooltip>
+            </QBtn>
+        </template>
+    </VnTable>
+    <QPageSticky :offset="[18, 18]">
+        <QBtn @click.stop="dialog.show()" color="primary" fab icon="add" v-shortcut="'+'">
+            <QDialog ref="dialog">
+                <FormModelPopup
+                    :title="t('Add new device')"
+                    url-create="DeviceProductionUsers"
+                    model="DeviceProductionUser"
+                    :form-initial-data="initialData"
+                    @on-data-saved="reloadData()"
+                >
+                    <template #form-inputs="{ data }">
+                        <VnRow>
+                            <VnSelect
+                                :label="t('PDA')"
+                                v-model="data.deviceProductionFk"
+                                :options="deviceProductions"
+                                option-label="modelFk"
+                                option-value="id"
+                                id="deviceProductionFk"
+                                hide-selected
+                                data-cy="pda-dialog-select"
+                                :required="true"
+                            >
+                                <template #option="scope">
+                                    <QItem v-bind="scope.itemProps">
+                                        <QItemSection>
+                                            <QItemLabel
+                                                >ID: {{ scope.opt?.id }}</QItemLabel
+                                            >
+                                            <QItemLabel caption>
+                                                {{ scope.opt?.modelFk }},
+                                                {{ scope.opt?.serialNumber }}
+                                            </QItemLabel>
+                                        </QItemSection>
+                                    </QItem>
+                                </template>
+                            </VnSelect>
+                            <VnSelect
+                                url="Sims"
+                                option-label="line"
+                                option-value="code"
+                                v-model="data.simFk"
+                                :label="t('SIM serial number')"
+                                id="simSerialNumber"
+                            />
+                        </VnRow>
+                    </template>
+                </FormModelPopup>
+            </QDialog>
+        </QBtn>
+        <QTooltip>
+            {{ t('globals.new') }}
+        </QTooltip>
+    </QPageSticky>
 </template>
-<style lang="scss" scoped>
-.btn-delete {
-    max-width: 4%;
-    margin-top: 30px;
-}
-</style>
 <i18n>
 es:
     Model: Modelo
@@ -190,4 +309,7 @@ es:
     Do you want to remove this PDA?: ¿Desea eliminar este PDA?
     You can only have one PDA: Solo puedes tener un PDA si no eres autonomo
     This PDA is already assigned to another user: Este PDA ya está asignado a otro usuario
+    Are you sure you want to send it?: ¿Seguro que quieres enviarlo?
+    Sign PDA: Firmar PDA
+    PDF sended to signed: PDF enviado para firmar
 </i18n>
diff --git a/src/pages/Worker/Card/WorkerPit.vue b/src/pages/Worker/Card/WorkerPit.vue
index 3de60d6a0..cb07c1f1d 100644
--- a/src/pages/Worker/Card/WorkerPit.vue
+++ b/src/pages/Worker/Card/WorkerPit.vue
@@ -68,8 +68,14 @@ const deleteRelative = async (id) => {
                         :label="t('familySituation')"
                         clearable
                         v-model="data.familySituation"
+                        data-cy="familySituation"
+                    />
+                    <VnInput
+                        :label="t('spouseNif')"
+                        clearable
+                        v-model="data.spouseNif"
+                        data-cy="spouseNif"
                     />
-                    <VnInput :label="t('spouseNif')" clearable v-model="data.spouseNif" />
                 </VnRow>
                 <VnRow>
                     <VnSelect
@@ -93,11 +99,13 @@ const deleteRelative = async (id) => {
                         clearable
                         v-model="data.childPension"
                         :label="t(`childPension`)"
+                        data-cy="childPension"
                     />
                     <VnInput
                         clearable
                         v-model="data.spousePension"
                         :label="t(`spousePension`)"
+                        data-cy="spousePension"
                     />
                 </VnRow>
                 <VnRow wrap>
@@ -190,12 +198,14 @@ const deleteRelative = async (id) => {
                                 type="number"
                                 v-model="row.birthed"
                                 :label="t(`birthed`)"
+                                data-cy="birthed"
                             />
 
                             <VnInput
                                 type="number"
                                 v-model="row.adoptionYear"
                                 :label="t(`adoptionYear`)"
+                                data-cy="adoptionYear"
                             />
                             <QCheckbox
                                 v-model="row.isDependend"
diff --git a/src/pages/Worker/Card/WorkerSummary.vue b/src/pages/Worker/Card/WorkerSummary.vue
index 78c5dfd82..96d5220f5 100644
--- a/src/pages/Worker/Card/WorkerSummary.vue
+++ b/src/pages/Worker/Card/WorkerSummary.vue
@@ -39,6 +39,7 @@ onBeforeMount(async () => {
         url="Workers/summary"
         :user-filter="{ where: { id: entityId } }"
         data-key="Worker"
+        module-name="Worker"
     >
         <template #header="{ entity }">
             <div>{{ entity.id }} - {{ entity.firstName }} {{ entity.lastName }}</div>
@@ -47,82 +48,91 @@ onBeforeMount(async () => {
             <WorkerDescriptorMenu :worker="entity" :is-excluded="workerExcluded" />
         </template>
         <template #body="{ entity: worker }">
-            <QCard class="vn-one">
+            <QCard class="vn-two">
                 <VnTitle :url="basicDataUrl" :text="t('globals.summary.basicData')" />
-                <VnLv :label="t('globals.name')" :value="worker.user?.nickname" />
-                <VnLv :label="t('worker.list.department')">
-                    <template #value>
-                        <span class="link" v-text="worker.department?.department?.name" />
-                        <DepartmentDescriptorProxy
-                            :id="worker.department?.department?.id"
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
+                        <VnLv :label="t('globals.name')" :value="worker.user?.nickname" />
+                        <VnLv :label="t('globals.department')">
+                            <template #value>
+                                <span
+                                    class="link"
+                                    v-text="worker.department?.department?.name"
+                                />
+                                <DepartmentDescriptorProxy
+                                    :id="worker.department?.department?.id"
+                                />
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('worker.summary.boss')" link>
+                            <template #value>
+                                <VnUserLink
+                                    v-if="worker.boss"
+                                    :name="dashIfEmpty(worker.boss?.name)"
+                                    :worker-id="worker.bossFk"
+                                />
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('worker.summary.phoneExtension')">
+                            <template #value>
+                                <VnLinkPhone :phone-number="worker.mobileExtension" />
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('worker.summary.entPhone')">
+                            <template #value>
+                                <VnLinkPhone :phone-number="worker.phone" />
+                            </template>
+                        </VnLv>
+                        <VnLv :label="t('worker.summary.personalPhone')">
+                            <template #value>
+                                <VnLinkPhone
+                                    :phone-number="advancedSummary?.client?.phone"
+                                />
+                            </template>
+                        </VnLv>
+                    </div>
+                    <div class="vn-card-content" v-if="advancedSummary">
+                        <VnLv
+                            :label="t('worker.summary.fiDueDate')"
+                            :value="toDate(advancedSummary.fiDueDate)"
                         />
-                    </template>
-                </VnLv>
-                <VnLv :label="t('worker.summary.boss')" link>
-                    <template #value>
-                        <VnUserLink
-                            v-if="worker.boss"
-                            :name="dashIfEmpty(worker.boss?.name)"
-                            :worker-id="worker.bossFk"
+                        <VnLv :label="t('worker.summary.sex')" :value="worker.sex" />
+                        <VnLv
+                            :label="t('worker.summary.seniority')"
+                            :value="toDate(advancedSummary.seniority)"
                         />
-                    </template>
-                </VnLv>
-                <VnLv :value="worker.mobileExtension">
-                    <template #label>
-                        {{ t('worker.summary.phoneExtension') }}
-                        <VnLinkPhone :phone-number="worker.mobileExtension" />
-                    </template>
-                </VnLv>
-                <VnLv :value="worker.phone">
-                    <template #label>
-                        {{ t('worker.summary.entPhone') }}
-                        <VnLinkPhone :phone-number="worker.phone" />
-                    </template>
-                </VnLv>
-                <VnLv :value="advancedSummary?.client?.phone">
-                    <template #label>
-                        {{ t('worker.summary.personalPhone') }}
-                        <VnLinkPhone :phone-number="advancedSummary?.client?.phone" />
-                    </template>
-                </VnLv>
-            </QCard>
-            <QCard class="vn-one" v-if="advancedSummary">
-                <VnTitle :url="basicDataUrl" :text="t('globals.summary.basicData')" />
-                <VnLv
-                    :label="t('worker.summary.fiDueDate')"
-                    :value="toDate(advancedSummary.fiDueDate)"
-                />
-                <VnLv :label="t('worker.summary.sex')" :value="worker.sex" />
-                <VnLv
-                    :label="t('worker.summary.seniority')"
-                    :value="toDate(advancedSummary.seniority)"
-                />
-                <VnLv :label="t('worker.summary.fi')" :value="advancedSummary.fi" />
-                <VnLv
-                    :label="t('worker.summary.birth')"
-                    :value="toDate(advancedSummary.birth)"
-                />
-                <VnLv
-                    :label="t('worker.summary.isFreelance')"
-                    :value="advancedSummary.isFreelance"
-                />
-                <VnLv
-                    :label="t('worker.summary.isSsDiscounted')"
-                    :value="advancedSummary.isSsDiscounted"
-                />
-                <VnLv
-                    :label="t('worker.summary.hasMachineryAuthorized')"
-                    :value="advancedSummary.hasMachineryAuthorized"
-                />
-                <VnLv
-                    :label="t('worker.summary.isDisable')"
-                    :value="advancedSummary.isDisable"
-                />
+                        <VnLv
+                            :label="t('worker.summary.fi')"
+                            :value="advancedSummary.fi"
+                        />
+                        <VnLv
+                            :label="t('worker.summary.birth')"
+                            :value="toDate(advancedSummary.birth)"
+                        />
+                        <VnLv
+                            :label="t('worker.summary.isFreelance')"
+                            :value="advancedSummary.isFreelance"
+                        />
+                        <VnLv
+                            :label="t('worker.summary.isSsDiscounted')"
+                            :value="advancedSummary.isSsDiscounted"
+                        />
+                        <VnLv
+                            :label="t('worker.summary.hasMachineryAuthorized')"
+                            :value="advancedSummary.hasMachineryAuthorized"
+                        />
+                        <VnLv
+                            :label="t('worker.summary.isDisable')"
+                            :value="advancedSummary.isDisable"
+                        />
+                    </div>
+                </div>
             </QCard>
             <QCard class="vn-one">
                 <VnTitle :text="t('worker.summary.userData')" />
                 <VnLv :label="t('globals.name')" :value="worker?.user?.nickname" />
                 <VnLv
+                    class="ellipsis"
                     :label="t('globals.params.email')"
                     :value="worker.user?.emailUser?.email"
                     copy
@@ -135,9 +145,8 @@ onBeforeMount(async () => {
                         </span>
                     </template>
                 </VnLv>
-                <VnLv :value="worker?.sip?.extension">
-                    <template #label>
-                        {{ t('worker.summary.sipExtension') }}
+                <VnLv :label="t('worker.summary.sipExtension')">
+                    <template #value>
                         <VnLinkPhone :phone-number="worker?.sip?.extension" />
                     </template>
                 </VnLv>
diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue
index 9c0fa6758..b64166c7d 100644
--- a/src/pages/Worker/Card/WorkerTimeControl.vue
+++ b/src/pages/Worker/Card/WorkerTimeControl.vue
@@ -68,13 +68,9 @@ const arrayData = useArrayData('Worker');
 const acl = useAcl();
 const selectedDateYear = computed(() => moment(selectedDate.value).isoWeekYear());
 const worker = computed(() => arrayData.store?.data);
-const canSend = computed(() =>
-    acl.hasAny([{ model: 'WorkerTimeControl', props: 'sendMail', accessType: 'WRITE' }]),
-);
+const canSend = computed(() => acl.hasAcl('WorkerTimeControl', 'sendMail', 'WRITE'));
 const canUpdate = computed(() =>
-    acl.hasAny([
-        { model: 'WorkerTimeControl', props: 'updateMailState', accessType: 'WRITE' },
-    ]),
+    acl.hasAcl('WorkerTimeControl', 'updateMailState', 'WRITE'),
 );
 const isHimself = computed(() => user.value.id === Number(route.params.id));
 
diff --git a/src/pages/Worker/Card/WorkerTimeForm.vue b/src/pages/Worker/Card/WorkerTimeForm.vue
index 3250e3180..ea9d89144 100644
--- a/src/pages/Worker/Card/WorkerTimeForm.vue
+++ b/src/pages/Worker/Card/WorkerTimeForm.vue
@@ -53,7 +53,7 @@ const title = computed(() => (isEditMode.value ? t('Edit entry') : t('Add time')
 const urlCreate = computed(() =>
     isEditMode.value
         ? `WorkerTimeControls/${$props.entryId}/updateTimeEntry`
-        : `WorkerTimeControls/${route.params.id}/addTimeEntry`
+        : `WorkerTimeControls/${route.params.id}/addTimeEntry`,
 );
 
 onBeforeMount(() => {
@@ -83,6 +83,7 @@ onBeforeMount(() => {
                 autofocus
                 :required="true"
                 :is-clearable="false"
+                data-cy="entryHour"
             />
             <VnSelect
                 :label="t('Type')"
@@ -91,6 +92,7 @@ onBeforeMount(() => {
                 option-value="code"
                 option-label="description"
                 hide-selected
+                data-cy="entryType"
             />
         </template>
     </FormModelPopup>
diff --git a/src/pages/Worker/Department/Card/DepartmentCard.vue b/src/pages/Worker/Department/Card/DepartmentCard.vue
index 2e3f11521..0fbc90332 100644
--- a/src/pages/Worker/Department/Card/DepartmentCard.vue
+++ b/src/pages/Worker/Department/Card/DepartmentCard.vue
@@ -1,9 +1,9 @@
 <script setup>
-import VnCardBeta from 'components/common/VnCardBeta.vue';
+import VnCard from 'components/common/VnCard.vue';
 import DepartmentDescriptor from 'pages/Worker/Department/Card/DepartmentDescriptor.vue';
 </script>
 <template>
-    <VnCardBeta
+    <VnCard
         class="q-pa-md column items-center"
         v-bind="{ ...$attrs }"
         data-key="Department"
diff --git a/src/pages/Worker/Department/Card/DepartmentDescriptor.vue b/src/pages/Worker/Department/Card/DepartmentDescriptor.vue
index 4b7dfd9b8..820658593 100644
--- a/src/pages/Worker/Department/Card/DepartmentDescriptor.vue
+++ b/src/pages/Worker/Department/Card/DepartmentDescriptor.vue
@@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { useVnConfirm } from 'composables/useVnConfirm';
 import VnLv from 'src/components/ui/VnLv.vue';
-import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'src/components/ui/EntityDescriptor.vue';
 
 import axios from 'axios';
 import useNotify from 'src/composables/useNotify.js';
@@ -40,7 +40,7 @@ const removeDepartment = async () => {
 const { openConfirmationModal } = useVnConfirm();
 </script>
 <template>
-    <CardDescriptor
+    <EntityDescriptor
         ref="DepartmentDescriptorRef"
         :url="`Departments/${entityId}`"
         :summary="$props.summary"
@@ -95,7 +95,7 @@ const { openConfirmationModal } = useVnConfirm();
                 </QBtn>
             </QCardActions>
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
 
 <i18n>
diff --git a/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue b/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue
index 5b556f655..c793e9319 100644
--- a/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue
+++ b/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue
@@ -16,6 +16,7 @@ const $props = defineProps({
             v-if="$props.id"
             :id="$props.id"
             :summary="DepartmentSummary"
+            data-key="DepartmentDescriptorProxy"
         />
     </QPopupProxy>
 </template>
diff --git a/src/pages/Worker/WorkerFilter.vue b/src/pages/Worker/WorkerFilter.vue
index 8210ba0e3..c40afe57e 100644
--- a/src/pages/Worker/WorkerFilter.vue
+++ b/src/pages/Worker/WorkerFilter.vue
@@ -35,7 +35,7 @@ const getLocale = (label) => {
         <template #body="{ params }">
             <QItem>
                 <QItemSection>
-                    <VnInput :label="t('FI')" v-model="params.fi" is-outlined
+                    <VnInput :label="t('FI')" v-model="params.fi" filled
                         ><template #prepend>
                             <QIcon name="badge" size="xs"></QIcon> </template
                     ></VnInput>
@@ -43,29 +43,17 @@ const getLocale = (label) => {
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        :label="t('First Name')"
-                        v-model="params.firstName"
-                        is-outlined
-                    />
+                    <VnInput :label="t('First Name')" v-model="params.firstName" filled />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        :label="t('Last Name')"
-                        v-model="params.lastName"
-                        is-outlined
-                    />
+                    <VnInput :label="t('Last Name')" v-model="params.lastName" filled />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        :label="t('User Name')"
-                        v-model="params.userName"
-                        is-outlined
-                    />
+                    <VnInput :label="t('User Name')" v-model="params.userName" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -79,23 +67,18 @@ const getLocale = (label) => {
                         emit-value
                         map-options
                         dense
-                        outlined
-                        rounded
+                        filled
                     />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput :label="t('Email')" v-model="params.email" is-outlined />
+                    <VnInput :label="t('Email')" v-model="params.email" filled />
                 </QItemSection>
             </QItem>
             <QItem>
                 <QItemSection>
-                    <VnInput
-                        :label="t('Extension')"
-                        v-model="params.extension"
-                        is-outlined
-                    />
+                    <VnInput :label="t('Extension')" v-model="params.extension" filled />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -119,8 +102,11 @@ en:
         lastName: Last name
         userName: User
         extension: Extension
+        departmentFk: Department
 es:
+
     params:
+        departmentFk: Departamento
         search: Contiene
         firstName: Nombre
         lastName: Apellidos
diff --git a/src/pages/Worker/WorkerList.vue b/src/pages/Worker/WorkerList.vue
index 79eb26881..cb722a139 100644
--- a/src/pages/Worker/WorkerList.vue
+++ b/src/pages/Worker/WorkerList.vue
@@ -105,7 +105,7 @@ const columns = computed(() => [
             {
                 title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
-                action: (row) => viewSummary(row.id, WorkerSummary),
+                action: (row) => viewSummary(row.id, WorkerSummary, 'lg-width'),
                 isPrimary: true,
             },
         ],
@@ -223,7 +223,7 @@ async function autofillBic(worker) {
                 :right-search="false"
             >
                 <template #more-create-dialog="{ data }">
-                    <div class="q-pa-lg full-width">
+                    <div class="col-span-2">
                         <VnRadio
                             v-model="data.isFreelance"
                             :val="false"
diff --git a/src/pages/Zone/Card/ZoneCard.vue b/src/pages/Zone/Card/ZoneCard.vue
index 41daff5c0..80b209fe3 100644
--- a/src/pages/Zone/Card/ZoneCard.vue
+++ b/src/pages/Zone/Card/ZoneCard.vue
@@ -1,38 +1,15 @@
 <script setup>
-import { useRoute } from 'vue-router';
-import { computed } from 'vue';
-
-import VnCard from 'components/common/VnCard.vue';
+import VnCard from 'src/components/common/VnCard.vue';
 import ZoneDescriptor from './ZoneDescriptor.vue';
-import ZoneFilterPanel from '../ZoneFilterPanel.vue';
-import filter from './ZoneFilter.js';
-
+import filter from 'src/pages/Zone/Card/ZoneFilter.js';
+import { useRoute } from 'vue-router';
 const route = useRoute();
-const routeName = computed(() => route.name);
-
-function notIsLocations(ifIsFalse, ifIsTrue) {
-    if (routeName.value != 'ZoneLocations') return ifIsFalse;
-    return ifIsTrue;
-}
 </script>
-
 <template>
     <VnCard
         data-key="Zone"
-        :url="notIsLocations('Zones', undefined)"
+        :url="`Zones/${route.params.id}`"
         :descriptor="ZoneDescriptor"
         :filter="filter"
-        :filter-panel="notIsLocations(ZoneFilterPanel, undefined)"
-        :search-data-key="notIsLocations('ZoneList', undefined)"
-        :searchbar-props="{
-            url: notIsLocations('Zones', 'ZoneLocations'),
-            label: notIsLocations($t('list.searchZone'), $t('list.searchLocation')),
-            info: $t('list.searchInfo'),
-            whereFilter: notIsLocations((value) => {
-                return /^\d+$/.test(value)
-                    ? { id: value }
-                    : { name: { like: `%${value}%` } };
-            }),
-        }"
     />
 </template>
diff --git a/src/pages/Zone/Card/ZoneDescriptor.vue b/src/pages/Zone/Card/ZoneDescriptor.vue
index 27676212e..f2bcc1247 100644
--- a/src/pages/Zone/Card/ZoneDescriptor.vue
+++ b/src/pages/Zone/Card/ZoneDescriptor.vue
@@ -2,7 +2,7 @@
 import { computed } from 'vue';
 import { useRoute } from 'vue-router';
 
-import CardDescriptor from 'components/ui/CardDescriptor.vue';
+import EntityDescriptor from 'components/ui/EntityDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import { toTimeFormat } from 'src/filters/date';
 import { toCurrency } from 'filters/index';
@@ -25,7 +25,7 @@ const entityId = computed(() => {
 </script>
 
 <template>
-    <CardDescriptor :url="`Zones/${entityId}`" :filter="filter" data-key="Zone">
+    <EntityDescriptor :url="`Zones/${entityId}`" :filter="filter" data-key="Zone">
         <template #menu="{ entity }">
             <ZoneDescriptorMenuItems :zone="entity" />
         </template>
@@ -36,5 +36,5 @@ const entityId = computed(() => {
             <VnLv :label="$t('list.price')" :value="toCurrency(entity.price)" />
             <VnLv :label="$t('zone.bonus')" :value="toCurrency(entity.bonus)" />
         </template>
-    </CardDescriptor>
+    </EntityDescriptor>
 </template>
diff --git a/src/pages/Zone/Card/ZoneDescriptorProxy.vue b/src/pages/Zone/Card/ZoneDescriptorProxy.vue
index 27102ac07..a16d231e6 100644
--- a/src/pages/Zone/Card/ZoneDescriptorProxy.vue
+++ b/src/pages/Zone/Card/ZoneDescriptorProxy.vue
@@ -11,7 +11,7 @@ const $props = defineProps({
 </script>
 
 <template>
-    <QPopupProxy>
+    <QPopupProxy data-cy="ZoneDescriptor">
         <ZoneDescriptor v-if="$props.id" :id="$props.id" :summary="ZoneSummary" />
     </QPopupProxy>
 </template>
diff --git a/src/pages/Zone/Card/ZoneEventExclusionForm.vue b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
index 4b6aa52bd..582a8bbad 100644
--- a/src/pages/Zone/Card/ZoneEventExclusionForm.vue
+++ b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
@@ -1,16 +1,18 @@
 <script setup>
-import { ref, computed, onMounted, reactive } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
+import { useQuasar } from 'quasar';
+import axios from 'axios';
+import moment from 'moment';
 
 import VnRow from 'components/ui/VnRow.vue';
 import FormPopup from 'components/FormPopup.vue';
 import ZoneLocationsTree from './ZoneLocationsTree.vue';
 import VnInputDate from 'src/components/common/VnInputDate.vue';
-
 import { useArrayData } from 'src/composables/useArrayData';
 import { useVnConfirm } from 'composables/useVnConfirm';
-import axios from 'axios';
+import { toDateFormat } from 'src/filters/date';
 
 const props = defineProps({
     date: {
@@ -34,18 +36,25 @@ const props = defineProps({
         type: Array,
         default: () => [],
     },
+    isMasiveEdit: {
+        type: Boolean,
+        default: false,
+    },
+    zoneIds: {
+        type: Array,
+        default: () => [],
+    },
 });
 
 const emit = defineEmits(['onSubmit', 'closeForm']);
-
+const quasar = useQuasar();
 const route = useRoute();
 const { t } = useI18n();
 const { openConfirmationModal } = useVnConfirm();
 
 const isNew = computed(() => props.isNewMode);
-const dated = reactive(props.date);
+const dated = ref(props.date || Date.vnNew());
 const tickedNodes = ref();
-
 const _excludeType = ref('all');
 const excludeType = computed({
     get: () => _excludeType.value,
@@ -63,16 +72,46 @@ const exclusionGeoCreate = async () => {
         geoIds: tickedNodes.value,
     };
     await axios.post('Zones/exclusionGeo', params);
+    quasar.notify({
+        message: t('globals.dataSaved'),
+        type: 'positive',
+    });
     await refetchEvents();
 };
 
 const exclusionCreate = async () => {
-    const url = `Zones/${route.params.id}/exclusions`;
+    const defaultMonths = await axios.get('ZoneConfigs');
+    const nMonths = defaultMonths.data[0].defaultMonths;
     const body = {
-        dated,
+        dated: dated.value,
     };
-    if (isNew.value || props.event?.type) await axios.post(`${url}`, [body]);
-    else await axios.put(`${url}/${props.event?.id}`, body);
+    const zoneIds = props.zoneIds?.length ? props.zoneIds : [route.params.id];
+    for (const id of zoneIds) {
+        const url = `Zones/${id}/exclusions`;
+        let today = moment(dated.value);
+        let lastDay = today.clone().add(nMonths, 'months').endOf('month');
+
+        const { data } = await axios.get(`Zones/getEventsFiltered`, {
+            params: {
+                zoneFk: id,
+                started: today,
+                ended: lastDay,
+            },
+        });
+        const existsEvent = data.events.find(
+            (event) => toDateFormat(event.dated) === toDateFormat(dated.value),
+        );
+        if (existsEvent) {
+            await axios.delete(`Zones/${existsEvent?.zoneFk}/events/${existsEvent?.id}`);
+        }
+
+        if (isNew.value || props.event?.type) await axios.post(`${url}`, [body]);
+        else await axios.put(`${url}/${props.event?.id}`, body);
+    }
+    quasar.notify({
+        message: t('globals.dataSaved'),
+        type: 'positive',
+    });
     await refetchEvents();
 };
 
@@ -129,6 +168,7 @@ onMounted(() => {
                     :label="t('eventsExclusionForm.all')"
                 />
                 <QRadio
+                    v-if="!props.isMasiveEdit"
                     v-model="excludeType"
                     dense
                     val="specificLocations"
@@ -171,9 +211,10 @@ onMounted(() => {
                     openConfirmationModal(
                         t('eventsPanel.deleteTitle'),
                         t('eventsPanel.deleteSubtitle'),
-                        () => deleteEvent()
+                        () => deleteEvent(),
                     )
                 "
+                data-cy="ZoneEventExclusionDeleteBtn"
             />
             <QBtn
                 :label="isNew ? t('globals.add') : t('globals.save')"
diff --git a/src/pages/Zone/Card/ZoneEventInclusionForm.vue b/src/pages/Zone/Card/ZoneEventInclusionForm.vue
index 88f8b30e4..8b02c2d84 100644
--- a/src/pages/Zone/Card/ZoneEventInclusionForm.vue
+++ b/src/pages/Zone/Card/ZoneEventInclusionForm.vue
@@ -2,6 +2,13 @@
 import { ref, computed, onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
+import { useQuasar } from 'quasar';
+import axios from 'axios';
+import moment from 'moment';
+
+import { useArrayData } from 'src/composables/useArrayData';
+import { useWeekdayStore } from 'src/stores/useWeekdayStore';
+import { useVnConfirm } from 'composables/useVnConfirm';
 
 import VnRow from 'components/ui/VnRow.vue';
 import FormPopup from 'components/FormPopup.vue';
@@ -9,16 +16,11 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
 import VnWeekdayPicker from 'src/components/common/VnWeekdayPicker.vue';
 import VnInputTime from 'components/common/VnInputTime.vue';
 import VnInput from 'src/components/common/VnInput.vue';
-
-import { useArrayData } from 'src/composables/useArrayData';
-import { useWeekdayStore } from 'src/stores/useWeekdayStore';
-import { useVnConfirm } from 'composables/useVnConfirm';
-import axios from 'axios';
+import { toDateFormat } from 'src/filters/date';
 
 const props = defineProps({
     date: {
         type: Date,
-        required: true,
         default: null,
     },
     event: {
@@ -33,6 +35,14 @@ const props = defineProps({
         type: Boolean,
         default: true,
     },
+    isMasiveEdit: {
+        type: Boolean,
+        default: false,
+    },
+    zoneIds: {
+        type: Array,
+        default: () => [],
+    },
 });
 
 const emit = defineEmits(['onSubmit', 'closeForm']);
@@ -41,10 +51,10 @@ const route = useRoute();
 const { t } = useI18n();
 const weekdayStore = useWeekdayStore();
 const { openConfirmationModal } = useVnConfirm();
-
+const quasar = useQuasar();
 const isNew = computed(() => props.isNewMode);
 const eventInclusionFormData = ref({ wdays: [] });
-
+const dated = ref(props.date || Date.vnNew());
 const _inclusionType = ref('indefinitely');
 const inclusionType = computed({
     get: () => _inclusionType.value,
@@ -57,8 +67,12 @@ const inclusionType = computed({
 const arrayData = useArrayData('ZoneEvents');
 
 const createEvent = async () => {
+    const defaultMonths = await axios.get('ZoneConfigs');
+    const nMonths = defaultMonths.data[0].defaultMonths;
+
     eventInclusionFormData.value.weekDays = weekdayStore.toSet(
         eventInclusionFormData.value.wdays,
+        eventInclusionFormData.value.wdays,
     );
 
     if (inclusionType.value == 'day') eventInclusionFormData.value.weekDays = '';
@@ -69,14 +83,43 @@ const createEvent = async () => {
         eventInclusionFormData.value.ended = null;
     }
 
-    if (isNew.value)
-        await axios.post(`Zones/${route.params.id}/events`, eventInclusionFormData.value);
-    else
-        await axios.put(
-            `Zones/${route.params.id}/events/${props.event?.id}`,
-            eventInclusionFormData.value,
-        );
+    const zoneIds = props.zoneIds?.length ? props.zoneIds : [route.params.id];
+    for (const id of zoneIds) {
+        let today = eventInclusionFormData.value.dated
+            ? moment(eventInclusionFormData.value.dated)
+            : moment(dated.value);
+        let lastDay = today.clone().add(nMonths, 'months').endOf('month');
 
+        const { data } = await axios.get(`Zones/getEventsFiltered`, {
+            params: {
+                zoneFk: id,
+                started: today,
+                ended: lastDay,
+            },
+        });
+        const existsExclusion = data.exclusions.find(
+            (exclusion) =>
+                toDateFormat(exclusion.dated) ===
+                toDateFormat(eventInclusionFormData.value.dated),
+        );
+        if (existsExclusion) {
+            await axios.delete(
+                `Zones/${existsExclusion?.zoneFk}/exclusions/${existsExclusion?.id}`,
+            );
+        }
+
+        if (isNew.value)
+            await axios.post(`Zones/${id}/events`, eventInclusionFormData.value);
+        else
+            await axios.put(
+                `Zones/${id}/events/${props.event?.id}`,
+                eventInclusionFormData.value,
+            );
+    }
+    quasar.notify({
+        message: t('globals.dataSaved'),
+        type: 'positive',
+    });
     await refetchEvents();
     emit('onSubmit');
 };
@@ -98,9 +141,11 @@ const refetchEvents = async () => {
 
 onMounted(() => {
     if (props.event) {
+        dated.value = props.event?.dated;
         eventInclusionFormData.value = { ...props.event };
         inclusionType.value = props.event?.type || 'day';
     } else if (props.date) {
+        dated.value = props.date;
         eventInclusionFormData.value.dated = props.date;
         inclusionType.value = 'day';
     } else inclusionType.value = 'indefinitely';
@@ -126,6 +171,7 @@ onMounted(() => {
                     data-cy="ZoneEventInclusionDayRadio"
                 />
                 <QRadio
+                    v-if="!props.isMasiveEdit"
                     v-model="inclusionType"
                     dense
                     val="indefinitely"
@@ -133,6 +179,7 @@ onMounted(() => {
                     data-cy="ZoneEventInclusionIndefinitelyRadio"
                 />
                 <QRadio
+                    v-if="!props.isMasiveEdit"
                     v-model="inclusionType"
                     dense
                     val="range"
@@ -159,12 +206,10 @@ onMounted(() => {
                 <VnInputDate
                     :label="t('eventsInclusionForm.from')"
                     v-model="eventInclusionFormData.started"
-                    data-cy="ZoneEventsFromDate"
                 />
                 <VnInputDate
                     :label="t('eventsInclusionForm.to')"
                     v-model="eventInclusionFormData.ended"
-                    data-cy="ZoneEventsToDate"
                 />
             </VnRow>
             <VnRow>
diff --git a/src/pages/Zone/Card/ZoneEvents.vue b/src/pages/Zone/Card/ZoneEvents.vue
index 1e6debd25..2fa7dfb43 100644
--- a/src/pages/Zone/Card/ZoneEvents.vue
+++ b/src/pages/Zone/Card/ZoneEvents.vue
@@ -1,18 +1,14 @@
 <script setup>
-import { ref } from 'vue';
+import { ref, reactive } from 'vue';
 import { useI18n } from 'vue-i18n';
 
 import ZoneEventsPanel from './ZoneEventsPanel.vue';
 import ZoneCalendarGrid from '../ZoneCalendarGrid.vue';
 import ZoneEventInclusionForm from './ZoneEventInclusionForm.vue';
 import ZoneEventExclusionForm from './ZoneEventExclusionForm.vue';
-
-import { useStateStore } from 'stores/useStateStore';
-import { reactive } from 'vue';
+import RightMenu from 'src/components/common/RightMenu.vue';
 
 const { t } = useI18n();
-const stateStore = useStateStore();
-
 const firstDay = ref();
 const lastDay = ref();
 
@@ -43,14 +39,16 @@ const onZoneEventFormClose = () => {
 </script>
 
 <template>
-    <Teleport to="#right-panel" v-if="stateStore.isHeaderMounted()">
-        <ZoneEventsPanel
-            :first-day="firstDay"
-            :last-day="lastDay"
-            :events="events"
-            v-model:formModeName="formModeName"
-        />
-    </Teleport>
+    <RightMenu>
+        <template #right-panel>
+            <ZoneEventsPanel
+                :first-day="firstDay"
+                :last-day="lastDay"
+                :events="events"
+                v-model:formModeName="formModeName"
+            />
+        </template>
+    </RightMenu>
     <QPage class="q-pa-md flex justify-center">
         <ZoneCalendarGrid
             v-model:events="events"
diff --git a/src/pages/Zone/Card/ZoneEventsPanel.vue b/src/pages/Zone/Card/ZoneEventsPanel.vue
index bb8c15934..82b34e3a2 100644
--- a/src/pages/Zone/Card/ZoneEventsPanel.vue
+++ b/src/pages/Zone/Card/ZoneEventsPanel.vue
@@ -14,12 +14,10 @@ import { useVnConfirm } from 'composables/useVnConfirm';
 const props = defineProps({
     firstDay: {
         type: Date,
-        required: true,
         default: null,
     },
     lastDay: {
         type: Date,
-        required: true,
         default: null,
     },
     events: {
@@ -67,7 +65,7 @@ watch(
     async () => {
         await fetchData();
     },
-    { immediate: true, deep: true }
+    { immediate: true, deep: true },
 );
 
 const formatWdays = (event) => {
@@ -178,9 +176,10 @@ onMounted(async () => {
                             openConfirmationModal(
                                 t('zone.deleteTitle'),
                                 t('zone.deleteSubtitle'),
-                                () => deleteEvent(event.id)
+                                () => deleteEvent(event.id),
                             )
                         "
+                        data-cy="ZoneEventsPanelDeleteBtn"
                     >
                         <QTooltip>{{ t('eventsPanel.delete') }}</QTooltip>
                     </QBtn>
diff --git a/src/pages/Zone/Card/ZoneLocations.vue b/src/pages/Zone/Card/ZoneLocations.vue
index 08b99df60..add9f6f5b 100644
--- a/src/pages/Zone/Card/ZoneLocations.vue
+++ b/src/pages/Zone/Card/ZoneLocations.vue
@@ -34,9 +34,10 @@ const onSelected = async (val, node) => {
                             node.selected
                                 ? '--checked'
                                 : node.selected == false
-                                ? '--unchecked'
-                                : '--indeterminate',
+                                  ? '--unchecked'
+                                  : '--indeterminate',
                         ]"
+                        data-cy="ZoneLocationTreeCheckbox"
                     />
                 </template>
             </ZoneLocationsTree>
diff --git a/src/pages/Zone/Card/ZoneLocationsTree.vue b/src/pages/Zone/Card/ZoneLocationsTree.vue
index 5c87faf99..d5d7d52b6 100644
--- a/src/pages/Zone/Card/ZoneLocationsTree.vue
+++ b/src/pages/Zone/Card/ZoneLocationsTree.vue
@@ -1,6 +1,7 @@
 <script setup>
 import { onMounted, ref, computed, watch, onUnmounted } from 'vue';
 import { useRoute } from 'vue-router';
+import { useStateStore } from 'stores/useStateStore';
 import VnInput from 'src/components/common/VnInput.vue';
 import { useState } from 'src/composables/useState';
 import axios from 'axios';
@@ -30,7 +31,7 @@ const emit = defineEmits(['update:tickedNodes']);
 
 const route = useRoute();
 const state = useState();
-
+const stateStore = useStateStore();
 const treeRef = ref();
 const expanded = ref([]);
 
@@ -72,6 +73,7 @@ const onNodeExpanded = async (nodeKeysArray) => {
         const response = await axios.get(`Zones/${route.params.id}/getLeaves`, {
             params,
         });
+        response.data = JSON.parse(response.data);
         if (response.data) {
             node.childs = response.data.map((n) => {
                 if (n.sons > 0) n.childs = [{}];
@@ -82,7 +84,7 @@ const onNodeExpanded = async (nodeKeysArray) => {
         await fetchNodeLeaves(lastNodeKey, true);
     } else {
         const difference = new Set(
-            [...previousExpandedNodes.value].filter((x) => !nodeKeysSet.has(x))
+            [...previousExpandedNodes.value].filter((x) => !nodeKeysSet.has(x)),
         );
         const collapsedNode = Array.from(difference).pop();
         const node = treeRef.value?.getNodeByKey(collapsedNode);
@@ -125,17 +127,20 @@ watch(
     async (val) => {
         if (!val) return;
         // // Se triggerea cuando se actualiza el store.data, el cual es el resultado del fetch de la searchbar
+        val = JSON.parse(val);
         if (!nodes.value[0]) nodes.value = [defaultNode];
         nodes.value[0].childs = [...val];
         const fetchedNodeKeys = val.flatMap(getNodeIds);
         state.set('Tree', [...fetchedNodeKeys]);
         expanded.value = [null, ...fetchedNodeKeys];
+        const fetchs = [];
         for (let n of state.get('Tree')) {
-            await fetchNodeLeaves(n);
+            fetchs.push(fetchNodeLeaves(n));
         }
+        await Promise.all(fetchs);
         previousExpandedNodes.value = new Set(expanded.value);
     },
-    { immediate: true }
+    { immediate: true },
 );
 
 const reFetch = async () => {
@@ -153,6 +158,17 @@ onUnmounted(() => {
 </script>
 
 <template>
+    <Teleport to="#section-searchbar" v-if="stateStore.isHeaderMounted()">
+        <VnSearchbar
+            v-if="!showSearchBar"
+            :data-key="datakey"
+            :url="url"
+            :redirect="false"
+            :search-remove-params="false"
+            :label="$t('zone.searchLocations')"
+            :info="$t('zone.searchLocationsInfo')"
+        />
+    </Teleport>
     <VnInput
         v-if="showSearchBar"
         v-model="store.userParams.search"
@@ -163,13 +179,6 @@ onUnmounted(() => {
             <QBtn color="primary" icon="search" dense flat @click="reFetch()" />
         </template>
     </VnInput>
-    <VnSearchbar
-        v-if="!showSearchBar"
-        :data-key="datakey"
-        :url="url"
-        :redirect="false"
-        :search-remove-params="false"
-    />
     <QTree
         ref="treeRef"
         :nodes="nodes"
diff --git a/src/pages/Zone/Card/ZoneLog.vue b/src/pages/Zone/Card/ZoneLog.vue
index 373d210b5..99ea0912f 100644
--- a/src/pages/Zone/Card/ZoneLog.vue
+++ b/src/pages/Zone/Card/ZoneLog.vue
@@ -2,5 +2,5 @@
 import VnLog from 'src/components/common/VnLog.vue';
 </script>
 <template>
-    <VnLog model="Zone" url="/ZoneLogs"></VnLog>
+    <VnLog model="Zone" />
 </template>
diff --git a/src/pages/Zone/Card/ZoneSearchbar.vue b/src/pages/Zone/Card/ZoneSearchbar.vue
deleted file mode 100644
index d1188a1e8..000000000
--- a/src/pages/Zone/Card/ZoneSearchbar.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-<script setup>
-import { useI18n } from 'vue-i18n';
-import VnSearchbar from 'components/ui/VnSearchbar.vue';
-
-const { t } = useI18n();
-
-const exprBuilder = (param, value) => {
-    switch (param) {
-        case 'name':
-            return {
-                name: { like: `%${value}%` },
-            };
-        case 'code':
-            return {
-                code: { like: `%${value}%` },
-            };
-        case 'agencyModeFk':
-            return {
-                agencyModeFk: value,
-            };
-        case 'search':
-            return /^\d+$/.test(value) ? { id: value } : { name: { like: `%${value}%` } };
-    }
-};
-
-const tableFilter = {
-    include: [
-        {
-            relation: 'agencyMode',
-            scope: {
-                fields: ['id', 'name'],
-            },
-        },
-        {
-            relation: 'address',
-            scope: {
-                fields: ['id', 'nickname', 'provinceFk', 'postalCode'],
-                include: [
-                    {
-                        relation: 'province',
-                        scope: {
-                            fields: ['id', 'name'],
-                        },
-                    },
-                    {
-                        relation: 'postcode',
-                        scope: {
-                            fields: ['code', 'townFk'],
-                            include: {
-                                relation: 'town',
-                                scope: {
-                                    fields: ['id', 'name'],
-                                },
-                            },
-                        },
-                    },
-                ],
-            },
-        },
-    ],
-};
-</script>
-
-<template>
-    <VnSearchbar
-        data-key="ZonesList"
-        url="Zones"
-        :filter="tableFilter"
-        :expr-builder="exprBuilder"
-        :label="t('list.searchZone')"
-        :info="t('list.searchInfo')"
-        custom-route-redirect-name="ZoneSummary"
-    />
-</template>
diff --git a/src/pages/Zone/Card/ZoneSummary.vue b/src/pages/Zone/Card/ZoneSummary.vue
index 5b29b495b..5958fe27a 100644
--- a/src/pages/Zone/Card/ZoneSummary.vue
+++ b/src/pages/Zone/Card/ZoneSummary.vue
@@ -60,10 +60,11 @@ onMounted(async () => {
 
 <template>
     <CardSummary
-        data-key="Zone"
+        data-key="ZoneSummary"
         ref="summary"
         :url="`Zones/${entityId}`"
         :filter="filter"
+        :entity-id="entityId"
     >
         <template #header="{ entity }">
             <div>#{{ entity.id }} - {{ entity.name }}</div>
@@ -74,21 +75,30 @@ onMounted(async () => {
         <template #body="{ entity: zone }">
             <QCard class="vn-one">
                 <VnTitle :url="zoneUrl + `basic-data`" :text="t('summary.basicData')" />
-                <VnLv :label="t('list.agency')" :value="zone.agencyMode?.name" />
-                <VnLv :label="t('list.price')" :value="toCurrency(zone.price)" />
-                <VnLv :label="t('zone.bonus')" :value="toCurrency(zone.bonus)" />
+                <div class="vn-card-group">
+                    <div class="vn-card-content">
+                        <VnLv :label="t('list.agency')" :value="zone.agencyMode?.name" />
+                        <VnLv :label="t('list.price')" :value="toCurrency(zone.price)" />
+                        <VnLv :label="t('zone.bonus')" :value="toCurrency(zone.bonus)" />
+                    </div>
+                    <div class="vn-card-content">
+                        <VnLv
+                            :label="t('summary.closeHour')"
+                            :value="toTimeFormat(zone.hour)"
+                        />
+                        <VnLv
+                            :label="t('zone.travelingDays')"
+                            :value="zone.travelingDays"
+                        />
+                        <QCheckbox
+                            :label="t('zone.volumetric')"
+                            v-model="zone.isVolumetric"
+                            :disable="true"
+                        />
+                    </div>
+                </div>
             </QCard>
-            <QCard class="vn-one">
-                <VnTitle :url="zoneUrl + `basic-data`" :text="t('summary.basicData')" />
-                <VnLv :label="t('summary.closeHour')" :value="toTimeFormat(zone.hour)" />
-                <VnLv :label="t('zone.travelingDays')" :value="zone.travelingDays" />
-                <QCheckbox
-                    :label="t('zone.volumetric')"
-                    v-model="zone.isVolumetric"
-                    :disable="true"
-                />
-            </QCard>
-            <QCard class="full-width">
+            <QCard class="vn-max">
                 <VnTitle :url="zoneUrl + `warehouses`" :text="t('list.warehouse')" />
                 <QTable
                     :columns="columns"
diff --git a/src/pages/Zone/ZoneCalendarGrid.vue b/src/pages/Zone/ZoneCalendarGrid.vue
index 91d2cc7eb..1ef687b3f 100644
--- a/src/pages/Zone/ZoneCalendarGrid.vue
+++ b/src/pages/Zone/ZoneCalendarGrid.vue
@@ -42,7 +42,7 @@ const refreshEvents = () => {
     days.value = {};
     if (!data.value) return;
 
-    let day = new Date(firstDay.value.getTime());
+    let day = new Date(firstDay?.value?.getTime());
 
     while (day <= lastDay.value) {
         let stamp = day.getTime();
@@ -156,7 +156,7 @@ watch(
     (value) => {
         data.value = value;
     },
-    { immediate: true }
+    { immediate: true },
 );
 
 const getMonthNameAndYear = (date) => {
diff --git a/src/pages/Zone/ZoneDeliveryDays.vue b/src/pages/Zone/ZoneDeliveryDays.vue
index d95c64d8b..ddde3f6b3 100644
--- a/src/pages/Zone/ZoneDeliveryDays.vue
+++ b/src/pages/Zone/ZoneDeliveryDays.vue
@@ -3,7 +3,6 @@ import { ref } from 'vue';
 import ZoneDeliveryPanel from './ZoneDeliveryPanel.vue';
 import ZoneCalendarGrid from './ZoneCalendarGrid.vue';
 import RightMenu from 'src/components/common/RightMenu.vue';
-import ZoneSearchbar from './Card/ZoneSearchbar.vue';
 
 const firstDay = ref(null);
 const lastDay = ref(null);
@@ -11,7 +10,6 @@ const events = ref([]);
 </script>
 
 <template>
-    <ZoneSearchbar />
     <RightMenu>
         <template #right-panel>
             <ZoneDeliveryPanel />
diff --git a/src/pages/Zone/ZoneDeliveryPanel.vue b/src/pages/Zone/ZoneDeliveryPanel.vue
index 993ec274f..fc5c04b41 100644
--- a/src/pages/Zone/ZoneDeliveryPanel.vue
+++ b/src/pages/Zone/ZoneDeliveryPanel.vue
@@ -89,14 +89,13 @@ watch(
                 v-model="formData.geoFk"
                 url="Postcodes/location"
                 :fields="['geoFk', 'code', 'townFk', 'countryFk']"
-                :sort-by="['code ASC']"
+                :sort-by="'code ASC'"
                 option-value="geoFk"
                 option-label="code"
                 :filter-options="['code']"
                 hide-selected
                 dense
-                outlined
-                rounded
+                filled
                 map-key="geoFk"
                 data-cy="ZoneDeliveryDaysPostcodeSelect"
             >
@@ -128,8 +127,7 @@ watch(
                 option-label="name"
                 hide-selected
                 dense
-                outlined
-                rounded
+                filled
                 data-cy="ZoneDeliveryDaysAgencySelect"
             />
             <VnSelect
@@ -144,7 +142,6 @@ watch(
                 option-label="name"
                 hide-selected
                 dense
-                outlined
                 rounded
             />
         </div>
diff --git a/src/pages/Zone/ZoneFilterPanel.vue b/src/pages/Zone/ZoneFilterPanel.vue
deleted file mode 100644
index ff65479e4..000000000
--- a/src/pages/Zone/ZoneFilterPanel.vue
+++ /dev/null
@@ -1,69 +0,0 @@
-<script setup>
-import { ref } from 'vue';
-import { useI18n } from 'vue-i18n';
-import VnInput from 'components/common/VnInput.vue';
-import FetchData from 'components/FetchData.vue';
-import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
-import VnSelect from 'components/common/VnSelect.vue';
-import order from 'src/router/modules/order';
-
-const { t } = useI18n();
-const props = defineProps({
-    dataKey: {
-        type: String,
-        required: true,
-    },
-    exprBuilder: {
-        type: Function,
-        default: null,
-    },
-});
-
-const agencies = ref([]);
-</script>
-
-<template>
-    <FetchData
-        url="AgencyModes"
-        :filter="{ fields: ['id', 'name'], order: ['name ASC'] }"
-        @on-fetch="(data) => (agencies = data)"
-        auto-load
-    />
-    <VnFilterPanel :data-key="props.dataKey" :search-button="true">
-        <template #tags="{ tag }">
-            <div class="q-gutter-x-xs">
-                <strong>{{ t(`filterPanel.${tag.label}`) }}: </strong>
-                <span>{{ tag.value }}</span>
-            </div>
-        </template>
-        <template #body="{ params, searchFn }">
-            <QItem>
-                <QItemSection>
-                    <VnInput
-                        :label="t('list.name')"
-                        v-model="params.name"
-                        is-outlined
-                        data-cy="zoneFilterPanelNameInput"
-                    />
-                </QItemSection>
-            </QItem>
-            <QItem>
-                <QItemSection>
-                    <VnSelect
-                        :label="t('filterPanel.agencyModeFk')"
-                        v-model="params.agencyModeFk"
-                        :options="agencies"
-                        option-value="id"
-                        option-label="name"
-                        @update:model-value="searchFn()"
-                        dense
-                        outlined
-                        rounded
-                        data-cy="zoneFilterPanelAgencySelect"
-                    >
-                    </VnSelect>
-                </QItemSection>
-            </QItem>
-        </template>
-    </VnFilterPanel>
-</template>
diff --git a/src/pages/Zone/ZoneList.vue b/src/pages/Zone/ZoneList.vue
index eb54ec15b..8d7c4a165 100644
--- a/src/pages/Zone/ZoneList.vue
+++ b/src/pages/Zone/ZoneList.vue
@@ -14,9 +14,11 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import VnInputTime from 'src/components/common/VnInputTime.vue';
-import RightMenu from 'src/components/common/RightMenu.vue';
-import ZoneFilterPanel from './ZoneFilterPanel.vue';
-import ZoneSearchbar from './Card/ZoneSearchbar.vue';
+
+import VnSection from 'src/components/common/VnSection.vue';
+import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
+import ZoneEventInclusionForm from './Card/ZoneEventInclusionForm.vue';
+import ZoneEventExclusionForm from './Card/ZoneEventExclusionForm.vue';
 
 const { t } = useI18n();
 const router = useRouter();
@@ -25,7 +27,12 @@ const { viewSummary } = useSummaryDialog();
 const { openConfirmationModal } = useVnConfirm();
 const tableRef = ref();
 const warehouseOptions = ref([]);
-
+const dataKey = 'ZoneList';
+const selectedRows = ref([]);
+const hasSelectedRows = computed(() => selectedRows.value.length > 0);
+const openInclusionForm = ref();
+const showZoneEventForm = ref(false);
+const zoneIds = ref({});
 const tableFilter = {
     include: [
         {
@@ -114,6 +121,7 @@ const columns = computed(() => [
         columnFilter: {
             inWhere: true,
         },
+        columnClass: 'shrink-column',
     },
     {
         align: 'left',
@@ -169,77 +177,180 @@ function formatRow(row) {
     return dashIfEmpty(`${row?.address?.nickname},
             ${row?.address?.postcode?.town?.name} (${row?.address?.province?.name})`);
 }
+
+const exprBuilder = (param, value) => {
+    switch (param) {
+        case 'name':
+            return {
+                name: { like: `%${value}%` },
+            };
+        case 'code':
+            return {
+                code: { like: `%${value}%` },
+            };
+        case 'agencyModeFk':
+            return {
+                agencyModeFk: value,
+            };
+        case 'search':
+            return /^\d+$/.test(value) ? { id: value } : { name: { like: `%${value}%` } };
+        case 'price':
+            return {
+                price: value,
+            };
+    }
+};
+
+function openForm(value, rows) {
+    zoneIds.value = rows.map((row) => row.id);
+    openInclusionForm.value = value;
+    showZoneEventForm.value = true;
+}
+
+const closeEventForm = () => {
+    showZoneEventForm.value = false;
+};
 </script>
 
 <template>
-    <ZoneSearchbar />
-    <RightMenu>
-        <template #right-panel>
-            <ZoneFilterPanel data-key="ZonesList" />
-        </template>
-    </RightMenu>
-    <VnTable
-        ref="tableRef"
-        data-key="ZonesList"
-        url="Zones"
-        :create="{
-            urlCreate: 'Zones',
-            title: t('list.createZone'),
-            onDataSaved: ({ id }) => tableRef.redirect(`${id}/location`),
-            formInitialData: {},
-        }"
-        :user-filter="tableFilter"
+    <VnSection
+        :data-key="dataKey"
         :columns="columns"
-        redirect="zone"
-        :right-search="false"
+        prefix="zone"
+        :array-data-props="{
+            url: 'Zones',
+            order: ['id ASC'],
+            userFilter: tableFilter,
+            exprBuilder,
+        }"
     >
-        <template #column-addressFk="{ row }">
-            {{ dashIfEmpty(formatRow(row)) }}
+        <template #body>
+            <VnSubToolbar>
+                <template #st-actions>
+                    <QBtnGroup style="column-gap: 10px">
+                        <QBtn
+                            color="primary"
+                            icon-right="event_available"
+                            :disable="!hasSelectedRows"
+                            @click="openForm(true, selectedRows)"
+                        >
+                            <QTooltip>{{ t('list.includeEvent') }}</QTooltip>
+                        </QBtn>
+                        <QBtn
+                            color="primary"
+                            icon-right="event_busy"
+                            :disable="!hasSelectedRows"
+                            @click="openForm(false, selectedRows)"
+                        >
+                            <QTooltip>{{ t('list.excludeEvent') }}</QTooltip>
+                        </QBtn>
+                    </QBtnGroup>
+                </template>
+            </VnSubToolbar>
+            <div class="table-container">
+                <div class="column items-center">
+                    <VnTable
+                        ref="tableRef"
+                        :data-key="dataKey"
+                        :columns="columns"
+                        redirect="Zone"
+                        :create="{
+                            urlCreate: 'Zones',
+                            title: t('list.createZone'),
+                            onDataSaved: ({ id }) => tableRef.redirect(`${id}/location`),
+                            formInitialData: {},
+                        }"
+                        table-height="85vh"
+                        v-model:selected="selectedRows"
+                        :table="{
+                            'row-key': 'id',
+                            selection: 'multiple',
+                        }"
+                    >
+                        <template #column-addressFk="{ row }">
+                            {{ dashIfEmpty(formatRow(row)) }}
+                        </template>
+                        <template #more-create-dialog="{ data }">
+                            <VnSelect
+                                url="AgencyModes"
+                                v-model="data.agencyModeFk"
+                                option-value="id"
+                                option-label="name"
+                                :label="t('list.agency')"
+                            />
+                            <VnInput
+                                v-model="data.price"
+                                :label="t('list.price')"
+                                min="0"
+                                type="number"
+                                required="true"
+                            />
+                            <VnInput
+                                v-model="data.bonus"
+                                :label="t('zone.bonus')"
+                                min="0"
+                                type="number"
+                            />
+                            <VnInput
+                                v-model="data.travelingDays"
+                                :label="t('zone.travelingDays')"
+                                type="number"
+                                min="0"
+                            />
+                            <VnInputTime v-model="data.hour" :label="t('list.close')" />
+                            <VnSelect
+                                url="Warehouses"
+                                v-model="data.warehouseFK"
+                                option-value="id"
+                                option-label="name"
+                                :label="t('list.warehouse')"
+                                :options="warehouseOptions"
+                            />
+                            <QCheckbox
+                                v-model="data.isVolumetric"
+                                :label="t('list.isVolumetric')"
+                                :toggle-indeterminate="false"
+                            />
+                        </template>
+                    </VnTable>
+                </div>
+            </div>
         </template>
-        <template #more-create-dialog="{ data }">
-            <VnSelect
-                url="AgencyModes"
-                sort-by="name ASC"
-                v-model="data.agencyModeFk"
-                :label="t('list.agency')"
-            />
-            <VnInput
-                v-model="data.price"
-                :label="t('list.price')"
-                min="0"
-                type="number"
-                required="true"
-            />
-            <VnInput
-                v-model="data.bonus"
-                :label="t('zone.bonus')"
-                min="0"
-                type="number"
-            />
-            <VnInput
-                v-model="data.travelingDays"
-                :label="t('zone.travelingDays')"
-                type="number"
-                min="0"
-            />
-            <VnInputTime v-model="data.hour" :label="t('list.close')" />
-            <VnSelect
-                url="Warehouses"
-                v-model="data.warehouseFK"
-                option-value="id"
-                option-label="name"
-                :label="t('list.warehouse')"
-                :options="warehouseOptions"
-            />
-            <QCheckbox
-                v-model="data.isVolumetric"
-                :label="t('list.isVolumetric')"
-                :toggle-indeterminate="false"
-            />
-        </template>
-    </VnTable>
+    </VnSection>
+    <QDialog v-model="showZoneEventForm" @hide="closeEventForm()">
+        <ZoneEventInclusionForm
+            v-if="openInclusionForm"
+            :event="'event'"
+            :is-masive-edit="true"
+            :zone-ids="zoneIds"
+            @close-form="closeEventForm"
+        />
+        <ZoneEventExclusionForm
+            v-else
+            :zone-ids="zoneIds"
+            :is-masive-edit="true"
+            @close-form="closeEventForm"
+        />
+    </QDialog>
 </template>
 
+<style lang="scss" scoped>
+.table-container {
+    display: flex;
+    justify-content: center;
+}
+.column {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    min-width: 70%;
+}
+
+:deep(.shrink-column) {
+    width: 8%;
+}
+</style>
+
 <i18n>
 es:
     Search zone: Buscar zona
diff --git a/src/pages/Zone/ZoneUpcoming.vue b/src/pages/Zone/ZoneUpcoming.vue
index adcdfbc04..b8664dc2f 100644
--- a/src/pages/Zone/ZoneUpcoming.vue
+++ b/src/pages/Zone/ZoneUpcoming.vue
@@ -7,7 +7,6 @@ import FetchData from 'components/FetchData.vue';
 
 import { toDateFormat } from 'src/filters/date.js';
 import { useWeekdayStore } from 'src/stores/useWeekdayStore';
-import ZoneSearchbar from './Card/ZoneSearchbar.vue';
 
 const { t } = useI18n();
 const weekdayStore = useWeekdayStore();
@@ -31,7 +30,7 @@ const columns = computed(() => [
         label: t('list.id'),
         name: 'id',
         field: 'zoneFk',
-        align: 'left',
+        align: 'center',
     },
 ]);
 
@@ -53,7 +52,6 @@ onMounted(() => weekdayStore.initStore());
         @on-fetch="(data) => (details = data)"
         auto-load
     />
-    <ZoneSearchbar />
     <VnSubToolbar />
     <QPage class="column items-center q-pa-md">
         <QCard class="containerShrinked q-pa-md">
diff --git a/src/pages/Zone/locale/en.yml b/src/pages/Zone/locale/en.yml
index e53e7b560..f46a98ee6 100644
--- a/src/pages/Zone/locale/en.yml
+++ b/src/pages/Zone/locale/en.yml
@@ -11,10 +11,13 @@ zone:
     m3Max: Max m³
     deleteTitle: This item will be deleted
     deleteSubtitle: Are you sure you want to continue?
-    volumetric: Volumetric
     bonus: Bonus
     closing: Closing
     travelingDays: Traveling days
+    search: Search zone
+    searchInfo: Search zone by id or name
+    searchLocations: Search locations
+    searchLocationsInfo: Search locations by post code
 list:
     clone: Clone
     id: Id
@@ -22,6 +25,7 @@ list:
     agency: Agency
     close: Close
     price: Price
+    priceOptimum: Optimal price
     create: Create zone
     openSummary: Details
     searchZone: Search zones
@@ -30,9 +34,12 @@ list:
     confirmCloneTitle: All it's properties will be copied
     confirmCloneSubtitle: Do you want to clone this zone?
     warehouse: Warehouse
+    isVolumetric: Volumetric
     createZone: Create zone
     zoneSummary: Summary
     addressFk: Address
+    includeEvent: Include event
+    excludeEvent: Exclude event
 create:
     name: Name
     closingHour: Closing hour
diff --git a/src/pages/Zone/locale/es.yml b/src/pages/Zone/locale/es.yml
index bc31e74a9..7a23bdc02 100644
--- a/src/pages/Zone/locale/es.yml
+++ b/src/pages/Zone/locale/es.yml
@@ -15,6 +15,10 @@ zone:
     bonus: Bonificación
     closing: Cierre
     travelingDays: Días de viaje
+    search: Buscar zona
+    searchInfo: Buscar zona por Id o nombre
+    searchLocations: Buscar localización
+    searchLocationsInfo: Buscar localización por código postal
 list:
     clone: Clonar
     id: Id
@@ -35,6 +39,8 @@ list:
     createZone: Crear zona
     zoneSummary: Resumen
     addressFk: Consignatario
+    includeEvent: Incluir evento
+    excludeEvent: Excluir evento
 create:
     closingHour: Hora de cierre
     itemMaxSize: Medida máxima
diff --git a/src/router/__tests__/hooks.spec.js b/src/router/__tests__/hooks.spec.js
new file mode 100644
index 000000000..97f5eacdc
--- /dev/null
+++ b/src/router/__tests__/hooks.spec.js
@@ -0,0 +1,36 @@
+import { describe, it, expect, vi } from 'vitest';
+import { ref, nextTick } from 'vue';
+import { stateQueryGuard } from 'src/router/hooks';
+import { useStateQueryStore } from 'src/stores/useStateQueryStore';
+
+vi.mock('src/stores/useStateQueryStore', () => {
+    const isLoading = ref(true);
+    return {
+        useStateQueryStore: () => ({
+            isLoading: () => isLoading,
+            setLoading: isLoading,
+        }),
+    };
+});
+
+describe('hooks', () => {
+    describe('stateQueryGuard', () => {
+        const foo = { name: 'foo' };
+        it('should wait until the state query is not loading and then call next()', async () => {
+            const next = vi.fn();
+
+            stateQueryGuard(foo, { name: 'bar' }, next);
+            expect(next).not.toHaveBeenCalled();
+
+            useStateQueryStore().setLoading.value = false;
+            await nextTick();
+            expect(next).toHaveBeenCalled();
+        });
+
+        it('should ignore if both routes are the same', () => {
+            const next = vi.fn();
+            stateQueryGuard(foo, foo, next);
+            expect(next).toHaveBeenCalled();
+        });
+    });
+});
diff --git a/src/router/hooks.js b/src/router/hooks.js
new file mode 100644
index 000000000..bd9e5334f
--- /dev/null
+++ b/src/router/hooks.js
@@ -0,0 +1,95 @@
+import { useRole } from 'src/composables/useRole';
+import { useUserConfig } from 'src/composables/useUserConfig';
+import { useTokenConfig } from 'src/composables/useTokenConfig';
+import { useAcl } from 'src/composables/useAcl';
+import { isLoggedIn } from 'src/utils/session';
+import { useSession } from 'src/composables/useSession';
+import { useStateQueryStore } from 'src/stores/useStateQueryStore';
+import { watch } from 'vue';
+import { i18n } from 'src/boot/i18n';
+
+let session = null;
+const { t, te } = i18n.global;
+
+export async function navigationGuard(to, from, next, Router, state) {
+    if (!session) session = useSession();
+    const outLayout = Router.options.routes[0].children.map((r) => r.name);
+    if (!session.isLoggedIn() && !outLayout.includes(to.name)) {
+        return next({ name: 'Login', query: { redirect: to.fullPath } });
+    }
+
+    if (isLoggedIn()) {
+        const stateRoles = state.getRoles().value;
+        if (stateRoles.length === 0) {
+            await useRole().fetch();
+            await useAcl().fetch();
+            await useUserConfig().fetch();
+            await useTokenConfig().fetch();
+        }
+        const matches = to.matched;
+        const hasRequiredAcls = matches.every((route) => {
+            const meta = route.meta;
+            if (!meta?.acls) return true;
+            return useAcl().hasAny(meta.acls);
+        });
+        if (!hasRequiredAcls) return next({ path: '/' });
+    }
+
+    next();
+}
+
+export async function stateQueryGuard(to, from, next) {
+    if (to.name !== from.name) {
+        const stateQuery = useStateQueryStore();
+        await waitUntilFalse(stateQuery.isLoading());
+    }
+
+    next();
+}
+
+export function setPageTitle(to) {
+    let title = t(`login.title`);
+
+    const matches = to.matched;
+    if (matches && matches.length > 1) {
+        const module = matches[1];
+        const moduleTitle = module.meta?.title;
+        if (moduleTitle) {
+            title = t(`globals.pageTitles.${moduleTitle}`);
+        }
+    }
+
+    const childPage = to.meta;
+    const childPageTitle = childPage?.title;
+    if (childPageTitle && matches.length > 2) {
+        if (title != '') title += ': ';
+
+        const moduleLocale = `globals.pageTitles.${childPageTitle}`;
+        const pageTitle = te(moduleLocale)
+            ? t(moduleLocale)
+            : t(`globals.pageTitles.${childPageTitle}`);
+        const idParam = to.params?.id;
+        const idPageTitle = `${idParam} - ${pageTitle}`;
+        const builtTitle = idParam ? idPageTitle : pageTitle;
+
+        title += builtTitle;
+    }
+
+    document.title = title;
+}
+
+function waitUntilFalse(ref) {
+    return new Promise((resolve) => {
+        if (!ref.value) return resolve();
+        const stop = watch(
+            ref,
+            (val) => {
+                if (!val) {
+                    stop();
+                    resolve();
+                }
+            },
+            { immediate: true },
+        );
+    });
+}
diff --git a/src/router/index.js b/src/router/index.js
index 4403901cb..628a53c8e 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -6,101 +6,25 @@ import {
     createWebHashHistory,
 } from 'vue-router';
 import routes from './routes';
-import { i18n } from 'src/boot/i18n';
 import { useState } from 'src/composables/useState';
-import { useRole } from 'src/composables/useRole';
-import { useUserConfig } from 'src/composables/useUserConfig';
-import { useTokenConfig } from 'src/composables/useTokenConfig';
-import { useAcl } from 'src/composables/useAcl';
-import { isLoggedIn } from 'src/utils/session';
-import { useSession } from 'src/composables/useSession';
+import { navigationGuard, setPageTitle, stateQueryGuard } from './hooks';
 
-let session = null;
-const { t, te } = i18n.global;
-
-const createHistory = process.env.SERVER
-    ? createMemoryHistory
-    : process.env.VUE_ROUTER_MODE === 'history'
-      ? createWebHistory
-      : createWebHashHistory;
+const webHistory =
+    process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory;
+const createHistory = process.env.SERVER ? createMemoryHistory : webHistory;
 
 const Router = createRouter({
     scrollBehavior: () => ({ left: 0, top: 0 }),
     routes,
-
-    // Leave this as is and make changes in quasar.conf.js instead!
-    // quasar.conf.js -> build -> vueRouterMode
-    // quasar.conf.js -> build -> publicPath
     history: createHistory(process.env.VUE_ROUTER_BASE),
 });
 
-/*
- * If not building with SSR mode, you can
- * directly export the Router instantiation;
- *
- * The function below can be async too; either use
- * async/await or return a Promise which resolves
- * with the Router instance.
- */
 export { Router };
-export default defineRouter(function (/* { store, ssrContext } */) {
+export default defineRouter(() => {
     const state = useState();
-    Router.beforeEach(async (to, from, next) => {
-        if (!session) session = useSession();
-        const outLayout = Router.options.routes[0].children.map((r) => r.name);
-        if (!session.isLoggedIn() && !outLayout.includes(to.name)) {
-            return next({ name: 'Login', query: { redirect: to.fullPath } });
-        }
-
-        if (isLoggedIn()) {
-            const stateRoles = state.getRoles().value;
-            if (stateRoles.length === 0) {
-                await useRole().fetch();
-                await useAcl().fetch();
-                await useUserConfig().fetch();
-                await useTokenConfig().fetch();
-            }
-            const matches = to.matched;
-            const hasRequiredAcls = matches.every((route) => {
-                const meta = route.meta;
-                if (!meta?.acls) return true;
-                return useAcl().hasAny(meta.acls);
-            });
-            if (!hasRequiredAcls) return next({ path: '/' });
-        }
-
-        next();
-    });
-
-    Router.afterEach((to) => {
-        let title = t(`login.title`);
-
-        const matches = to.matched;
-        if (matches && matches.length > 1) {
-            const module = matches[1];
-            const moduleTitle = module.meta && module.meta.title;
-            if (moduleTitle) {
-                title = t(`globals.pageTitles.${moduleTitle}`);
-            }
-        }
-
-        const childPage = to.meta;
-        const childPageTitle = childPage && childPage.title;
-        if (childPageTitle && matches.length > 2) {
-            if (title != '') title += ': ';
-
-            const moduleLocale = `globals.pageTitles.${childPageTitle}`;
-            const pageTitle = te(moduleLocale)
-                ? t(moduleLocale)
-                : t(`globals.pageTitles.${childPageTitle}`);
-            const idParam = to.params && to.params.id;
-            const idPageTitle = `${idParam} - ${pageTitle}`;
-            const builtTitle = idParam ? idPageTitle : pageTitle;
-
-            title += builtTitle;
-        }
-        document.title = title;
-    });
+    Router.beforeEach((to, from, next) => navigationGuard(to, from, next, Router, state));
+    Router.beforeEach(stateQueryGuard);
+    Router.afterEach(setPageTitle);
 
     Router.onError(({ message }) => {
         const errorMessages = [
diff --git a/src/router/modules/customer.js b/src/router/modules/customer.js
index 67b00b161..a33ed6be5 100644
--- a/src/router/modules/customer.js
+++ b/src/router/modules/customer.js
@@ -4,8 +4,8 @@ const customerCard = {
     name: 'CustomerCard',
     path: ':id',
     component: () => import('src/pages/Customer/Card/CustomerCard.vue'),
-    redirect: { name: 'CustomerSummary' },                                           
-    meta: { 
+    redirect: { name: 'CustomerSummary' },
+    meta: {
         menu: [
             'CustomerBasicData',
             'CustomerFiscalData',
@@ -40,8 +40,7 @@ const customerCard = {
                 title: 'basicData',
                 icon: 'vn:settings',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerBasicData.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerBasicData.vue'),
         },
         {
             path: 'fiscal-data',
@@ -50,8 +49,7 @@ const customerCard = {
                 title: 'fiscalData',
                 icon: 'vn:dfiscales',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerFiscalData.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerFiscalData.vue'),
         },
         {
             path: 'billing-data',
@@ -60,8 +58,7 @@ const customerCard = {
                 title: 'billingData',
                 icon: 'vn:payment',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerBillingData.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerBillingData.vue'),
         },
         {
             path: 'address',
@@ -85,9 +82,7 @@ const customerCard = {
                         title: 'address-create',
                     },
                     component: () =>
-                        import(
-                            'src/pages/Customer/components/CustomerAddressCreate.vue'
-                        ),
+                        import('src/pages/Customer/components/CustomerAddressCreate.vue'),
                 },
                 {
                     path: ':addressId',
@@ -125,8 +120,7 @@ const customerCard = {
                 title: 'credits',
                 icon: 'vn:credit',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerCredits.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerCredits.vue'),
         },
         {
             path: 'greuges',
@@ -135,8 +129,7 @@ const customerCard = {
                 title: 'greuges',
                 icon: 'vn:greuge',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerGreuges.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerGreuges.vue'),
         },
         {
             path: 'balance',
@@ -145,8 +138,7 @@ const customerCard = {
                 title: 'balance',
                 icon: 'balance',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerBalance.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerBalance.vue'),
         },
         {
             path: 'recoveries',
@@ -155,8 +147,7 @@ const customerCard = {
                 title: 'recoveries',
                 icon: 'vn:recovery',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerRecoveries.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerRecoveries.vue'),
         },
         {
             path: 'web-access',
@@ -165,8 +156,7 @@ const customerCard = {
                 title: 'webAccess',
                 icon: 'vn:web',
             },
-            component: () =>
-                import('src/pages/Customer/Card/CustomerWebAccess.vue'),
+            component: () => import('src/pages/Customer/Card/CustomerWebAccess.vue'),
         },
         {
             path: 'log',
@@ -247,9 +237,7 @@ const customerCard = {
                         title: 'creditOpinion',
                     },
                     component: () =>
-                        import(
-                            'src/pages/Customer/Card/CustomerCreditOpinion.vue'
-                        ),
+                        import('src/pages/Customer/Card/CustomerCreditOpinion.vue'),
                 },
             ],
         },
@@ -319,9 +307,7 @@ const customerCard = {
                                 title: 'samples',
                             },
                             component: () =>
-                                import(
-                                    'src/pages/Customer/Card/CustomerSamples.vue'
-                                ),
+                                import('src/pages/Customer/Card/CustomerSamples.vue'),
                         },
                         {
                             path: 'create',
@@ -376,9 +362,7 @@ const customerCard = {
                         title: 'fileManagement',
                     },
                     component: () =>
-                        import(
-                            'src/pages/Customer/Card/CustomerFileManagement.vue'
-                        ),
+                        import('src/pages/Customer/Card/CustomerFileManagement.vue'),
                 },
                 {
                     path: 'file-management',
@@ -420,8 +404,7 @@ const customerCard = {
                     meta: {
                         title: 'unpaid',
                     },
-                    component: () =>
-                        import('src/pages/Customer/Card/CustomerUnpaid.vue'),
+                    component: () => import('src/pages/Customer/Card/CustomerUnpaid.vue'),
                 },
             ],
         },
@@ -429,7 +412,7 @@ const customerCard = {
 };
 
 export default {
-    name: 'Customer',    
+    name: 'Customer',
     path: '/customer',
     meta: {
         title: 'customers',
@@ -469,15 +452,6 @@ export default {
                         customerCard,
                     ],
                 },
-                {
-                    path: 'create',
-                    name: 'CustomerCreate',
-                    meta: {
-                        title: 'customerCreate',
-                        icon: 'add',
-                    },
-                    component: () => import('src/pages/Customer/CustomerCreate.vue'),
-                },
                 {
                     path: 'payments',
                     name: 'CustomerPayments',
diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js
index b5656dc5f..02eea8c6c 100644
--- a/src/router/modules/entry.js
+++ b/src/router/modules/entry.js
@@ -81,7 +81,7 @@ export default {
         keyBinding: 'e',
         menu: [
             'EntryList',
-            'MyEntries',
+            'EntrySupplier',
             'EntryLatestBuys',
             'EntryStockBought',
             'EntryWasteRecalc',
@@ -125,21 +125,12 @@ export default {
                 },
                 {
                     path: 'my',
-                    name: 'MyEntries',
+                    name: 'EntrySupplier',
                     meta: {
                         title: 'labeler',
                         icon: 'sell',
                     },
-                    component: () => import('src/pages/Entry/MyEntries.vue'),
-                },
-                {
-                    path: 'latest-buys',
-                    name: 'EntryLatestBuys',
-                    meta: {
-                        title: 'latestBuys',
-                        icon: 'contact_support',
-                    },
-                    component: () => import('src/pages/Entry/EntryLatestBuys.vue'),
+                    component: () => import('src/pages/Entry/EntrySupplier.vue'),
                 },
                 {
                     path: 'stock-Bought',
diff --git a/src/router/modules/monitor.js b/src/router/modules/monitor.js
index 89ba4078f..3f30ace72 100644
--- a/src/router/modules/monitor.js
+++ b/src/router/modules/monitor.js
@@ -8,13 +8,10 @@ export default {
         icon: 'grid_view',
         moduleName: 'Monitor',
         keyBinding: 'm',
+        menu: ['MonitorTickets', 'MonitorClientsActions'],
     },
     component: RouterView,
     redirect: { name: 'MonitorMain' },
-    menus: {
-        main: ['MonitorTickets', 'MonitorClientsActions'],
-        card: [],
-    },
     children: [
         {
             path: '',
diff --git a/src/router/modules/route.js b/src/router/modules/route.js
index 835324d20..0dd41c86e 100644
--- a/src/router/modules/route.js
+++ b/src/router/modules/route.js
@@ -166,7 +166,7 @@ const vehicleCard = {
     component: () => import('src/pages/Route/Vehicle/Card/VehicleCard.vue'),
     redirect: { name: 'VehicleSummary' },
     meta: {
-        menu: ['VehicleBasicData'],
+        menu: ['VehicleBasicData', 'VehicleNotes'],
     },
     children: [
         {
@@ -187,6 +187,15 @@ const vehicleCard = {
             },
             component: () => import('src/pages/Route/Vehicle/Card/VehicleBasicData.vue'),
         },
+        {
+            name: 'VehicleNotes',
+            path: 'notes',
+            meta: {
+                title: 'notes',
+                icon: 'vn:notes',
+            },
+            component: () => import('src/pages/Route/Vehicle/Card/VehicleNotes.vue'),
+        }
     ],
 };
 
@@ -229,6 +238,7 @@ export default {
                                 title: 'list',
                                 icon: 'view_list',
                             },
+                            component: () => import('src/pages/Route/RouteList.vue'),
                         },
                         routeCard,
                     ],
@@ -264,11 +274,11 @@ export default {
                     path: 'roadmap',
                     name: 'RouteRoadmap',
                     redirect: { name: 'RoadmapList' },
+                    component: () => import('src/pages/Route/RouteRoadmap.vue'),
                     meta: {
                         title: 'RouteRoadmap',
                         icon: 'vn:troncales',
                     },
-                    component: () => import('src/pages/Route/RouteRoadmap.vue'),
                     children: [
                         {
                             name: 'RoadmapList',
@@ -277,6 +287,7 @@ export default {
                                 title: 'list',
                                 icon: 'view_list',
                             },
+                            component: () => import('src/pages/Route/RouteRoadmap.vue'),
                         },
                         roadmapCard,
                     ],
@@ -294,11 +305,11 @@ export default {
                     path: 'agency',
                     name: 'RouteAgency',
                     redirect: { name: 'AgencyList' },
+                    component: () => import('src/pages/Route/Agency/AgencyList.vue'),
                     meta: {
                         title: 'agency',
                         icon: 'garage_home',
                     },
-                    component: () => import('src/pages/Route/Agency/AgencyList.vue'),
                     children: [
                         {
                             name: 'AgencyList',
@@ -307,6 +318,8 @@ export default {
                                 title: 'list',
                                 icon: 'view_list',
                             },
+                            component: () =>
+                                import('src/pages/Route/Agency/AgencyList.vue'),
                         },
                         agencyCard,
                     ],
@@ -315,11 +328,11 @@ export default {
                     path: 'vehicle',
                     name: 'RouteVehicle',
                     redirect: { name: 'VehicleList' },
+                    component: () => import('src/pages/Route/Vehicle/VehicleList.vue'),
                     meta: {
                         title: 'vehicle',
                         icon: 'directions_car',
                     },
-                    component: () => import('src/pages/Route/Vehicle/VehicleList.vue'),
                     children: [
                         {
                             path: 'list',
@@ -328,6 +341,8 @@ export default {
                                 title: 'vehicleList',
                                 icon: 'directions_car',
                             },
+                            component: () =>
+                                import('src/pages/Route/Vehicle/VehicleList.vue'),
                         },
                         vehicleCard,
                     ],
diff --git a/src/router/modules/wagon.js b/src/router/modules/wagon.js
index 4a322d305..798c671eb 100644
--- a/src/router/modules/wagon.js
+++ b/src/router/modules/wagon.js
@@ -1,52 +1,60 @@
 import { RouterView } from 'vue-router';
 
+const wagonCard = {
+    name: 'WagonCard',
+    path: ':id',
+    component: () => import('src/pages/Wagon/Card/WagonCard.vue'),
+    redirect: { name: 'WagonEdit' },
+    meta: {
+        menu: ['WagonEdit'],
+    },
+    children: [
+        {
+            path: 'edit',
+            name: 'WagonEdit',
+            meta: {
+                title: 'wagonEdit',
+                icon: 'edit',
+            },
+            component: () => import('src/pages/Wagon/WagonCreate.vue'),
+        },
+    ],
+};
+
 export default {
-    path: '/wagon',
     name: 'Wagon',
+    path: '/wagon',
     meta: {
         title: 'wagons',
         icon: 'vn:trolley',
         moduleName: 'Wagon',
+        menu: ['WagonList', 'WagonTypeList', 'WagonCounter'],
     },
     component: RouterView,
     redirect: { name: 'WagonMain' },
-    menus: {
-        main: ['WagonList', 'WagonTypeList', 'WagonCounter', 'WagonTray'],
-        card: [],
-    },
     children: [
         {
-            path: '/wagon',
+            path: '',
             name: 'WagonMain',
             component: () => import('src/components/common/VnModule.vue'),
-            redirect: { name: 'WagonList' },
+            redirect: { name: 'WagonIndexMain' },
             children: [
                 {
-                    path: 'list',
-                    name: 'WagonList',
-                    meta: {
-                        title: 'list',
-                        icon: 'vn:trolley',
-                    },
+                    path: '',
+                    name: 'WagonIndexMain',
+                    redirect: { name: 'WagonList' },
                     component: () => import('src/pages/Wagon/WagonList.vue'),
-                },
-                {
-                    path: 'create',
-                    name: 'WagonCreate',
-                    meta: {
-                        title: 'wagonCreate',
-                        icon: 'create',
-                    },
-                    component: () => import('src/pages/Wagon/WagonCreate.vue'),
-                },
-                {
-                    path: ':id/edit',
-                    name: 'WagonEdit',
-                    meta: {
-                        title: 'wagonEdit',
-                        icon: 'edit',
-                    },
-                    component: () => import('src/pages/Wagon/WagonCreate.vue'),
+                    children: [
+                        {
+                            name: 'WagonList',
+                            path: 'list',
+                            meta: {
+                                title: 'list',
+                                icon: 'view_list',
+                            },
+                        },
+                        wagonCard,
+                    ],
                 },
                 {
                     path: 'counter',
@@ -57,40 +65,32 @@ export default {
                     },
                     component: () => import('src/pages/Wagon/WagonCounter.vue'),
                 },
-            ],
-        },
-        {
-            path: '/wagon/type',
-            name: 'WagonTypeMain',
-            component: () => import('src/components/common/VnModule.vue'),
-            redirect: { name: 'WagonTypeList' },
-            children: [
                 {
-                    path: 'list',
-                    name: 'WagonTypeList',
-                    meta: {
-                        title: 'typesList',
-                        icon: 'view_list',
-                    },
-                    component: () => import('src/pages/Wagon/Type/WagonTypeList.vue'),
-                },
-                {
-                    path: 'create',
-                    name: 'WagonTypeCreate',
-                    meta: {
-                        title: 'typeCreate',
-                        icon: 'create',
-                    },
-                    component: () => import('src/pages/Wagon/Type/WagonTypeList.vue'),
-                },
-                {
-                    path: ':id/edit',
-                    name: 'WagonTypeEdit',
-                    meta: {
-                        title: 'typeEdit',
-                        icon: 'edit',
-                    },
-                    component: () => import('src/pages/Wagon/Type/WagonTypeEdit.vue'),
+                    path: 'type',
+                    name: 'WagonTypeMain',
+                    redirect: { name: 'WagonTypeList' },
+                    children: [
+                        {
+                            path: 'list',
+                            name: 'WagonTypeList',
+                            meta: {
+                                title: 'typesList',
+                                icon: 'view_list',
+                            },
+                            component: () =>
+                                import('src/pages/Wagon/Type/WagonTypeList.vue'),
+                        },
+                        {
+                            path: ':id/edit',
+                            name: 'WagonTypeEdit',
+                            meta: {
+                                title: 'typeEdit',
+                                icon: 'edit',
+                            },
+                            component: () =>
+                                import('src/pages/Wagon/Type/WagonTypeEdit.vue'),
+                        },
+                    ],
                 },
             ],
         },
diff --git a/src/router/modules/worker.js b/src/router/modules/worker.js
index 3eb95a96e..ff3d483cf 100644
--- a/src/router/modules/worker.js
+++ b/src/router/modules/worker.js
@@ -271,12 +271,14 @@ export default {
                     path: 'department',
                     name: 'Department',
                     redirect: { name: 'WorkerDepartment' },
-                    component: () => import('src/pages/Worker/WorkerDepartment.vue'),
+                    meta: { title: 'department', icon: 'vn:greuge' },
                     children: [
                         {
+                            component: () =>
+                                import('src/pages/Worker/WorkerDepartment.vue'),
+                            meta: { title: 'department', icon: 'vn:greuge' },
                             name: 'WorkerDepartment',
                             path: 'list',
-                            meta: { title: 'department', icon: 'vn:greuge' },
                         },
                         departmentCard,
                     ],
diff --git a/src/router/modules/zone.js b/src/router/modules/zone.js
index f400a708e..f48a715b9 100644
--- a/src/router/modules/zone.js
+++ b/src/router/modules/zone.js
@@ -1,24 +1,12 @@
 import { RouterView } from 'vue-router';
 
-export default {
-    path: '/zone',
-    name: 'Zone',
+const zoneCard = {
+    name: 'ZoneCard',
+    path: ':id',
+    component: () => import('src/pages/Zone/Card/ZoneCard.vue'),
+    redirect: { name: 'ZoneSummary' },
     meta: {
-        title: 'zones',
-        icon: 'vn:zone',
-        moduleName: 'Zone',
-        keyBinding: 'z',
-    },
-    component: RouterView,
-    redirect: { name: 'ZoneMain' },
-    menus: {
-        main: [
-            'ZoneList',
-            'ZoneDeliveryDays',
-            'ZoneUpcomingList',
-            'ZoneUpcomingDeliveries',
-        ],
-        card: [
+        menu: [
             'ZoneBasicData',
             'ZoneWarehouses',
             'ZoneHistory',
@@ -28,19 +16,102 @@ export default {
     },
     children: [
         {
-            path: '/zone',
+            name: 'ZoneSummary',
+            path: 'summary',
+            meta: {
+                title: 'summary',
+                icon: 'launch',
+            },
+            component: () => import('src/pages/Zone/Card/ZoneSummary.vue'),
+        },
+        {
+            path: 'basic-data',
+            name: 'ZoneBasicData',
+            meta: {
+                title: 'basicData',
+                icon: 'vn:settings',
+            },
+            component: () => import('src/pages/Zone/Card/ZoneBasicData.vue'),
+        },
+        {
+            path: 'location',
+            name: 'ZoneLocations',
+            meta: {
+                title: 'locations',
+                icon: 'my_location',
+            },
+            component: () => import('src/pages/Zone/Card/ZoneLocations.vue'),
+        },
+        {
+            path: 'warehouses',
+            name: 'ZoneWarehouses',
+            meta: {
+                title: 'warehouses',
+                icon: 'home',
+            },
+            component: () => import('src/pages/Zone/Card/ZoneWarehouses.vue'),
+        },
+        {
+            path: 'log',
+            name: 'ZoneHistory',
+            meta: {
+                title: 'log',
+                icon: 'history',
+            },
+            component: () => import('src/pages/Zone/Card/ZoneLog.vue'),
+        },
+        {
+            path: 'events',
+            name: 'ZoneEvents',
+            meta: {
+                title: 'calendar',
+                icon: 'vn:calendar',
+            },
+            component: () => import('src/pages/Zone/Card/ZoneEvents.vue'),
+        },
+    ],
+};
+
+export default {
+    name: 'Zone',
+    path: '/zone',
+    meta: {
+        title: 'zones',
+        icon: 'vn:zone',
+        moduleName: 'Zone',
+        keyBinding: 'z',
+        menu: [
+            'ZoneList',
+            'ZoneDeliveryDays',
+            'ZoneUpcomingList',
+            'ZoneUpcomingDeliveries',
+        ],
+    },
+    component: RouterView,
+    redirect: { name: 'ZoneMain' },
+    children: [
+        {
             name: 'ZoneMain',
+            path: '',
             component: () => import('src/components/common/VnModule.vue'),
-            redirect: { name: 'ZoneList' },
+            redirect: { name: 'ZoneIndexMain' },
             children: [
                 {
-                    path: 'list',
-                    name: 'ZoneList',
-                    meta: {
-                        title: 'zonesList',
-                        icon: 'view_list',
-                    },
+                    path: '',
+                    name: 'ZoneIndexMain',
+                    redirect: { name: 'ZoneList' },
                     component: () => import('src/pages/Zone/ZoneList.vue'),
+                    children: [
+                        {
+                            name: 'ZoneList',
+                            path: 'list',
+                            meta: {
+                                title: 'list',
+                                icon: 'view_list',
+                            },
+                        },
+                        zoneCard,
+                    ],
                 },
                 {
                     path: 'delivery-days',
@@ -62,67 +133,5 @@ export default {
                 },
             ],
         },
-        {
-            name: 'ZoneCard',
-            path: ':id',
-            component: () => import('src/pages/Zone/Card/ZoneCard.vue'),
-            redirect: { name: 'ZoneSummary' },
-            children: [
-                {
-                    name: 'ZoneSummary',
-                    path: 'summary',
-                    meta: {
-                        title: 'summary',
-                        icon: 'launch',
-                    },
-                    component: () => import('src/pages/Zone/Card/ZoneSummary.vue'),
-                },
-                {
-                    name: 'ZoneBasicData',
-                    path: 'basic-data',
-                    meta: {
-                        title: 'basicData',
-                        icon: 'vn:settings',
-                    },
-                    component: () => import('src/pages/Zone/Card/ZoneBasicData.vue'),
-                },
-                {
-                    name: 'ZoneLocations',
-                    path: 'location',
-                    meta: {
-                        title: 'locations',
-                        icon: 'my_location',
-                    },
-                    component: () => import('src/pages/Zone/Card/ZoneLocations.vue'),
-                },
-                {
-                    name: 'ZoneWarehouses',
-                    path: 'warehouses',
-                    meta: {
-                        title: 'warehouses',
-                        icon: 'home',
-                    },
-                    component: () => import('src/pages/Zone/Card/ZoneWarehouses.vue'),
-                },
-                {
-                    name: 'ZoneHistory',
-                    path: 'log',
-                    meta: {
-                        title: 'log',
-                        icon: 'history',
-                    },
-                    component: () => import('src/pages/Zone/Card/ZoneLog.vue'),
-                },
-                {
-                    name: 'ZoneEvents',
-                    path: 'events',
-                    meta: {
-                        title: 'calendar',
-                        icon: 'vn:calendar',
-                    },
-                    component: () => import('src/pages/Zone/Card/ZoneEvents.vue'),
-                },
-            ],
-        },
     ],
 };
diff --git a/src/stores/__tests__/useArrayDataStore.spec.js b/src/stores/__tests__/useArrayDataStore.spec.js
new file mode 100644
index 000000000..79f17cf69
--- /dev/null
+++ b/src/stores/__tests__/useArrayDataStore.spec.js
@@ -0,0 +1,95 @@
+import { describe, expect, it, beforeEach } from 'vitest';
+import { setActivePinia, createPinia } from 'pinia';
+import { useArrayDataStore } from '../useArrayDataStore';
+
+describe('useArrayDataStore', () => {
+    beforeEach(() => {
+        setActivePinia(createPinia());
+    });
+
+    it('should get undefined for non-existent key', () => {
+        const store = useArrayDataStore();
+        expect(store.get('nonExistent')).toBeUndefined();
+    });
+
+    it('should set default state for new key', () => {
+        const store = useArrayDataStore();
+        store.set('test');
+        const state = store.get('test');
+
+        expect(state).toMatchObject({
+            filter: {},
+            userFilter: {},
+            userParams: {},
+            url: '',
+            limit: 20,
+            skip: 0,
+            order: '',
+            isLoading: false,
+            userParamsChanged: false,
+            exprBuilder: null,
+            searchUrl: 'params',
+            navigate: null,
+            page: 1,
+            mapKey: 'id',
+            oneRecord: false,
+        });
+    });
+
+    it('should clear state for specific key', () => {
+        const store = useArrayDataStore();
+        store.set('test');
+        store.clear('test');
+        expect(store.get('test')).toBeUndefined();
+    });
+
+    it('should reset all properties when no options provided', () => {
+        const store = useArrayDataStore();
+        store.set('test');
+        const state = store.get('test');
+        state.limit = 50;
+        state.page = 3;
+
+        store.reset('test');
+        expect(store.get('test').limit).toBe(20);
+        expect(store.get('test').page).toBe(1);
+    });
+
+    it('should reset only specified properties', () => {
+        const store = useArrayDataStore();
+        store.set('test');
+        const state = store.get('test');
+        state.limit = 50;
+        state.page = 3;
+        state.url = 'test-url';
+
+        store.reset('test', ['limit', 'page']);
+        expect(state.limit).toBe(20);
+        expect(state.page).toBe(1);
+        expect(state.url).toBe('test-url');
+    });
+
+    it('should reset nested properties', () => {
+        const store = useArrayDataStore();
+        store.set('test');
+        const state = store.get('test');
+        state.filter.skip = 10;
+
+        store.reset('test', ['filter.skip']);
+        expect(state.filter.skip).toBe(0);
+    });
+
+    it('should reset pagination properties', () => {
+        const store = useArrayDataStore();
+        store.set('test');
+        const state = store.get('test');
+        state.skip = 20;
+        state.filter.skip = 20;
+        state.page = 3;
+
+        store.resetPagination('test');
+        expect(state.skip).toBe(0);
+        expect(state.filter.skip).toBe(0);
+        expect(state.page).toBe(1);
+    });
+});
diff --git a/src/stores/__tests__/useDescriptorStore.spec.js b/src/stores/__tests__/useDescriptorStore.spec.js
new file mode 100644
index 000000000..61aab8d14
--- /dev/null
+++ b/src/stores/__tests__/useDescriptorStore.spec.js
@@ -0,0 +1,28 @@
+import { describe, expect, it, beforeEach } from 'vitest';
+import 'app/test/vitest/helper';
+
+import { useDescriptorStore } from 'src/stores/useDescriptorStore';
+import { useStateStore } from 'stores/useStateStore';
+
+describe('useDescriptorStore', () => {
+    const { get, has } = useDescriptorStore();
+    const stateStore = useStateStore();
+
+    beforeEach(() => {
+        stateStore.setDescriptors({});
+    });
+
+    function getDescriptors() {
+        return stateStore.descriptors;
+    }
+
+    it('should get descriptors in stateStore', async () => {
+        expect(Object.keys(getDescriptors()).length).toBe(0);
+        get();
+        expect(Object.keys(getDescriptors()).length).toBeGreaterThan(0);
+    });
+
+    it('should find ticketDescriptor if search ticketFk', async () => {
+        expect(has('ticketFk')).toBeDefined();
+    });
+});
diff --git a/src/stores/__tests__/useNavigationStore.spec.js b/src/stores/__tests__/useNavigationStore.spec.js
index c5df6157e..120fa64cb 100644
--- a/src/stores/__tests__/useNavigationStore.spec.js
+++ b/src/stores/__tests__/useNavigationStore.spec.js
@@ -1,15 +1,17 @@
 import { setActivePinia, createPinia } from 'pinia';
-import { describe, beforeEach, afterEach, it, expect, vi, beforeAll } from 'vitest';
+import { describe, beforeEach, afterEach, it, expect, vi } from 'vitest';
 import { useNavigationStore } from '../useNavigationStore';
-import axios from 'axios';
+import { default as axios } from 'axios';
 
 let store;
 
-vi.mock('src/router/modules', () => [
-    { name: 'Item', meta: {} },
-    { name: 'Shelving', meta: {} },
-    { name: 'Order', meta: {} },
-]);
+vi.mock('src/router/modules', () => ({
+    default: [
+        { name: 'Item', meta: {} },
+        { name: 'Shelving', meta: {} },
+        { name: 'Order', meta: {} },
+    ],
+}));
 
 vi.mock('src/filters', () => ({
     toLowerCamel: vi.fn((name) => name.toLowerCase()),
diff --git a/src/stores/useArrayDataStore.js b/src/stores/useArrayDataStore.js
index b3996d1e3..569ff1c7e 100644
--- a/src/stores/useArrayDataStore.js
+++ b/src/stores/useArrayDataStore.js
@@ -18,7 +18,6 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
         navigate: null,
         page: 1,
         mapKey: 'id',
-        keepData: false,
         oneRecord: false,
     };
 
diff --git a/src/stores/useDescriptorStore.js b/src/stores/useDescriptorStore.js
new file mode 100644
index 000000000..be342b016
--- /dev/null
+++ b/src/stores/useDescriptorStore.js
@@ -0,0 +1,33 @@
+import { defineAsyncComponent } from 'vue';
+import { defineStore } from 'pinia';
+import { useStateStore } from 'stores/useStateStore';
+
+export const useDescriptorStore = defineStore('descriptorStore', () => {
+    const { descriptors, setDescriptors } = useStateStore();
+    function get() {
+        if (Object.keys(descriptors).length) return descriptors;
+
+        const currentDescriptors = {};
+        const files = import.meta.glob(`/src/**/*DescriptorProxy.vue`);
+        const moduleParser = {
+            account: 'user',
+            customer: 'client',
+        };
+        for (const file in files) {
+            const name = file.split('/').at(-1).slice(0, -19).toLowerCase();
+            const descriptor = moduleParser[name] ?? name;
+            currentDescriptors[descriptor + 'Fk'] = defineAsyncComponent(files[file]);
+        }
+        setDescriptors(currentDescriptors);
+        return currentDescriptors;
+    }
+
+    function has(name) {
+        return get()[name];
+    }
+
+    return {
+        has,
+        get,
+    };
+});
diff --git a/src/stores/useStateStore.js b/src/stores/useStateStore.js
index ca447bc11..44fa133d0 100644
--- a/src/stores/useStateStore.js
+++ b/src/stores/useStateStore.js
@@ -8,6 +8,7 @@ export const useStateStore = defineStore('stateStore', () => {
     const rightAdvancedDrawer = ref(false);
     const subToolbar = ref(false);
     const cardDescriptor = ref(null);
+    const descriptors = ref({});
 
     function cardDescriptorChangeValue(descriptor) {
         cardDescriptor.value = descriptor;
@@ -52,6 +53,10 @@ export const useStateStore = defineStore('stateStore', () => {
         return subToolbar.value;
     }
 
+    function setDescriptors(value) {
+        descriptors.value = value;
+    }
+
     return {
         cardDescriptor,
         cardDescriptorChangeValue,
@@ -68,5 +73,7 @@ export const useStateStore = defineStore('stateStore', () => {
         isSubToolbarShown,
         toggleSubToolbar,
         rightDrawerChangeValue,
+        descriptors,
+        setDescriptors,
     };
 });
diff --git a/src/stores/useWeekdayStore.js b/src/stores/useWeekdayStore.js
index 57a302dc1..bf6b2704d 100644
--- a/src/stores/useWeekdayStore.js
+++ b/src/stores/useWeekdayStore.js
@@ -77,14 +77,14 @@ export const useWeekdayStore = defineStore('weekdayStore', () => {
         const locales = {};
         for (let code of localeOrder.es) {
             const weekDay = weekdaysMap[code];
-            const locale = t(`weekdays.${weekdaysMap[code].code}`);
+            const locale = t(`weekdays.${weekDay?.code}`);
             const obj = {
                 ...weekDay,
                 locale,
                 localeChar: locale.substr(0, 1),
                 localeAbr: locale.substr(0, 3),
             };
-            locales[weekDay.code] = obj;
+            locales[weekDay?.code] = obj;
         }
         return locales;
     });
diff --git a/test/cypress/cypressParallel.sh b/test/cypress/cypressParallel.sh
deleted file mode 100644
index 8ef26bcde..000000000
--- a/test/cypress/cypressParallel.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-find 'test/cypress/integration' \
-    -mindepth 1 \
-    -maxdepth 1 \
-    -type d | \
-xargs -P "$1" -I {} sh -c '
-    echo "🔷 {}" &&
-    xvfb-run -a cypress run \
-        --headless \
-        --spec "{}" \
-        --quiet \
-        > /dev/null
-'
-wait
diff --git a/test/cypress/docker/cypressParallel.sh b/test/cypress/docker/cypressParallel.sh
new file mode 100644
index 000000000..8e253f1e3
--- /dev/null
+++ b/test/cypress/docker/cypressParallel.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+echo $2
+if [ -z "$2" ]; then
+    TEST_DIRS=$(find 'test/cypress/integration' -mindepth 1 -maxdepth 1 -type d)
+else
+    TEST_DIRS=$2
+fi
+
+echo $TEST_DIRS x$1
+
+echo "$TEST_DIRS" | xargs -P "$1" -I {} sh -c '
+    echo "🔷 {}" &&
+    xvfb-run -a cypress run \
+        --headless \
+        --spec "{}" \
+        --quiet \
+        > /dev/null
+'
+wait
diff --git a/test/cypress/docker/find/find-imports.js b/test/cypress/docker/find/find-imports.js
new file mode 100644
index 000000000..622049c9f
--- /dev/null
+++ b/test/cypress/docker/find/find-imports.js
@@ -0,0 +1,52 @@
+import fs from 'fs';
+import { parse } from 'es-module-lexer';
+import { parse as vueParse } from '@vue/compiler-sfc';
+import glob from 'fast-glob';
+import { resolveImportPath, toRelative } from './resolve-import-path.js';
+
+const ROUTER_MODULES = 'src/router/modules/';
+const files = await glob(['src/**/*.{vue,js,ts}'], { absolute: true });
+const vueFiles = new Map();
+
+export async function findImports(targetFile, visited = new Set(), identation = '') {
+    if (visited.has(targetFile)) return []; // Avoid infinite loops
+    visited.add(targetFile);
+
+    const usageFiles = files
+        .filter((file) => {
+            let content = fs.readFileSync(file, 'utf8');
+            if (file.endsWith('.vue')) {
+                if (vueFiles.has(file)) {
+                    content = vueFiles.get(file);
+                } else {
+                    const { descriptor } = vueParse(content);
+                    content = descriptor?.scriptSetup?.content ?? '';
+                    vueFiles.set(file, content);
+                }
+            }
+            if (!content.trim()) return false;
+
+            return parse(content)[0].some((imp) => {
+                if (!imp?.n) return false;
+                return resolveImportPath(imp.n, targetFile) === targetFile;
+            });
+        })
+        .map((file) => toRelative(file));
+
+    let fullTree = [...usageFiles];
+    for (const file of usageFiles) {
+        if (file.startsWith(ROUTER_MODULES)) {
+            continue;
+        }
+        fullTree = [
+            ...fullTree,
+            ...(await findImports(file, visited, identation + '  ')),
+        ];
+    }
+
+    return getUniques([...fullTree, targetFile]); // Remove duplicates
+}
+
+function getUniques(array) {
+    return Array.from(new Set(array));
+}
diff --git a/test/cypress/docker/find/find.js b/test/cypress/docker/find/find.js
new file mode 100644
index 000000000..4f8063c86
--- /dev/null
+++ b/test/cypress/docker/find/find.js
@@ -0,0 +1,53 @@
+import { execSync } from 'child_process';
+import { findImports } from './find-imports.js';
+import { getModules } from './get-modules.js';
+const E2E_PATH = 'test/cypress/integration';
+const FINDED_PATHS = ['src', E2E_PATH];
+
+function getGitDiff(options) {
+    const TARGET_BRANCH = options[2] || 'dev';
+    const diff = execSync(`git diff --name-only origin/${TARGET_BRANCH}`, {
+        encoding: 'utf-8',
+    });
+    return diff.split('\n');
+}
+
+async function getChangedModules() {
+    let changedModules = new Set();
+    const changes = getGitDiff(process.argv);
+    for (const change of changes) {
+        if (!change) continue;
+        if (!FINDED_PATHS.some((prefix) => change.startsWith(prefix))) return '';
+        const changedArray = [
+            ...changedModules,
+            ...new Set(getModules(await findImports(change))),
+        ];
+        if (change.startsWith(E2E_PATH)) changedArray.push(change);
+        changedModules = new Set(changedArray);
+    }
+    return cleanSpecs(changedModules).join('\n');
+}
+
+getChangedModules()
+    .then((modules) => console.log(modules)) // is return
+    .catch((e) => {
+        console.error(e);
+        process.exit(1);
+    });
+
+function cleanSpecs(changedModules) {
+    let specifics = [];
+    const modules = [];
+    for (const changed of changedModules) {
+        if (changed.endsWith('*.spec.js')) {
+            modules.push(changed);
+            continue;
+        }
+        specifics.push(changed);
+    }
+    specifics = specifics.filter(
+        (spec) => !modules.some((module) => spec.startsWith(module.split('**')[0])),
+    );
+
+    return [...modules, ...specifics];
+}
diff --git a/test/cypress/docker/find/get-modules.js b/test/cypress/docker/find/get-modules.js
new file mode 100644
index 000000000..4ac9ec8c4
--- /dev/null
+++ b/test/cypress/docker/find/get-modules.js
@@ -0,0 +1,13 @@
+export function getModules(files) {
+    const CYPRESS_PREFIX = 'test/cypress/integration/';
+    const CYPRESS_SUFIX = '/**/*.spec.js';
+    const modules = [];
+    for (const file of files) {
+        if (file.startsWith('src/page')) {
+            modules.push(
+                CYPRESS_PREFIX + file.split('/')[2].toLowerCase() + CYPRESS_SUFIX,
+            );
+        }
+    }
+    return modules;
+}
diff --git a/test/cypress/docker/find/resolve-import-path.js b/test/cypress/docker/find/resolve-import-path.js
new file mode 100644
index 000000000..38c225fd2
--- /dev/null
+++ b/test/cypress/docker/find/resolve-import-path.js
@@ -0,0 +1,34 @@
+import fs from 'fs';
+import path from 'path';
+const rootDir = process.cwd();
+const config = JSON.parse(fs.readFileSync('jsconfig.json', 'utf-8'));
+const { paths, baseUrl } = config.compilerOptions;
+
+function resolveImportPath(importPath, fileBase) {
+    if (!importPath) return null;
+    importPath = jsConfigPaths(importPath);
+    const fileDir = path.dirname(fileBase);
+    if (importPath.startsWith('.') || importPath.startsWith('/')) {
+        return path.relative(rootDir, path.resolve(fileDir, importPath));
+    }
+
+    return importPath;
+}
+function toRelative(file) {
+    return path.relative(rootDir, file);
+}
+
+function jsConfigPaths(importPath) {
+    for (const [aliasPattern, [target]] of Object.entries(paths)) {
+        const alias = aliasPattern.replace('/*', '');
+        const targetBase = target.replace('/*', '');
+
+        if (importPath.startsWith(alias)) {
+            const rest = importPath.slice(alias.length);
+            return path.resolve(baseUrl, targetBase + rest);
+        }
+    }
+    return importPath;
+}
+
+export { resolveImportPath, toRelative };
diff --git a/test/cypress/docker/run.sh b/test/cypress/docker/run.sh
new file mode 100755
index 000000000..f62f57960
--- /dev/null
+++ b/test/cypress/docker/run.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+salix_dir="${1:-$HOME/Projects/salix}"
+salix_dir=$(eval echo "$salix_dir")
+
+echo "$salix_dir"
+
+current_dir=$(pwd)
+
+cleanup() {
+    docker-compose -p e2e --project-directory . -f test/cypress/docker-compose.yml down -v
+}
+
+trap cleanup SIGINT
+
+# CLEAN
+rm -rf test/cypress/screenshots
+rm -f test/cypress/results/*
+rm -f test/cypress/reports/*
+rm -f junit/e2e-*.xml
+
+# RUN
+export CI=true
+export TZ=Europe/Madrid
+
+# IMAGES
+docker build -t registry.verdnatura.es/salix-back:dev -f "$salix_dir/back/Dockerfile" "$salix_dir"
+cd "$salix_dir" && npx myt run -t
+docker exec vn-database sh -c "rm -rf /mysql-template"
+docker exec vn-database sh -c "cp -a /var/lib/mysql /mysql-template"
+docker commit vn-database registry.verdnatura.es/salix-db:dev
+docker rm -f vn-database
+cd "$current_dir"
+docker build -f ./docs/Dockerfile.dev -t lilium-dev .
+# END IMAGES
+
+docker-compose -p e2e --project-directory . -f test/cypress/docker-compose.yml up -d
+files=$(node test/cypress/docker/find/find.js)
+echo $files
+
+docker run -it --rm \
+    -v "$(pwd)":/app \
+    --network e2e_default \
+    -e CI \
+    -e TZ \
+    lilium-dev \
+    bash -c "sh test/cypress/docker/cypressParallel.sh 2 '$files'"
+
+cleanup
diff --git a/test/cypress/summary.sh b/test/cypress/docker/summary.sh
similarity index 100%
rename from test/cypress/summary.sh
rename to test/cypress/docker/summary.sh
diff --git a/test/cypress/integration/account/accountDescriptorMenu.spec.js b/test/cypress/integration/account/accountDescriptorMenu.spec.js
index 67a7d8ef6..04fc57040 100644
--- a/test/cypress/integration/account/accountDescriptorMenu.spec.js
+++ b/test/cypress/integration/account/accountDescriptorMenu.spec.js
@@ -1,4 +1,4 @@
-describe('ClaimNotes', () => {
+describe('Account descriptor', () => {
     const descriptorOptions = '[data-cy="descriptor-more-opts-menu"] > .q-list';
     const url = '/#/account/1/summary';
 
@@ -7,6 +7,9 @@ describe('ClaimNotes', () => {
         cy.visit(url);
         cy.dataCy('descriptor-more-opts').click();
         cy.get(descriptorOptions)
+            .should('exist')
+            .should('be.visible')
+
             .find('.q-item')
             .its('length')
             .then((count) => {
diff --git a/test/cypress/integration/claim/claimAction.spec.js b/test/cypress/integration/claim/claimAction.spec.js
index b0a16a2ad..8f406ad2f 100644
--- a/test/cypress/integration/claim/claimAction.spec.js
+++ b/test/cypress/integration/claim/claimAction.spec.js
@@ -1,5 +1,5 @@
 /// <reference types="cypress" />
-describe('ClaimAction', () => {
+describe.skip('ClaimAction', () => {
     const claimId = 1;
 
     const firstRow = 'tbody > :nth-child(1)';
@@ -15,12 +15,14 @@ describe('ClaimAction', () => {
         cy.get('[title="Import claim"]').click();
     });
 
-    it('should change destination', () => {
+    // https://redmine.verdnatura.es/issues/8756
+    xit('should change destination', () => {
         const rowData = [true, null, null, 'Bueno'];
         cy.fillRow(firstRow, rowData);
     });
 
-    it('should change destination from other button', () => {
+    // https://redmine.verdnatura.es/issues/8756
+    xit('should change destination from other button', () => {
         const rowData = [true];
 
         cy.fillRow(firstRow, rowData);
@@ -33,7 +35,8 @@ describe('ClaimAction', () => {
         cy.get('[title="Regularize"]').click();
     });
 
-    it('should remove the line', () => {
+    // https://redmine.verdnatura.es/issues/8756
+    xit('should remove the line', () => {
         cy.fillRow(firstRow, [true]);
         cy.removeCard();
         cy.clickConfirm();
diff --git a/test/cypress/integration/claim/claimDevelopment.spec.js b/test/cypress/integration/claim/claimDevelopment.spec.js
index 05ee7f0b8..097d870df 100755
--- a/test/cypress/integration/claim/claimDevelopment.spec.js
+++ b/test/cypress/integration/claim/claimDevelopment.spec.js
@@ -1,5 +1,5 @@
 /// <reference types="cypress" />
-describe('ClaimDevelopment', () => {
+describe.skip('ClaimDevelopment', () => {
     const claimId = 1;
     const firstLineReason = 'tbody > :nth-child(1) > :nth-child(2)';
     const thirdRow = 'tbody > :nth-child(3)';
@@ -19,11 +19,10 @@ describe('ClaimDevelopment', () => {
         cy.getValue(firstLineReason).should('equal', lastReason);
     });
 
-    it('should edit line', () => {
+    it.skip('should edit line', () => {
         cy.selectOption(firstLineReason, newReason);
 
         cy.saveCard();
-        cy.login('developer');
         cy.visit(`/#/claim/${claimId}/development`);
 
         cy.getValue(firstLineReason).should('equal', newReason);
@@ -49,12 +48,9 @@ describe('ClaimDevelopment', () => {
         cy.fillRow(thirdRow, rowData);
 
         cy.saveCard();
-        cy.login('developer');
-        cy.visit(`/#/claim/${claimId}/development`);
-
         cy.validateRow(thirdRow, rowData);
 
-        cy.reload();
+        cy.visit(`/#/claim/${claimId}/development`);
         cy.validateRow(thirdRow, rowData);
 
         //remove row
@@ -63,7 +59,7 @@ describe('ClaimDevelopment', () => {
         cy.clickConfirm();
         cy.get(thirdRow).should('not.exist');
 
-        cy.reload();
+        cy.visit(`/#/claim/${claimId}/development`);
         cy.get(thirdRow).should('not.exist');
     });
 });
diff --git a/test/cypress/integration/claim/claimPhoto.spec.js b/test/cypress/integration/claim/claimPhoto.spec.js
index b84b4f958..ac0460029 100755
--- a/test/cypress/integration/claim/claimPhoto.spec.js
+++ b/test/cypress/integration/claim/claimPhoto.spec.js
@@ -1,5 +1,5 @@
 /// <reference types="cypress" />
-describe('ClaimPhoto', () => {
+describe.skip('ClaimPhoto', () => {
     const carrouselClose =
         '.q-dialog__inner > .q-toolbar > .q-btn > .q-btn__content > .q-icon';
     beforeEach(() => {
diff --git a/test/cypress/integration/client/clientAddress.spec.js b/test/cypress/integration/customer/clientAddress.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientAddress.spec.js
rename to test/cypress/integration/customer/clientAddress.spec.js
diff --git a/test/cypress/integration/customer/clientBalance.spec.js b/test/cypress/integration/customer/clientBalance.spec.js
new file mode 100644
index 000000000..fff6a5e04
--- /dev/null
+++ b/test/cypress/integration/customer/clientBalance.spec.js
@@ -0,0 +1,13 @@
+/// <reference types="cypress" />
+describe('Client balance', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.visit('#/customer/1101/balance');
+    });
+    it('Should create a mandate', () => {
+        cy.get('.q-page-sticky > div > .q-btn').click();
+        cy.selectOption('[data-cy="paymentBank"]', 2);
+        cy.dataCy('paymentAmount_input').clear().type('100');
+        cy.saveCard();
+    });
+});
diff --git a/test/cypress/integration/client/clientBasicData.spec.js b/test/cypress/integration/customer/clientBasicData.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientBasicData.spec.js
rename to test/cypress/integration/customer/clientBasicData.spec.js
diff --git a/test/cypress/integration/client/clientBillingData.spec.js b/test/cypress/integration/customer/clientBillingData.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientBillingData.spec.js
rename to test/cypress/integration/customer/clientBillingData.spec.js
diff --git a/test/cypress/integration/client/clientCredits.spec.js b/test/cypress/integration/customer/clientCredits.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientCredits.spec.js
rename to test/cypress/integration/customer/clientCredits.spec.js
diff --git a/test/cypress/integration/client/clientFiscalData.spec.js b/test/cypress/integration/customer/clientFiscalData.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientFiscalData.spec.js
rename to test/cypress/integration/customer/clientFiscalData.spec.js
diff --git a/test/cypress/integration/client/clientGreuges.spec.js b/test/cypress/integration/customer/clientGreuges.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientGreuges.spec.js
rename to test/cypress/integration/customer/clientGreuges.spec.js
diff --git a/test/cypress/integration/client/clientList.spec.js b/test/cypress/integration/customer/clientList.spec.js
similarity index 95%
rename from test/cypress/integration/client/clientList.spec.js
rename to test/cypress/integration/customer/clientList.spec.js
index b29ad74af..caf94b8bd 100644
--- a/test/cypress/integration/client/clientList.spec.js
+++ b/test/cypress/integration/customer/clientList.spec.js
@@ -1,5 +1,5 @@
 /// <reference types="cypress" />
-describe('Client list', () => {
+describe.skip('Client list', () => {
     beforeEach(() => {
         cy.login('developer');
         cy.visit('/#/customer/list', {
@@ -25,7 +25,7 @@ describe('Client list', () => {
             'Web user': { val: `user_test_${randomInt}` },
             Street: { val: `C/ STREET ${randomInt}` },
             Email: { val: `user.test${randomInt}@cypress.com` },
-            'Sales person': { val: 'salesPerson', type: 'select' },
+            Team: { val: 'Informatica', type: 'select' },
             Location: { val: '46000', type: 'select' },
             'Business type': { val: 'others', type: 'select' },
         };
@@ -53,7 +53,7 @@ describe('Client list', () => {
     it('Client founded create ticket', () => {
         const search = 'Jessica Jones';
         cy.searchByLabel('Name', search);
-        cy.openActionDescriptor('Create ticket');
+        cy.selectDescriptorOption();
         cy.waitForElement('#formModel');
         cy.waitForElement('.q-form');
         cy.checkValueForm(1, search);
diff --git a/test/cypress/integration/client/clientNotes.spec.js b/test/cypress/integration/customer/clientNotes.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientNotes.spec.js
rename to test/cypress/integration/customer/clientNotes.spec.js
diff --git a/test/cypress/integration/client/clientRecoveries.spec.js b/test/cypress/integration/customer/clientRecoveries.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientRecoveries.spec.js
rename to test/cypress/integration/customer/clientRecoveries.spec.js
diff --git a/test/cypress/integration/client/clientSms.spec.js b/test/cypress/integration/customer/clientSms.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientSms.spec.js
rename to test/cypress/integration/customer/clientSms.spec.js
diff --git a/test/cypress/integration/client/clientWebAccess.spec.js b/test/cypress/integration/customer/clientWebAccess.spec.js
similarity index 100%
rename from test/cypress/integration/client/clientWebAccess.spec.js
rename to test/cypress/integration/customer/clientWebAccess.spec.js
diff --git a/test/cypress/integration/client/credit-management/clientCreditContracts.spec.js b/test/cypress/integration/customer/credit-management/clientCreditContracts.spec.js
similarity index 100%
rename from test/cypress/integration/client/credit-management/clientCreditContracts.spec.js
rename to test/cypress/integration/customer/credit-management/clientCreditContracts.spec.js
diff --git a/test/cypress/integration/client/credit-management/clientCreditOpinion.spec.js b/test/cypress/integration/customer/credit-management/clientCreditOpinion.spec.js
similarity index 100%
rename from test/cypress/integration/client/credit-management/clientCreditOpinion.spec.js
rename to test/cypress/integration/customer/credit-management/clientCreditOpinion.spec.js
diff --git a/test/cypress/integration/client/others/clientConsumption.spec.js b/test/cypress/integration/customer/others/clientConsumption.spec.js
similarity index 100%
rename from test/cypress/integration/client/others/clientConsumption.spec.js
rename to test/cypress/integration/customer/others/clientConsumption.spec.js
diff --git a/test/cypress/integration/client/others/clientContacts.spec.js b/test/cypress/integration/customer/others/clientContacts.spec.js
similarity index 100%
rename from test/cypress/integration/client/others/clientContacts.spec.js
rename to test/cypress/integration/customer/others/clientContacts.spec.js
diff --git a/test/cypress/integration/client/others/clientMandates.spec.js b/test/cypress/integration/customer/others/clientMandates.spec.js
similarity index 100%
rename from test/cypress/integration/client/others/clientMandates.spec.js
rename to test/cypress/integration/customer/others/clientMandates.spec.js
diff --git a/test/cypress/integration/client/others/clientSamples.spec.js b/test/cypress/integration/customer/others/clientSamples.spec.js
similarity index 100%
rename from test/cypress/integration/client/others/clientSamples.spec.js
rename to test/cypress/integration/customer/others/clientSamples.spec.js
diff --git a/test/cypress/integration/client/others/clientUnpaid.spec.js b/test/cypress/integration/customer/others/clientUnpaid.spec.js
similarity index 100%
rename from test/cypress/integration/client/others/clientUnpaid.spec.js
rename to test/cypress/integration/customer/others/clientUnpaid.spec.js
diff --git a/test/cypress/integration/client/others/clientWebPayments.spec.js b/test/cypress/integration/customer/others/clientWebPayments.spec.js
similarity index 100%
rename from test/cypress/integration/client/others/clientWebPayments.spec.js
rename to test/cypress/integration/customer/others/clientWebPayments.spec.js
diff --git a/test/cypress/integration/entry/commands.js b/test/cypress/integration/entry/commands.js
new file mode 100644
index 000000000..4d4a8f980
--- /dev/null
+++ b/test/cypress/integration/entry/commands.js
@@ -0,0 +1,20 @@
+Cypress.Commands.add('selectTravel', (warehouse = '1') => {
+    cy.get('i[data-cy="Travel_icon"]').click();
+    cy.selectOption('input[data-cy="Warehouse Out_select"]', warehouse);
+    cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
+    cy.get('button[data-cy="save-filter-travel-form"]').click();
+    cy.get('tr').eq(1).click();
+});
+
+Cypress.Commands.add('deleteEntry', () => {
+    cy.get('[data-cy="descriptor-more-opts"]').should('be.visible').click();
+    cy.waitForElement('div[data-cy="delete-entry"]').click();
+});
+
+Cypress.Commands.add('createEntry', () => {
+    cy.get('button[data-cy="vnTableCreateBtn"]').click();
+    cy.selectTravel('one');
+    cy.get('button[data-cy="FormModelPopup_save"]').click();
+    cy.url().should('include', 'summary');
+    cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+});
diff --git a/test/cypress/integration/entry/entryCard/entryBasicData.spec.js b/test/cypress/integration/entry/entryCard/entryBasicData.spec.js
new file mode 100644
index 000000000..ba689b8c7
--- /dev/null
+++ b/test/cypress/integration/entry/entryCard/entryBasicData.spec.js
@@ -0,0 +1,19 @@
+import '../commands.js';
+
+describe('EntryBasicData', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyer');
+        cy.visit(`/#/entry/list`);
+    });
+
+    it('Change Travel', () => {
+        cy.createEntry();
+        cy.waitForElement('[data-cy="entry-buys"]');
+        cy.get('a[data-cy="EntryBasicData-menu-item"]').click();
+        cy.selectTravel('two');
+        cy.saveCard();
+        cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+        cy.deleteEntry();
+    });
+});
diff --git a/test/cypress/integration/entry/entryCard/entryBuys.spec.js b/test/cypress/integration/entry/entryCard/entryBuys.spec.js
new file mode 100644
index 000000000..b5e185a8e
--- /dev/null
+++ b/test/cypress/integration/entry/entryCard/entryBuys.spec.js
@@ -0,0 +1,101 @@
+import '../commands.js';
+describe('EntryBuys', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyer');
+        cy.visit(`/#/entry/list`);
+    });
+
+    it('Edit buys and use toolbar actions', () => {
+        const COLORS = {
+            negative: 'rgb(251, 82, 82)',
+            positive: 'rgb(200, 228, 132)',
+            enabled: 'rgb(255, 255, 255)',
+            disable: 'rgb(168, 168, 168)',
+        };
+
+        const selectCell = (field, row = 0) =>
+            cy.get(`td[data-col-field="${field}"][data-row-index="${row}"]`);
+        const selectSpan = (field, row = 0) => selectCell(field, row).find('div > span');
+        const selectButton = (cySelector) => cy.get(`button[data-cy="${cySelector}"]`);
+        const clickAndType = (field, value, row = 0) => {
+            selectCell(field, row).click().type(`${value}{esc}`);
+        };
+        const checkText = (field, expectedText, row = 0) =>
+            selectCell(field, row).should('have.text', expectedText);
+        const checkColor = (field, expectedColor, row = 0) =>
+            selectSpan(field, row).should('have.css', 'color', expectedColor);
+
+        cy.createEntry();
+        createBuy();
+
+        selectCell('isIgnored').click().click().type('{esc}');
+        checkText('isIgnored', 'close');
+
+        clickAndType('stickers', '1');
+        checkText('stickers', '0/01');
+        checkText('quantity', '1');
+        checkText('amount', '50.00');
+        clickAndType('packing', '2');
+        checkText('packing', '12');
+        checkText('weight', '12.0');
+        checkText('quantity', '12');
+        checkText('amount', '600.00');
+        checkColor('packing', COLORS.enabled);
+
+        selectCell('groupingMode').click().click().click();
+        checkColor('packing', COLORS.disable);
+        checkColor('grouping', COLORS.enabled);
+
+        selectCell('buyingValue').click().clear().type('{backspace}{backspace}1');
+        checkText('amount', '12.00');
+        checkColor('minPrice', COLORS.disable);
+
+        selectCell('hasMinPrice').click().click();
+        checkColor('minPrice', COLORS.enabled);
+        selectCell('hasMinPrice').click();
+
+        cy.saveCard();
+        cy.get('span[data-cy="footer-stickers"]').should('have.text', '1');
+        cy.get('.q-notification__message').contains('Data saved');
+
+        selectButton('change-quantity-sign').should('be.disabled');
+        selectButton('check-buy-amount').should('be.disabled');
+        cy.get('tr.cursor-pointer > .q-table--col-auto-width > .q-checkbox').click();
+        selectButton('change-quantity-sign').should('be.enabled');
+        selectButton('check-buy-amount').should('be.enabled');
+
+        selectButton('change-quantity-sign').click();
+        selectButton('set-negative-quantity').click();
+        checkText('quantity', '-12');
+        selectButton('set-positive-quantity').click();
+        checkText('quantity', '12');
+        checkColor('amount', COLORS.disable);
+
+        selectButton('check-buy-amount').click();
+        selectButton('uncheck-amount').click();
+        checkColor('amount', COLORS.disable);
+
+        selectButton('check-amount').click();
+        checkColor('amount', COLORS.positive);
+        cy.saveCard();
+
+        cy.get('tbody > tr [tabindex="0"][role="checkbox"]').click();
+        cy.dataCy('transferBuys').should('be.enabled').click();
+        cy.dataCy('entryDestinyInput').should('be.visible').type('100');
+        cy.dataCy('transferBuysBtn').click();
+
+        cy.deleteEntry();
+    });
+
+    function createBuy() {
+        cy.waitForElement('[data-cy="entry-buys"]');
+        cy.get('a[data-cy="EntryBuys-menu-item"]').click();
+        cy.get('button[data-cy="vnTableCreateBtn"]').click();
+
+        cy.get('input[data-cy="itemFk-create-popup"]').type('1');
+        cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
+        cy.get('input[data-cy="Grouping mode_select"]').should('have.value', 'packing');
+        cy.get('button[data-cy="FormModelPopup_save"]').click();
+    }
+});
diff --git a/test/cypress/integration/entry/entryCard/entryDescriptor.spec.js b/test/cypress/integration/entry/entryCard/entryDescriptor.spec.js
new file mode 100644
index 000000000..8185866db
--- /dev/null
+++ b/test/cypress/integration/entry/entryCard/entryDescriptor.spec.js
@@ -0,0 +1,40 @@
+import '../commands.js';
+describe('EntryDescriptor', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyer');
+        cy.visit(`/#/entry/list`);
+    });
+
+    it('Clone entry and recalculate rates', () => {
+        cy.createEntry();
+
+        cy.waitForElement('[data-cy="entry-buys"]');
+
+        cy.url().then((previousUrl) => {
+            cy.get('[data-cy="descriptor-more-opts"]').click();
+            cy.get('div[data-cy="clone-entry"]').should('be.visible').click();
+
+            cy.get('.q-notification__message').eq(1).should('have.text', 'Entry cloned');
+
+            cy.url()
+                .should('not.eq', previousUrl)
+                .then(() => {
+                    cy.waitForElement('[data-cy="entry-buys"]');
+
+                    cy.get('[data-cy="descriptor-more-opts"]').click();
+                    cy.get('div[data-cy="recalculate-rates"]').click();
+
+                    cy.get('.q-notification__message')
+                        .eq(2)
+                        .should('have.text', 'Entry prices recalculated');
+                    cy.deleteEntry();
+
+                    cy.visit(previousUrl);
+
+                    cy.waitForElement('[data-cy="entry-buys"]');
+                    cy.deleteEntry();
+                });
+        });
+    });
+});
diff --git a/test/cypress/integration/entry/entryCard/entryDms.spec.js b/test/cypress/integration/entry/entryCard/entryDms.spec.js
new file mode 100644
index 000000000..f3f0ef20b
--- /dev/null
+++ b/test/cypress/integration/entry/entryCard/entryDms.spec.js
@@ -0,0 +1,22 @@
+import '../commands.js';
+describe('EntryDms', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyer');
+        cy.visit(`/#/entry/list`);
+    });
+
+    it('should create edit and remove new dms', () => {
+        cy.createEntry();
+        cy.waitForElement('[data-cy="entry-buys"]');
+        cy.dataCy('EntryDms-menu-item').click();
+        cy.dataCy('addButton').click();
+        cy.dataCy('attachFile').click();
+        cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', {
+            force: true,
+        });
+        cy.dataCy('FormModelPopup_save').click();
+        cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+        cy.deleteEntry();
+    });
+});
diff --git a/test/cypress/integration/entry/entryCard/entryLock.spec.js b/test/cypress/integration/entry/entryCard/entryLock.spec.js
new file mode 100644
index 000000000..6ba4392ae
--- /dev/null
+++ b/test/cypress/integration/entry/entryCard/entryLock.spec.js
@@ -0,0 +1,44 @@
+import '../commands.js';
+describe('EntryLock', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyer');
+        cy.visit(`/#/entry/list`);
+    });
+
+    it('Should notify when entry is lock by another user', () => {
+        const checkLockMessage = () => {
+            cy.get('[role="dialog"]').should('be.visible');
+            cy.get('[data-cy="VnConfirm_message"] > span').should(
+                'contain.text',
+                'This entry has been locked by buyerNick',
+            );
+        };
+
+        cy.createEntry();
+        goToEntryBuys();
+        cy.get('.q-notification__message')
+            .eq(1)
+            .should('have.text', 'The entry has been locked successfully');
+
+        cy.login('logistic');
+        cy.reload();
+        checkLockMessage();
+        cy.get('[data-cy="VnConfirm_cancel"]').click();
+        cy.url().should('include', 'summary');
+
+        goToEntryBuys();
+        checkLockMessage();
+        cy.get('[data-cy="VnConfirm_confirm"]').click();
+        cy.url().should('include', 'buys');
+
+        cy.deleteEntry();
+
+        function goToEntryBuys() {
+            const entryBuySelector = 'a[data-cy="EntryBuys-menu-item"]';
+            cy.get(entryBuySelector).should('be.visible');
+            cy.waitForElement('[data-cy="entry-buys"]');
+            cy.get(entryBuySelector).click();
+        }
+    });
+});
diff --git a/test/cypress/integration/entry/entryCard/entryNotes.spec.js b/test/cypress/integration/entry/entryCard/entryNotes.spec.js
new file mode 100644
index 000000000..544ac23b0
--- /dev/null
+++ b/test/cypress/integration/entry/entryCard/entryNotes.spec.js
@@ -0,0 +1,50 @@
+import '../commands.js';
+
+describe('EntryNotes', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyer');
+        cy.visit(`/#/entry/list`);
+    });
+
+    const createObservation = (type, description) => {
+        cy.dataCy('vnTableCreateBtn').click();
+        cy.dataCy('Observation type_select').eq(1).should('be.visible').type(type);
+        cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
+        cy.dataCy('Description_input').should('be.visible').type(description);
+        cy.dataCy('FormModelPopup_save').should('be.enabled').click();
+    };
+
+    const editObservation = (rowIndex, type, description) => {
+        cy.get(`td[data-col-field="description"][data-row-index="${rowIndex}"]`)
+            .click()
+            .clear()
+            .type(description);
+        cy.get(`td[data-col-field="observationTypeFk"][data-row-index="${rowIndex}"]`)
+            .click()
+            .clear()
+            .type(type);
+        cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
+        cy.saveCard();
+    };
+
+    it('Create, delete, and edit observations', () => {
+        cy.createEntry();
+        cy.waitForElement('[data-cy="entry-buys"]');
+
+        cy.dataCy('EntryNotes-menu-item').click();
+
+        createObservation('Packager', 'test');
+        cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+
+        editObservation(0, 'Administrative', 'test2');
+
+        createObservation('Administrative', 'test');
+        cy.get('.q-notification__message')
+            .eq(2)
+            .should('have.text', "The observation type can't be repeated");
+        cy.dataCy('FormModelPopup_cancel').click();
+
+        cy.deleteEntry();
+    });
+});
diff --git a/test/cypress/integration/entry/entryDms.spec.js b/test/cypress/integration/entry/entryDms.spec.js
deleted file mode 100644
index 47dcdba9e..000000000
--- a/test/cypress/integration/entry/entryDms.spec.js
+++ /dev/null
@@ -1,44 +0,0 @@
-describe('EntryDms', () => {
-    const entryId = 1;
-
-    beforeEach(() => {
-        cy.viewport(1920, 1080);
-        cy.login('developer');
-        cy.visit(`/#/entry/${entryId}/dms`);
-    });
-
-    it('should create edit and remove new dms', () => {
-        cy.addRow();
-        cy.get('.icon-attach').click();
-        cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', {
-            force: true,
-        });
-
-        cy.get('tbody > tr').then((value) => {
-            const u = undefined;
-
-            //Create and check if exist new row
-            let newFileTd = Cypress.$(value).length;
-            cy.get('.q-btn--standard > .q-btn__content > .block').click();
-            expect(value).to.have.length(newFileTd++);
-            const newRowSelector = `tbody > :nth-child(${newFileTd})`;
-            cy.waitForElement(newRowSelector);
-            cy.validateRow(newRowSelector, [u, u, u, u, u, 'ENTRADA ID 1']);
-
-            //Edit new dms
-            const newDescription = 'entry id 1 modified';
-            const textAreaSelector =
-                '.q-textarea > .q-field__inner > .q-field__control > .q-field__control-container';
-            cy.get(
-                `tbody :nth-child(${newFileTd}) > .text-right > .no-wrap > :nth-child(2) > .q-btn > .q-btn__content > .q-icon`
-            ).click();
-
-            cy.get(textAreaSelector).clear();
-            cy.get(textAreaSelector).type(newDescription);
-            cy.saveCard();
-            cy.reload();
-
-            cy.validateRow(newRowSelector, [u, u, u, u, u, newDescription]);
-        });
-    });
-});
diff --git a/test/cypress/integration/entry/entryList.spec.js b/test/cypress/integration/entry/entryList.spec.js
index 4c4c4f004..bad47615f 100644
--- a/test/cypress/integration/entry/entryList.spec.js
+++ b/test/cypress/integration/entry/entryList.spec.js
@@ -1,223 +1,55 @@
-describe('Entry', () => {
+import './commands';
+
+describe('EntryList', () => {
     beforeEach(() => {
         cy.viewport(1920, 1080);
         cy.login('buyer');
         cy.visit(`/#/entry/list`);
     });
 
-    it('Filter deleted entries and other fields', () => {
-        createEntry();
+    it('View popup summary', () => {
+        cy.createEntry();
         cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
         cy.waitForElement('[data-cy="entry-buys"]');
-        deleteEntry();
+        cy.deleteEntry();
         cy.typeSearchbar('{enter}');
-        cy.get('span[title="Date"]').click().click();
-        cy.typeSearchbar('{enter}');
-        cy.url().should('include', 'order');
-        cy.get('td[data-row-index="0"][data-col-field="landed"]').should(
-            'have.text',
-            '-',
-        );
+        cy.get('button[title="Summary"]').eq(1).should('be.visible').click();
+        cy.dataCy('entry-summary').should('be.visible');
     });
 
-    it.skip('Create entry, modify travel and add buys', () => {
-        createEntryAndBuy();
-        cy.get('a[data-cy="EntryBasicData-menu-item"]').click();
-        selectTravel('two');
-        cy.saveCard();
-        cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
-        deleteEntry();
+    it('Show supplierDescriptor on click on supplierDescriptor', () => {
+        cy.typeSearchbar('{enter}');
+        cy.get('td[data-col-field="supplierFk"] > div > span').eq(0).click();
+        cy.get('div[role="menu"] > div[class="descriptor"]').should('be.visible');
     });
 
-    it('Clone entry and recalculate rates', () => {
-        createEntry();
+    it('Landed badge should display the right color', () => {
+        cy.typeSearchbar('{enter}');
 
-        cy.waitForElement('[data-cy="entry-buys"]');
-
-        cy.url().then((previousUrl) => {
-            cy.get('[data-cy="descriptor-more-opts"]').click();
-            cy.get('div[data-cy="clone-entry"]').should('be.visible').click();
-
-            cy.get('.q-notification__message').eq(1).should('have.text', 'Entry cloned');
-
-            cy.url()
-                .should('not.eq', previousUrl)
-                .then(() => {
-                    cy.waitForElement('[data-cy="entry-buys"]');
-
-                    cy.get('[data-cy="descriptor-more-opts"]').click();
-                    cy.get('div[data-cy="recalculate-rates"]').click();
-
-                    cy.get('.q-notification__message')
-                        .eq(2)
-                        .should('have.text', 'Entry prices recalculated');
-
-                    cy.get('[data-cy="descriptor-more-opts"]').click();
-                    deleteEntry();
-
-                    cy.log(previousUrl);
-
-                    cy.visit(previousUrl);
-
-                    cy.waitForElement('[data-cy="entry-buys"]');
-                    deleteEntry();
+        const checkBadgeDate = (selector, comparisonFn) => {
+            cy.get(selector)
+                .should('exist')
+                .each(($badge) => {
+                    const badgeText = $badge.text().trim();
+                    const badgeDate = new Date(badgeText);
+                    const compareDate = new Date('01/01/2001');
+                    comparisonFn(badgeDate, compareDate);
                 });
-        });
-    });
-
-    it('Should notify when entry is lock by another user', () => {
-        const checkLockMessage = () => {
-            cy.get('[role="dialog"]').should('be.visible');
-            cy.get('[data-cy="VnConfirm_message"] > span').should(
-                'contain.text',
-                'This entry has been locked by buyerNick',
-            );
         };
 
-        createEntry();
-        goToEntryBuys();
-        cy.get('.q-notification__message')
-            .eq(1)
-            .should('have.text', 'The entry has been locked successfully');
-
-        cy.login('logistic');
-        cy.reload();
-        checkLockMessage();
-        cy.get('[data-cy="VnConfirm_cancel"]').click();
-        cy.url().should('include', 'summary');
-
-        goToEntryBuys();
-        checkLockMessage();
-        cy.get('[data-cy="VnConfirm_confirm"]').click();
-        cy.url().should('include', 'buys');
-
-        deleteEntry();
-    });
-
-    it('Edit buys and use toolbar actions', () => {
-        const COLORS = {
-            negative: 'rgb(251, 82, 82)',
-            positive: 'rgb(200, 228, 132)',
-            enabled: 'rgb(255, 255, 255)',
-            disable: 'rgb(168, 168, 168)',
-        };
-
-        const selectCell = (field, row = 0) =>
-            cy.get(`td[data-col-field="${field}"][data-row-index="${row}"]`);
-        const selectSpan = (field, row = 0) => selectCell(field, row).find('div > span');
-        const selectButton = (cySelector) => cy.get(`button[data-cy="${cySelector}"]`);
-        const clickAndType = (field, value, row = 0) => {
-            selectCell(field, row).click().type(`${value}{esc}`);
-        };
-        const checkText = (field, expectedText, row = 0) =>
-            selectCell(field, row).should('have.text', expectedText);
-        const checkColor = (field, expectedColor, row = 0) =>
-            selectSpan(field, row).should('have.css', 'color', expectedColor);
-
-        createEntryAndBuy();
-
-        selectCell('isIgnored').click().click().type('{esc}');
-        checkText('isIgnored', 'close');
-
-        clickAndType('stickers', '1');
-        checkText('stickers', '0/01');
-        checkText('quantity', '1');
-        checkText('amount', '50.00');
-        clickAndType('packing', '2');
-        checkText('packing', '12');
-        checkText('weight', '12.0');
-        checkText('quantity', '12');
-        checkText('amount', '600.00');
-        checkColor('packing', COLORS.enabled);
-
-        selectCell('groupingMode').click().click().click();
-        checkColor('packing', COLORS.disable);
-        checkColor('grouping', COLORS.enabled);
-
-        selectCell('buyingValue').click().clear().type('{backspace}{backspace}1');
-        checkText('amount', '12.00');
-        checkColor('minPrice', COLORS.disable);
-
-        selectCell('hasMinPrice').click().click();
-        checkColor('minPrice', COLORS.enabled);
-        selectCell('hasMinPrice').click();
-
-        cy.saveCard();
-        cy.get('span[data-cy="footer-stickers"]').should('have.text', '1');
-        cy.get('.q-notification__message').contains('Data saved');
-
-        selectButton('change-quantity-sign').should('be.disabled');
-        selectButton('check-buy-amount').should('be.disabled');
-        cy.get('tr.cursor-pointer > .q-table--col-auto-width > .q-checkbox').click();
-        selectButton('change-quantity-sign').should('be.enabled');
-        selectButton('check-buy-amount').should('be.enabled');
-
-        selectButton('change-quantity-sign').click();
-        selectButton('set-negative-quantity').click();
-        checkText('quantity', '-12');
-        selectButton('set-positive-quantity').click();
-        checkText('quantity', '12');
-        checkColor('amount', COLORS.disable);
-
-        selectButton('check-buy-amount').click();
-        selectButton('uncheck-amount').click();
-        checkColor('amount', COLORS.disable);
-
-        selectButton('check-amount').click();
-        checkColor('amount', COLORS.positive);
-        cy.saveCard();
-
-        cy.get('span[data-cy="footer-amount"]').should(
-            'have.css',
-            'color',
-            COLORS.positive,
+        checkBadgeDate(
+            'td[data-col-field="landed"] > div .bg-warning',
+            (badgeDate, compareDate) => {
+                expect(badgeDate.getTime()).to.be.greaterThan(compareDate.getTime());
+            },
         );
 
-        deleteEntry();
+        // fix on task https://redmine.verdnatura.es/issues/8638
+        /* checkBadgeDate(
+            'td[data-col-field="landed"] > div .bg-info',
+            (badgeDate, compareDate) => {
+                expect(badgeDate.getTime()).to.be.lessThan(compareDate.getTime());
+            },
+        ); */
     });
-
-    function goToEntryBuys() {
-        const entryBuySelector = 'a[data-cy="EntryBuys-menu-item"]';
-        cy.get(entryBuySelector).should('be.visible');
-        cy.waitForElement('[data-cy="entry-buys"]');
-        cy.get(entryBuySelector).click();
-    }
-
-    function deleteEntry() {
-        cy.get('[data-cy="descriptor-more-opts"]').should('be.visible').click();
-        cy.waitForElement('div[data-cy="delete-entry"]').click();
-        cy.url().should('include', 'list');
-    }
-
-    function createEntryAndBuy() {
-        createEntry();
-        createBuy();
-    }
-
-    function createEntry() {
-        cy.get('button[data-cy="vnTableCreateBtn"]').click();
-        selectTravel('one');
-        cy.get('button[data-cy="FormModelPopup_save"]').click();
-        cy.url().should('include', 'summary');
-        cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
-    }
-
-    function selectTravel(warehouse) {
-        cy.get('i[data-cy="Travel_icon"]').click();
-        cy.get('input[data-cy="Warehouse Out_select"]').type(warehouse);
-        cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
-        cy.get('button[data-cy="save-filter-travel-form"]').click();
-        cy.get('tr').eq(1).click();
-    }
-
-    function createBuy() {
-        cy.get('a[data-cy="EntryBuys-menu-item"]').click();
-        cy.get('a[data-cy="EntryBuys-menu-item"]').click();
-        cy.get('button[data-cy="vnTableCreateBtn"]').click();
-
-        cy.get('input[data-cy="itemFk-create-popup"]').type('1');
-        cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click();
-        cy.get('input[data-cy="Grouping mode_select"]').should('have.value', 'packing');
-        cy.get('button[data-cy="FormModelPopup_save"]').click();
-    }
 });
diff --git a/test/cypress/integration/entry/entryStockBought.spec.js b/test/cypress/integration/entry/entryStockBought.spec.js
new file mode 100644
index 000000000..3fad44d91
--- /dev/null
+++ b/test/cypress/integration/entry/entryStockBought.spec.js
@@ -0,0 +1,23 @@
+describe('EntryStockBought', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyer');
+        cy.visit(`/#/entry/stock-Bought`);
+    });
+
+    it('Should edit the reserved space adjust the purchased spaces and check detail', () => {
+        cy.get('[data-cy="edit-travel"]').should('be.visible').click();
+        cy.get('input[aria-label="m3"]').clear().type('60');
+        cy.get('[data-cy="FormModelPopup_save"]').click();
+        cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60');
+
+        cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001');
+        cy.get('[data-col-field="reserve"][data-row-index="0"]').click();
+        cy.get('input[name="reserve"]').type('10{enter}');
+        cy.get('button[title="Save"]').click();
+        cy.checkNotification('Data saved');
+
+        cy.get('[data-cy="searchBtn"]').eq(0).click();
+        cy.get('tBody > tr').eq(1).its('length').should('eq', 1);
+    });
+});
diff --git a/test/cypress/integration/entry/myEntry.spec.js b/test/cypress/integration/entry/entrySupplier.spec.js
similarity index 71%
rename from test/cypress/integration/entry/myEntry.spec.js
rename to test/cypress/integration/entry/entrySupplier.spec.js
index ed469d9e2..83deecea5 100644
--- a/test/cypress/integration/entry/myEntry.spec.js
+++ b/test/cypress/integration/entry/entrySupplier.spec.js
@@ -1,4 +1,4 @@
-describe('EntryMy when is supplier', () => {
+describe('EntrySupplier when is supplier', () => {
     beforeEach(() => {
         cy.viewport(1920, 1080);
         cy.login('supplier');
@@ -13,5 +13,7 @@ describe('EntryMy when is supplier', () => {
         cy.dataCy('cardBtn').eq(2).click();
         cy.dataCy('printLabelsBtn').click();
         cy.window().its('open').should('be.called');
+        cy.dataCy('seeLabelBtn').eq(0).should('be.visible').click();
+        cy.window().its('open').should('be.called');
     });
 });
diff --git a/test/cypress/integration/entry/entryWasteRecalc.spec.js b/test/cypress/integration/entry/entryWasteRecalc.spec.js
new file mode 100644
index 000000000..1b358676c
--- /dev/null
+++ b/test/cypress/integration/entry/entryWasteRecalc.spec.js
@@ -0,0 +1,22 @@
+import './commands';
+describe('EntryDms', () => {
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('buyerBoss');
+        cy.visit(`/#/entry/waste-recalc`);
+    });
+
+    it('should recalc waste for today', () => {
+        cy.waitForElement('[data-cy="wasteRecalc"]');
+        cy.dataCy('recalc').should('be.disabled');
+
+        cy.dataCy('dateFrom').should('be.visible').click().type('01-01-2001');
+        cy.dataCy('dateTo').should('be.visible').click().type('01-01-2001');
+
+        cy.dataCy('recalc').should('be.enabled').click();
+        cy.get('.q-notification__message').should(
+            'have.text',
+            'The wastes were successfully recalculated',
+        );
+    });
+});
diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js
deleted file mode 100644
index 91e0d507e..000000000
--- a/test/cypress/integration/entry/stockBought.spec.js
+++ /dev/null
@@ -1,50 +0,0 @@
-describe('EntryStockBought', () => {
-    beforeEach(() => {
-        cy.viewport(1920, 1080);
-        cy.login('buyer');
-        cy.visit(`/#/entry/stock-Bought`);
-    });
-    it('Should edit the reserved space', () => {
-        cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001');
-        cy.get('[data-col-field="reserve"][data-row-index="0"]').click();
-        cy.get('input[name="reserve"]').type('10{enter}');
-        cy.get('button[title="Save"]').click();
-        cy.checkNotification('Data saved');
-    });
-    it('Should add a new reserved space for buyerBoss', () => {
-        cy.addBtnClick();
-        cy.get('input[aria-label="Reserve"]').type('1');
-        cy.get('input[aria-label="Date"]').eq(1).clear();
-        cy.get('input[aria-label="Date"]').eq(1).type('01-01');
-        cy.get('input[aria-label="Buyer"]').type('itNick');
-        cy.get('div[role="listbox"] > div > div[role="option"]')
-            .eq(1)
-            .should('be.visible')
-            .click();
-
-        cy.get('[data-cy="FormModelPopup_save"]').click();
-        cy.get('.q-notification__message').should('have.text', 'Data created');
-
-        cy.get('[data-col-field="reserve"][data-row-index="1"]').click().clear();
-        cy.get('[data-cy="searchBtn"]').eq(1).click();
-        cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata')
-            .should('have.text', 'warningNo data available')
-            .type('{esc}');
-        cy.get('[data-col-field="reserve"][data-row-index="1"]')
-            .click()
-            .type('{backspace}{enter}');
-        cy.get('[data-cy="crudModelDefaultSaveBtn"]').should('be.enabled').click();
-        cy.get('.q-notification__message').eq(1).should('have.text', 'Data saved');
-    });
-    it('Should check detail for the buyer', () => {
-        cy.get('[data-cy="searchBtn"]').eq(0).click();
-        cy.get('tBody > tr').eq(1).its('length').should('eq', 1);
-    });
-
-    it('Should edit travel m3 and refresh', () => {
-        cy.get('[data-cy="edit-travel"]').should('be.visible').click();
-        cy.get('input[aria-label="m3"]').clear().type('60');
-        cy.get('[data-cy="FormModelPopup_save"]').click();
-        cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60');
-    });
-});
diff --git a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
index 11ca1bb59..ee4d9fb74 100644
--- a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
@@ -1,26 +1,40 @@
 /// <reference types="cypress" />
+import moment from 'moment';
 describe('InvoiceInBasicData', () => {
-    const firstFormSelect = '.q-card > .vn-row:nth-child(1) > .q-select';
     const dialogInputs = '.q-dialog input';
-    const resetBtn = '.q-btn-group--push > .q-btn--flat';
     const getDocumentBtns = (opt) => `[data-cy="dms-buttons"]  > :nth-child(${opt})`;
+    const futureDate = moment().add(1, 'days').format('DD-MM-YYYY');
+    const mock = {
+        invoiceInBasicDataSupplier: { val: 'Bros nick', type: 'select' },
+        invoiceInBasicDataSupplierRef_input: 'mockInvoice41',
+        invoiceInBasicDataIssued: { val: futureDate, type: 'date' },
+        invoiceInBasicDataOperated: { val: futureDate, type: 'date' },
+        invoiceInBasicDatabookEntried: { val: futureDate, type: 'date' },
+        invoiceInBasicDataBooked: {
+            val: moment().add(5, 'days').format('DD-MM-YYYY'),
+            type: 'date',
+        },
+        invoiceInBasicDataDeductibleExpenseFk: {
+            val: '4751000000',
+            type: 'select',
+        },
+        invoiceInBasicDataCurrencyFk: { val: 'USD', type: 'select' },
+        invoiceInBasicDataCompanyFk: { val: 'CCs', type: 'select' },
+        invoiceInBasicDataWithholdingSageFk: {
+            val: 'Arrendamiento y subarrendamiento',
+            type: 'select',
+        },
+    };
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/1/basic-data`);
     });
 
-    it('should edit the provideer and supplier ref', () => {
-        cy.dataCy('UnDeductibleVatSelect').type('4751000000');
-        cy.get('.q-menu .q-item').contains('4751000000').click();
-        cy.get(resetBtn).click();
-
-        cy.waitForElement('#formModel').within(() => {
-            cy.dataCy('vnSupplierSelect').type('Bros nick');
-        })
-        cy.get('.q-menu .q-item').contains('Bros nick').click();
+    it('should edit every field', () => {
+        cy.fillInForm(mock, { attr: 'data-cy' });
         cy.saveCard();
-        cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Bros nick');
+        cy.validateForm(mock, { attr: 'data-cy' });
     });
 
     it('should edit, remove and create the dms data', () => {
@@ -44,7 +58,7 @@ describe('InvoiceInBasicData', () => {
         cy.checkNotification('Data saved');
 
         //create
-        cy.get('[data-cy="dms-create"]').eq(0).click();
+        cy.get('[data-cy="invoiceInBasicDataDmsAdd"]').eq(0).click();
         cy.get('[data-cy="VnDms_inputFile"').selectFile(
             'test/cypress/fixtures/image.jpg',
             {
diff --git a/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js b/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js
index 731174040..275fa1358 100644
--- a/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js
@@ -1,22 +1,59 @@
-/// <reference types="cypress" />
-describe('InvoiceInCorrective', () => {
-    const saveDialog = '.q-card > .q-card__actions > .q-btn--standard ';
+describe('invoiceInCorrective', () => {
+    beforeEach(() => cy.login('administrative'));
 
-    it('should create a correcting invoice', () => {
-        cy.viewport(1280, 720);
-        cy.login('developer');
-        cy.visit(`/#/invoice-in/1/summary`);
+    it('should modify the invoice', () => {
+        cy.visit('/#/invoice-in/1/summary');
         cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
+        cy.intercept('POST', '/api/InvoiceInCorrections/crud').as('crud');
+        cy.intercept('GET', /InvoiceInCorrections\?filter=.+/).as('getCorrective');
 
-        cy.openActionsDescriptor();
+        cy.selectDescriptorOption(4);
+        cy.dataCy('saveCorrectiveInvoice').click();
 
-        cy.dataCy('createCorrectiveItem').click();
-        cy.get(saveDialog).click();
-        cy.wait('@corrective').then((interception) => {
-            const correctingId = interception.response.body;
-            cy.url().should('include', `/invoice-in/${correctingId}/summary`);
-            cy.visit(`/#/invoice-in/${correctingId}/corrective`);
+        cy.wait('@corrective').then(({ response }) => {
+            const correctingFk = response.body;
+            cy.url().should('include', `/invoice-in/${correctingFk}/summary`);
+            cy.visit(`/#/invoice-in/${correctingFk}/corrective`);
+            cy.selectOption('[data-cy="invoiceInCorrective_class"]', 'r4');
+            cy.selectOption('[data-cy="invoiceInCorrective_type"]', 'sustitución');
+            cy.selectOption('[data-cy="invoiceInCorrective_reason"]', 'vat');
+            cy.dataCy('crudModelDefaultSaveBtn').click();
+
+            cy.wait('@crud');
+            cy.reload();
+            cy.wait('@getCorrective');
+            cy.validateRow('tbody > :nth-of-type(1)', [
+                ,
+                'S – Por sustitución',
+                'R4',
+                'Error in VAT calculation',
+            ]);
         });
-        cy.get('tbody > tr:visible').should('have.length', 1);
+    });
+
+    it('should not be able to modify the invoice if the original invoice is booked', () => {
+        cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
+        cy.visit('/#/invoice-in/4/summary');
+        cy.selectDescriptorOption();
+        cy.dataCy('VnConfirm_confirm').click();
+        cy.selectDescriptorOption(4);
+        cy.dataCy('saveCorrectiveInvoice').click();
+
+        cy.wait('@corrective').then(({ response }) => {
+            const correctingFk = response.body;
+            cy.url().should('include', `/invoice-in/${correctingFk}/summary`);
+            cy.visit(`/#/invoice-in/${correctingFk}/corrective`);
+
+            cy.dataCy('invoiceInCorrective_class').should('be.disabled');
+            cy.dataCy('invoiceInCorrective_type').should('be.disabled');
+            cy.dataCy('invoiceInCorrective_reason').should('be.disabled');
+        });
+    });
+
+    it('should show/hide the section if it is a corrective invoice', () => {
+        cy.visit('/#/invoice-in/1/summary');
+        cy.get('[data-cy="InvoiceInCorrective-menu-item"]').should('not.exist');
+        cy.clicDescriptorAction(4);
+        cy.get('[data-cy="InvoiceInCorrective-menu-item"]').should('exist');
     });
 });
diff --git a/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js b/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
index 97a9fe976..9744486e0 100644
--- a/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
@@ -1,21 +1,147 @@
 describe('InvoiceInDescriptor', () => {
-    const book = '.summaryHeader > .no-wrap > .q-btn';
-    const firstDescritorOpt = '.q-menu > .q-list > :nth-child(5) > .q-item__section';
-    const checkbox = ':nth-child(5) > .q-checkbox';
+    beforeEach(() => cy.login('administrative'));
 
-    it('should booking and unbooking the invoice properly', () => {
-        cy.viewport(1280, 720);
-        cy.login('developer');
-        cy.visit('/#/invoice-in/1/summary');
-        cy.waitForElement('.q-page');
+    describe('more options', () => {
+        it('should booking and unbooking the invoice properly', () => {
+            const checkbox = '[data-cy="vnLvIs booked"] > .q-checkbox';
+            cy.visit('/#/invoice-in/2/summary');
+            cy.selectDescriptorOption();
+            cy.dataCy('VnConfirm_confirm').click();
+            cy.validateCheckbox(checkbox);
+            cy.selectDescriptorOption();
+            cy.dataCy('VnConfirm_confirm').click();
+            cy.validateCheckbox(checkbox, false);
+        });
 
-        cy.get(book).click();
-        cy.dataCy('VnConfirm_confirm').click();
-        cy.get(checkbox).invoke('attr', 'aria-checked').should('eq', 'true');
+        it('should delete the invoice properly', () => {
+            cy.visit('/#/invoice-in/2/summary');
+            cy.selectDescriptorOption(2);
+            cy.clickConfirm();
+            cy.checkNotification('invoice deleted');
+        });
 
-        cy.dataCy('descriptor-more-opts').first().click();
-        cy.get(firstDescritorOpt).click();
-        cy.dataCy('VnConfirm_confirm').click();
-        cy.get(checkbox).invoke('attr', 'aria-checked').should('eq', 'false');
+        it('should clone the invoice properly', () => {
+            cy.visit('/#/invoice-in/3/summary');
+            cy.selectDescriptorOption(3);
+            cy.clickConfirm();
+            cy.checkNotification('Invoice cloned');
+        });
+
+        it('should show the agricultural PDF properly', () => {
+            cy.visit('/#/invoice-in/6/summary');
+            cy.validatePdfDownload(
+                /api\/InvoiceIns\/6\/invoice-in-pdf\?access_token=.*/,
+                () => cy.selectDescriptorOption(4),
+            );
+        });
+
+        it('should send the agricultural PDF properly', () => {
+            cy.intercept('POST', 'api/InvoiceIns/6/invoice-in-email').as('sendEmail');
+            cy.visit('/#/invoice-in/6/summary');
+            cy.selectDescriptorOption(5);
+
+            cy.dataCy('SendEmailNotificationDialogInput_input').type(
+                '{selectall}jorgito@gmail.mx',
+            );
+            cy.clickConfirm();
+            cy.checkNotification('Notification sent');
+            cy.wait('@sendEmail').then(({ request, response }) => {
+                expect(request.body).to.deep.equal({
+                    recipientId: 2,
+                    recipient: 'jorgito@gmail.mx',
+                });
+                expect(response.statusCode).to.equal(200);
+            });
+        });
+        // https://redmine.verdnatura.es/issues/8767
+        it.skip('should download the file properly', () => {
+            cy.visit('/#/invoice-in/1/summary');
+            cy.validateDownload(() => cy.selectDescriptorOption(5));
+        });
+    });
+
+    describe('buttons', () => {
+        beforeEach(() => cy.visit('/#/invoice-in/1/summary'));
+
+        it('should navigate to the supplier summary', () => {
+            cy.clicDescriptorAction(1);
+            cy.url().should('to.match', /supplier\/\d+\/summary/);
+        });
+
+        it('should navigate to the entry summary', () => {
+            cy.clicDescriptorAction(2);
+            cy.url().should('to.match', /entry\/\d+\/summary/);
+        });
+
+        it('should navigate to the invoiceIn list', () => {
+            cy.clicDescriptorAction(3);
+            cy.url().should('to.match', /invoice-in\/list\?table=\{.*supplierFk.+\}/);
+        });
+    });
+
+    describe('corrective', () => {
+        const originalId = 4;
+
+        beforeEach(() => cy.visit(`/#/invoice-in/${originalId}/summary`));
+
+        it('should create a correcting invoice and redirect to original invoice', () => {
+            createCorrective();
+            redirect(originalId);
+        });
+
+        it('should create a correcting invoice and navigate to list filtered by corrective', () => {
+            createCorrective();
+            redirect(originalId);
+
+            cy.clicDescriptorAction(4);
+            cy.validateVnTableRows({
+                cols: [
+                    {
+                        name: 'supplierRef',
+                        val: '1237',
+                        operation: 'include',
+                    },
+                ],
+            });
+        });
+    });
+
+    describe('link', () => {
+        it('should open the supplier descriptor popup', () => {
+            cy.visit('/#/invoice-in/1/summary');
+            cy.intercept('GET', /Suppliers\/\d+/).as('getSupplier');
+
+            cy.dataCy('invoiceInDescriptor_supplier').then(($el) => {
+                const alias = $el.text().trim();
+                $el.click();
+                cy.wait('@getSupplier').then(() =>
+                    cy.validateDescriptor({ listbox: { 1: alias }, popup: true }),
+                );
+            });
+        });
     });
 });
+
+function createCorrective() {
+    cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
+
+    cy.selectDescriptorOption(4);
+    cy.dataCy('saveCorrectiveInvoice').click();
+
+    cy.wait('@corrective').then(({ response }) => {
+        const correctingId = response.body;
+        cy.url().should('include', `/invoice-in/${correctingId}/summary`);
+        cy.visit(`/#/invoice-in/${correctingId}/corrective`);
+        cy.dataCy('invoiceInCorrective_class').should('contain.value', 'R2');
+        cy.dataCy('invoiceInCorrective_type').should('contain.value', 'diferencias');
+        cy.dataCy('invoiceInCorrective_reason').should('contain.value', 'sales details');
+    });
+}
+
+function redirect(subtitle) {
+    const regex = new RegExp(`InvoiceIns/${subtitle}\\?filter=.*`);
+    cy.intercept('GET', regex).as('getOriginal');
+    cy.clicDescriptorAction(4);
+    cy.wait('@getOriginal');
+    cy.validateDescriptor({ subtitle });
+}
diff --git a/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js b/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
index 5a5becd22..2fc34a7ae 100644
--- a/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
@@ -4,7 +4,7 @@ describe('InvoiceInDueDay', () => {
     const addBtn = '.q-page-sticky > div > .q-btn > .q-btn__content';
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/6/due-day`);
     });
 
diff --git a/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js b/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
index 4c2550548..6a1c18785 100644
--- a/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
@@ -6,7 +6,7 @@ describe('InvoiceInIntrastat', () => {
     const firstRowAmount = `${firstRow} > :nth-child(3)`;
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/1/intrastat`);
     });
 
diff --git a/test/cypress/integration/invoiceIn/invoiceInList.spec.js b/test/cypress/integration/invoiceIn/invoiceInList.spec.js
index d9ab3f7e7..ef3e33000 100644
--- a/test/cypress/integration/invoiceIn/invoiceInList.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInList.spec.js
@@ -1,13 +1,21 @@
 /// <reference types="cypress" />
+
 describe('InvoiceInList', () => {
     const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)';
     const firstId = `${firstRow} > td:nth-child(2) span`;
-    const firstDetailBtn = `${firstRow} .q-btn:nth-child(1)`;
-    const summaryHeaders = '.summaryBody .header-link';
+    const invoiceId = '6';
+    const summaryHeaders = (opt) => `.summaryBody > .${opt} > .q-pb-lg > .header-link`;
+    const mockInvoiceRef = `createMockInvoice${Math.floor(Math.random() * 100)}`;
+    const mock = {
+        vnSupplierSelect: { val: 'farmer king', type: 'select' },
+        'Invoice nº_input': mockInvoiceRef,
+        Company_select: { val: 'orn', type: 'select' },
+        'Expedition date_inputDate': '16-11-2001',
+    };
 
     beforeEach(() => {
         cy.viewport(1920, 1080);
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/list`);
         cy.get('#searchbar input').type('{enter}');
     });
@@ -23,8 +31,28 @@ describe('InvoiceInList', () => {
     });
 
     it('should open the details', () => {
-        cy.get(firstDetailBtn).click();
-        cy.get(summaryHeaders).eq(1).contains('Basic data');
-        cy.get(summaryHeaders).eq(4).contains('Vat');
+        cy.get('[data-col-field="id"]').then(($cells) => {
+            const exactMatch = [...$cells].find(
+                (cell) => cell.textContent.trim() === invoiceId,
+            );
+            expect(exactMatch).to.exist;
+            cy.wrap(exactMatch).closest('tr').find('.q-btn:nth-child(1)').click();
+        });
+        cy.get(summaryHeaders('max-width')).contains('Basic data');
+        cy.get(summaryHeaders('vat')).contains('Vat');
+    });
+
+    it('should create a new Invoice', () => {
+        cy.dataCy('vnTableCreateBtn').click();
+        cy.fillInForm({ ...mock }, { attr: 'data-cy' });
+        cy.dataCy('FormModelPopup_save').click();
+        cy.intercept('GET', /\/api\/InvoiceIns\/\d+\/getTotals$/).as('invoice');
+        cy.wait('@invoice').then(() => {
+            cy.validateDescriptor({
+                title: mockInvoiceRef,
+                listBox: { 0: '11/16/2001', 3: 'The farmer' },
+            });
+            cy.dataCy('invoiceInBasicDataCompanyFk').should('have.value', 'ORN');
+        });
     });
 });
diff --git a/test/cypress/integration/invoiceIn/invoiceInSerial.spec.js b/test/cypress/integration/invoiceIn/invoiceInSerial.spec.js
new file mode 100644
index 000000000..3750f8f06
--- /dev/null
+++ b/test/cypress/integration/invoiceIn/invoiceInSerial.spec.js
@@ -0,0 +1,25 @@
+describe('InvoiceInSerial', () => {
+    beforeEach(() => {
+        cy.login('administrative');
+        cy.visit('#/invoice-in/serial');
+    });
+
+    it('should filter by serial number', () => {
+        cy.dataCy('serial_input').type('R{enter}');
+        cy.validateVnTableRows({ cols: [{ name: 'serial', val: 'r' }] });
+    });
+
+    it('should filter by last days ', () => {
+        cy.dataCy('vnTableCell_total')
+            .invoke('text')
+            .then((before) => {
+                cy.dataCy('Last days_input')
+                    .type('{selectall}1{enter}')
+                    .then(() => {
+                        cy.dataCy('vnTableCell_total')
+                            .invoke('text')
+                            .then((after) => expect(+after).to.be.lessThan(+before));
+                    });
+            });
+    });
+});
diff --git a/test/cypress/integration/invoiceIn/invoiceInSummary.spec.js b/test/cypress/integration/invoiceIn/invoiceInSummary.spec.js
new file mode 100644
index 000000000..72dbdd9a8
--- /dev/null
+++ b/test/cypress/integration/invoiceIn/invoiceInSummary.spec.js
@@ -0,0 +1,24 @@
+describe('InvoiceInSummary', () => {
+    beforeEach(() => {
+        cy.login('administrative');
+        cy.visit('/#/invoice-in/3/summary');
+    });
+
+    it('should booking and unbooking the invoice properly', () => {
+        const checkbox = '[data-cy="vnLvIs booked"] > .q-checkbox';
+        cy.dataCy('invoiceInSummary_book').click();
+        cy.dataCy('VnConfirm_confirm').click();
+        cy.validateCheckbox(checkbox);
+    });
+
+    it('should open the supplier descriptor popup', () => {
+        cy.intercept('GET', /Suppliers\/\d+/).as('getSupplier');
+        cy.dataCy('invoiceInSummary_supplier').then(($el) => {
+            const description = $el.text().trim();
+            $el.click();
+            cy.wait('@getSupplier').then(() =>
+                cy.validateDescriptor({ description, popup: true }),
+            );
+        });
+    });
+});
diff --git a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
index 3e9997a74..ff7d639e6 100644
--- a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
@@ -1,14 +1,14 @@
 /// <reference types="cypress" />
 describe('InvoiceInVat', () => {
     const thirdRow = 'tbody > :nth-child(3)';
-    const firstLineVat = 'tbody > :nth-child(1) > :nth-child(4)';
+    const firstLineVat = 'tbody > :nth-child(1) ';
     const vats = '[data-cy="vat-sageiva"]';
     const dialogInputs = '.q-dialog label input';
     const addBtn = 'tbody tr:nth-child(1) td:nth-child(2) .--add-icon';
     const randomInt = Math.floor(Math.random() * 100);
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/1/vat`);
     });
 
@@ -18,6 +18,17 @@ describe('InvoiceInVat', () => {
         cy.get(vats).eq(0).should('have.value', '8: H.P. IVA 21% CEE');
     });
 
+    it('should mark the line as deductible VAT', () => {
+        cy.get(`${firstLineVat}  [data-cy="isDeductible_checkbox"]`).click();
+
+        cy.saveCard();
+
+        cy.get(`${firstLineVat}  [data-cy="isDeductible_checkbox"]`)
+
+            .click();
+        cy.saveCard();
+    });
+
     it('should add a new row', () => {
         cy.addRow();
         cy.fillRow(thirdRow, [true, 2000000001, 30, 'H.P. IVA 10']);
diff --git a/test/cypress/integration/invoiceOut/invoiceOutList.spec.js b/test/cypress/integration/invoiceOut/invoiceOutList.spec.js
index d3a84d226..b8b42fa4b 100644
--- a/test/cypress/integration/invoiceOut/invoiceOutList.spec.js
+++ b/test/cypress/integration/invoiceOut/invoiceOutList.spec.js
@@ -13,7 +13,6 @@ describe('InvoiceOut list', () => {
         ':nth-child(1) > .text-right > [data-cy="tableAction-0"] > .q-btn__content > .q-icon';
 
     beforeEach(() => {
-        cy.viewport(1920, 1080);
         cy.login('developer');
         cy.visit(`/#/invoice-out/list`);
         cy.typeSearchbar('{enter}');
@@ -41,7 +40,7 @@ describe('InvoiceOut list', () => {
     });
 
     it('should filter the results by client ID, then check the first result is correct', () => {
-        cy.dataCy('Customer ID_input').type('1103');
+        cy.dataCy('Client id_input').type('1103');
         cy.get(filterBtn).click();
         cy.get(firstRowDescriptor).click();
         cy.get('.q-item > .q-item__label').should('include.text', '1103');
diff --git a/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js b/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js
index 0039f6240..9c6eef2ed 100644
--- a/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js
+++ b/test/cypress/integration/invoiceOut/invoiceOutNegativeBases.spec.js
@@ -16,9 +16,9 @@ describe('InvoiceOut negative bases', () => {
         cy.get(getDescriptors('ticketFk')).click();
         cy.get('.descriptor').should('be.visible');
         cy.get('.q-item > .q-item__label').should('include.text', '23');
-        cy.get(getDescriptors('workerName')).click();
+        cy.get(getDescriptors('departmentFk')).click();
         cy.get('.descriptor').should('be.visible');
-        cy.get('.q-item > .q-item__label').should('include.text', '18');
+        cy.get('.q-item > .q-item__label').should('include.text', '155');
     });
 
     it('should filter and download as CSV', () => {
diff --git a/test/cypress/integration/invoiceOut/invoiceOutSummary.spec.js b/test/cypress/integration/invoiceOut/invoiceOutSummary.spec.js
index 63e828f55..49eed32c7 100644
--- a/test/cypress/integration/invoiceOut/invoiceOutSummary.spec.js
+++ b/test/cypress/integration/invoiceOut/invoiceOutSummary.spec.js
@@ -37,7 +37,7 @@ describe('InvoiceOut summary', () => {
         });
     });
 
-    it('should transfer the invoice ', () => {
+    it.skip('should transfer the invoice ', () => {
         cy.typeSearchbar('T1111111{enter}');
         cy.dataCy('descriptor-more-opts').click();
         cy.get(selectMenuOption(1)).click();
@@ -50,7 +50,7 @@ describe('InvoiceOut summary', () => {
         cy.dataCy('descriptor-more-opts').click();
         cy.get(selectMenuOption(3)).click();
         cy.dataCy('InvoiceOutDescriptorMenuSendPdfOption').click();
-        cy.dataCy('SendEmailNotifiactionDialogInput').should('be.visible');
+        cy.dataCy('SendEmailNotificationDialogInput').should('be.visible');
         cy.get(confirmSend).click();
         cy.checkNotification('Notification sent');
     });
@@ -59,7 +59,7 @@ describe('InvoiceOut summary', () => {
         cy.dataCy('descriptor-more-opts').click();
         cy.get(selectMenuOption(3)).click();
         cy.dataCy('InvoiceOutDescriptorMenuSendCsvOption').click();
-        cy.dataCy('SendEmailNotifiactionDialogInput').should('be.visible');
+        cy.dataCy('SendEmailNotificationDialogInput').should('be.visible');
         cy.get(confirmSend).click();
         cy.checkNotification('Notification sent');
     });
diff --git a/test/cypress/integration/item/ItemFixedPrice.spec.js b/test/cypress/integration/item/ItemFixedPrice.spec.js
index 404e8e365..41230f570 100644
--- a/test/cypress/integration/item/ItemFixedPrice.spec.js
+++ b/test/cypress/integration/item/ItemFixedPrice.spec.js
@@ -1,9 +1,14 @@
 /// <reference types="cypress" />
-function goTo(n = 1) {
-    return `.q-virtual-scroll__content > :nth-child(${n})`;
-}
-const firstRow = goTo();
 describe('Handle Items FixedPrice', () => {
+    const grouping = 'Grouping price';
+    const saveEditBtn = '.q-mt-lg > .q-btn--standard';
+    const createForm = {
+        'Grouping price': { val: '5' },
+        'Packing price': { val: '5' },
+        Started: { val: '01-01-2001', type: 'date' },
+        Ended: { val: '15-01-2001', type: 'date' },
+    };
+
     beforeEach(() => {
         cy.viewport(1280, 720);
         cy.login('developer');
@@ -13,50 +18,57 @@ describe('Handle Items FixedPrice', () => {
             '.q-header > .q-toolbar > :nth-child(1) > .q-btn__content > .q-icon',
         ).click();
     });
-    it.skip('filter', function () {
+
+    it('filter by category', () => {
         cy.get('.category-filter > :nth-child(1) > .q-btn__content > .q-icon').click();
-        cy.selectOption('.list > :nth-child(2)', 'Alstroemeria');
-        cy.get('.q-gutter-x-sm > .q-btn > .q-btn__content > .q-icon').click();
-
-        cy.addBtnClick();
-        cy.selectOption(`${firstRow} > :nth-child(2)`, '#13');
-        cy.get(`${firstRow} > :nth-child(4)`).find('input').type(1);
-        cy.get(`${firstRow} > :nth-child(5)`).find('input').type('2');
-        cy.selectOption(`${firstRow} > :nth-child(9)`, 'Warehouse One');
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
-        /* ==== End Cypress Studio ==== */
-    });
-    it.skip('Create and delete ', function () {
-        cy.get('.q-gutter-x-sm > .q-btn > .q-btn__content > .q-icon').click();
-        cy.addBtnClick();
-        cy.selectOption(`${firstRow} > :nth-child(2)`, '#11');
-        cy.get(`${firstRow} > :nth-child(4)`).type('1');
-        cy.get(`${firstRow} > :nth-child(5)`).type('2');
-        cy.selectOption(`${firstRow} > :nth-child(9)`, 'Warehouse One');
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
-        cy.get('.q-gutter-x-sm > .q-btn > .q-btn__content > .q-icon').click();
-        cy.get(`${firstRow} > .text-right > .q-btn > .q-btn__content > .q-icon`).click();
-        cy.get(
-            '.q-card__actions > .q-btn--unelevated > .q-btn__content > .block',
-        ).click();
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
+        cy.get('.q-table__middle').should('be.visible').should('have.length', 1);
     });
 
-    it.skip('Massive edit', function () {
-        cy.get(' .bg-header > :nth-child(1) > .q-checkbox > .q-checkbox__inner ').click();
-        cy.get('#subToolbar > .q-btn--standard').click();
-        cy.selectOption("[data-cy='field-to-edit']", 'Min price');
-        cy.dataCy('value-to-edit').find('input').type('1');
-        cy.get('.countLines').should('have.text', ' 1 ');
-        cy.get('.q-mt-lg > .q-btn--standard').click();
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
+    it('should create a new fixed price, then delete it', () => {
+        cy.dataCy('vnTableCreateBtn').click();
+        cy.dataCy('FixedPriceCreateNameSelect').type('Melee weapon combat fist 15cm');
+        cy.get('.q-menu .q-item').contains('Melee weapon combat fist 15cm').click();
+        cy.dataCy('FixedPriceCreateWarehouseSelect').type('Warehouse One');
+        cy.get('.q-menu .q-item').contains('Warehouse One').click();
+        cy.get('.q-menu').then(($menu) => {
+            if ($menu.is(':visible')) {
+                cy.dataCy('FixedPriceCreateWarehouseSelect').as('focusedElement').focus();
+                cy.dataCy('FixedPriceCreateWarehouseSelect').blur();
+            }
+        });
+        cy.fillInForm(createForm);
+        cy.dataCy('FormModelPopup_save').click();
+        cy.checkNotification('Data created');
+        cy.get('[data-col-field="name"]').each(($el) => {
+            cy.wrap($el)
+                .invoke('text')
+                .then((text) => {
+                    if (text.includes('Melee weapon combat fist 15cm')) {
+                        cy.wrap($el).parent().find('.q-checkbox').click();
+                        cy.get('[data-cy="crudModelDefaultRemoveBtn"]').click();
+                        cy.dataCy('VnConfirm_confirm').click().click();
+                        cy.checkNotification('Data saved');
+                    }
+                });
+        });
     });
-    it.skip('Massive remove', function () {
-        cy.get(' .bg-header > :nth-child(1) > .q-checkbox > .q-checkbox__inner ').click();
-        cy.get('#subToolbar > .q-btn--flat').click();
-        cy.get(
-            '.q-card__actions > .q-btn--unelevated > .q-btn__content > .block',
-        ).click();
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
+
+    it('should edit all items', () => {
+        cy.get('.bg-header > :nth-child(1) > .q-checkbox > .q-checkbox__inner').click();
+        cy.dataCy('FixedPriceToolbarEditBtn').should('not.be.disabled');
+        cy.dataCy('FixedPriceToolbarEditBtn').click();
+        cy.dataCy('EditFixedPriceSelectOption').type(grouping);
+        cy.get('.q-menu .q-item').contains(grouping).click();
+        cy.dataCy('EditFixedPriceValueOption').type('5');
+        cy.get(saveEditBtn).click();
+        cy.checkNotification('Data saved');
+    });
+
+    it('should remove all items', () => {
+        cy.get('.bg-header > :nth-child(1) > .q-checkbox > .q-checkbox__inner').click();
+        cy.dataCy('crudModelDefaultRemoveBtn').should('not.be.disabled');
+        cy.dataCy('crudModelDefaultRemoveBtn').click();
+        cy.dataCy('VnConfirm_confirm').click();
+        cy.checkNotification('Data saved');
     });
 });
diff --git a/test/cypress/integration/item/itemSummary.spec.js b/test/cypress/integration/item/itemSummary.spec.js
index ad8267ecf..8d67c8e3c 100644
--- a/test/cypress/integration/item/itemSummary.spec.js
+++ b/test/cypress/integration/item/itemSummary.spec.js
@@ -19,6 +19,7 @@ describe('Item summary', () => {
         cy.get('.q-menu > .q-list > :nth-child(1) > .q-item__section').click();
         cy.dataCy('regularizeStockInput').type('10');
         cy.dataCy('Warehouse_select').type('Warehouse One{enter}');
+        cy.dataCy('FormModelPopup_save').click();
         cy.checkNotification('Data created');
     });
 });
diff --git a/test/cypress/integration/outLogin/login.spec.js b/test/cypress/integration/login/login.spec.js
similarity index 75%
rename from test/cypress/integration/outLogin/login.spec.js
rename to test/cypress/integration/login/login.spec.js
index 2bd5a8c3b..22e30dd8e 100755
--- a/test/cypress/integration/outLogin/login.spec.js
+++ b/test/cypress/integration/login/login.spec.js
@@ -12,7 +12,7 @@ describe('Login', () => {
         cy.get('button[type="submit"]').click();
         cy.get('.q-notification__message').should(
             'have.text',
-            'Invalid username or password'
+            'Invalid username or password',
         );
     });
 
@@ -23,7 +23,7 @@ describe('Login', () => {
         cy.get('button[type="submit"]').click();
         cy.get('.q-notification__message').should(
             'have.text',
-            'Invalid username or password'
+            'Invalid username or password',
         );
     });
 
@@ -33,7 +33,7 @@ describe('Login', () => {
         cy.get('button[type="submit"]').click();
         cy.get('.q-notification__message').should(
             'have.text',
-            'You have successfully logged in'
+            'You have successfully logged in',
         );
         cy.url().should('contain', '/dashboard');
     });
@@ -44,7 +44,7 @@ describe('Login', () => {
         cy.get('button[type="submit"]').click();
         cy.get('.q-notification__message').should(
             'have.text',
-            'You have successfully logged in'
+            'You have successfully logged in',
         );
         cy.url().should('contain', '/dashboard');
         cy.get('#user').click();
@@ -61,14 +61,4 @@ describe('Login', () => {
         cy.get('button[type="submit"]').click();
         cy.url().should('contain', '/dashboard');
     });
-
-    // ticket creation is not yet implemented, use this test once it is
-    // it(`should get redirected to ticket creation after login since salesPerson can do it`, () => {
-    //     cy.visit('/#/ticket/create', { failOnStatusCode: false });
-    //     cy.url().should('contain', '/#/login?redirect=/ticket/create');
-    //     cy.get('input[aria-label="Username"]').type('salesPerson');
-    //     cy.get('input[aria-label="Password"]').type('nightmare');
-    //     cy.get('button[type="submit"]').click();
-    //     cy.url().should('contain', '/#/ticket/create');
-    // })
 });
diff --git a/test/cypress/integration/outLogin/logout.spec.js b/test/cypress/integration/login/logout.spec.js
similarity index 80%
rename from test/cypress/integration/outLogin/logout.spec.js
rename to test/cypress/integration/login/logout.spec.js
index 373f0cc93..9f022617d 100644
--- a/test/cypress/integration/outLogin/logout.spec.js
+++ b/test/cypress/integration/login/logout.spec.js
@@ -1,8 +1,8 @@
 /// <reference types="cypress" />
-describe('Logout', () => {
+describe.skip('Logout', () => {
     beforeEach(() => {
         cy.login('developer');
-        cy.visit(`/#/dashboard`, false);
+        cy.visit(`/#/dashboard`);
         cy.waitForElement('.q-page', 6000);
     });
     describe('by user', () => {
@@ -24,11 +24,13 @@ describe('Logout', () => {
                     },
                 },
                 statusMessage: 'AUTHORIZATION_REQUIRED',
-            });
+            }).as('badRequest');
         });
 
         it('when token not exists', () => {
-            cy.get('.q-list').first().should('be.visible').click();
+            cy.get('.q-list').should('be.visible').first().should('be.visible').click();
+            cy.wait('@badRequest');
+
             cy.checkNotification('Authorization Required');
         });
     });
diff --git a/test/cypress/integration/outLogin/recoverPassword.spec.js b/test/cypress/integration/login/recoverPassword.spec.js
similarity index 100%
rename from test/cypress/integration/outLogin/recoverPassword.spec.js
rename to test/cypress/integration/login/recoverPassword.spec.js
diff --git a/test/cypress/integration/outLogin/twoFactor.spec.js b/test/cypress/integration/login/twoFactor.spec.js
similarity index 100%
rename from test/cypress/integration/outLogin/twoFactor.spec.js
rename to test/cypress/integration/login/twoFactor.spec.js
diff --git a/test/cypress/integration/Order/orderCatalog.spec.js b/test/cypress/integration/order/orderCatalog.spec.js
similarity index 93%
rename from test/cypress/integration/Order/orderCatalog.spec.js
rename to test/cypress/integration/order/orderCatalog.spec.js
index a106d0e8a..050dd396c 100644
--- a/test/cypress/integration/Order/orderCatalog.spec.js
+++ b/test/cypress/integration/order/orderCatalog.spec.js
@@ -34,7 +34,7 @@ describe('OrderCatalog', () => {
         searchByCustomTagInput('Silver');
     });
 
-    it('filters by custom value dialog', () => {
+    it.skip('filters by custom value dialog', () => {
         Cypress.on('uncaught:exception', (err) => {
             if (err.message.includes('canceled')) {
                 return false;
@@ -55,9 +55,9 @@ describe('OrderCatalog', () => {
     it('removes a secondary tag', () => {
         cy.get(':nth-child(1) > [data-cy="catalogFilterCategory"]').click();
         cy.selectOption('[data-cy="catalogFilterType"]', 'Anthurium');
-        cy.dataCy('vnFilterPanelChip').should('exist');
+        cy.dataCy('vnFilterPanelChip_typeFk').should('exist');
         cy.get('[data-cy="catalogFilterCustomTag"] > .q-chip__icon--remove').click();
-        cy.dataCy('vnFilterPanelChip').should('not.exist');
+        cy.dataCy('vnFilterPanelChip_typeFk').should('not.exist');
     });
 
     it('Removes category tag', () => {
diff --git a/test/cypress/integration/order/orderList.spec.js b/test/cypress/integration/order/orderList.spec.js
index 8b8852a02..ee011ea05 100644
--- a/test/cypress/integration/order/orderList.spec.js
+++ b/test/cypress/integration/order/orderList.spec.js
@@ -32,10 +32,12 @@ describe('OrderList', () => {
 
     it('filter list and create order', () => {
         cy.dataCy('Customer ID_input').type('1101{enter}');
+        cy.intercept('GET', /\/api\/Clients/).as('clientFilter');
         cy.dataCy('vnTableCreateBtn').click();
+        cy.wait('@clientFilter');
         cy.dataCy('landedDate').find('input').type('06/01/2001');
-        cy.get(agencyCreateSelect).click();
-        cy.get('.q-menu > div> .q-item:nth-child(1)').click();
+        cy.selectOption(agencyCreateSelect, 1);
+
         cy.intercept('GET', /\/api\/Orders\/\d/).as('orderSale');
         cy.get('[data-cy="FormModelPopup_save"] > .q-btn__content > .block').click();
         cy.wait('@orderSale');
@@ -60,8 +62,8 @@ describe('OrderList', () => {
         cy.get(clientCreateSelect).should('have.value', 'Bruce Wayne');
         cy.get(addressCreateSelect).should('have.value', 'Bruce Wayne');
         cy.dataCy('landedDate').find('input').type('06/01/2001');
-        cy.get(agencyCreateSelect).click();
-        cy.get('.q-menu > div> .q-item:nth-child(1)').click();
+        cy.selectOption(agencyCreateSelect, 1);
+
         cy.intercept('GET', /\/api\/Orders\/\d/).as('orderSale');
         cy.get('[data-cy="FormModelPopup_save"] > .q-btn__content > .block').click();
         cy.wait('@orderSale');
diff --git a/test/cypress/integration/route/agency/agencyModes.spec.js b/test/cypress/integration/route/agency/agencyModes.spec.js
new file mode 100644
index 000000000..3f5784997
--- /dev/null
+++ b/test/cypress/integration/route/agency/agencyModes.spec.js
@@ -0,0 +1,15 @@
+describe('Agency modes', () => {
+    const name = 'inhouse pickup';
+
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('developer');
+        cy.visit(`/#/route/agency/1/modes`);
+    });
+
+    it('should display the agency modes page', () => {
+        cy.get('.flex > .title').should('have.text', name);
+        cy.get('.flex > .q-chip > .q-chip__content').should('have.text', 'ID: 1');
+        cy.get('.list-items > :nth-child(1) > .value').should('have.text', name);
+    });
+});
diff --git a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
index 5679ceba1..79dcd6f70 100644
--- a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
+++ b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
@@ -1,27 +1,34 @@
-describe.skip('AgencyWorkCenter', () => {
+describe('AgencyWorkCenter', () => {
+    const selectors = {
+        workCenter: 'workCenter_select',
+        popupSave: 'FormModelPopup_save',
+        popupCancel: 'FormModelPopup_cancel',
+        remove: 'removeWorkCenterBtn',
+    };
+
+    const messages = {
+        dataCreated: 'Data created',
+        alreadyAssigned: 'This workCenter is already assigned to this agency',
+        removed: 'Work center removed successfully',
+    };
+
     beforeEach(() => {
         cy.viewport(1920, 1080);
         cy.login('developer');
         cy.visit(`/#/route/agency/11/workCenter`);
     });
-    const createButton = '.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon';
-    const workCenterCombobox = 'input[role="combobox"]';
 
-    it('check workCenter crud', () => {
-        // create
-        cy.get(createButton).click();
-        cy.get(workCenterCombobox).type('workCenterOne{enter}');
+    it('Should add work center, check already assigned and remove work center', () => {
+        cy.addBtnClick();
+        cy.selectOption('[data-cy="workCenter_select"]', 'workCenterOne');
+        cy.dataCy(selectors.popupSave).click();
         cy.checkNotification('Data created');
-
-        // expect error when duplicate
-        cy.get(createButton).click();
-        cy.selectOption(workCenterCombobox, 'workCenterOne');
-        cy.get('[data-cy="FormModelPopup_save"]').click();
-        cy.checkNotification('This workCenter is already assigned to this agency');
-        cy.get('[data-cy="FormModelPopup_cancel"]').click();
-
-        // delete
-        cy.get('.q-item__section--side > .q-btn > .q-btn__content > .q-icon').click();
-        cy.checkNotification('WorkCenter removed successfully');
+        cy.addBtnClick();
+        cy.selectOption('[data-cy="workCenter_select"]', 'workCenterOne');
+        cy.dataCy(selectors.popupSave).click();
+        cy.checkNotification(messages.alreadyAssigned);
+        cy.dataCy(selectors.popupCancel).click();
+        cy.dataCy(selectors.remove).click();
+        cy.checkNotification(messages.removed);
     });
 });
diff --git a/test/cypress/integration/route/cmr/cmrList.spec.js b/test/cypress/integration/route/cmr/cmrList.spec.js
new file mode 100644
index 000000000..d33508e3a
--- /dev/null
+++ b/test/cypress/integration/route/cmr/cmrList.spec.js
@@ -0,0 +1,91 @@
+describe('Cmr list', () => {
+    const getLinkSelector = (colField) =>
+        `tr:first-child > [data-col-field="${colField}"] > .no-padding > .link`;
+
+    const selectors = {
+        ticket: getLinkSelector('ticketFk'),
+        client: getLinkSelector('clientFk'),
+        lastRowSelectCheckBox:
+            '.q-virtual-scroll__content > tr:last-child > :nth-child(1) > .q-checkbox',
+        downloadBtn: '#subToolbar > .q-btn',
+        viewCmr: 'tableAction-0',
+        descriptorOpenSummaryBtn: '.descriptor [data-cy="openSummaryBtn"]',
+        summaryTitle: '.summaryHeader',
+        descriptorId: '.descriptor .subtitle',
+        descriptorTitle: '.descriptor .title',
+        summaryGoToSummaryBtn: '.summaryHeader [data-cy="goToSummaryBtn"]',
+        descriptorGoToSummaryBtn: '.descriptor [data-cy="goToSummaryBtn"]',
+        removeFilter: '.q-chip__icon--remove',
+    };
+
+    const data = {
+        ticket: '1',
+        client: 'Bruce Wayne',
+    };
+
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('developer');
+        cy.visit('/#/route/cmr');
+        cy.typeSearchbar('{enter}');
+        cy.get(selectors.removeFilter).click();
+    });
+
+    it('Should download selected cmr', () => {
+        const downloadsFolder = Cypress.config('downloadsFolder');
+        cy.get(selectors.lastRowSelectCheckBox).should('be.visible').click();
+        cy.get(selectors.downloadBtn).should('be.visible').click();
+        cy.wait(3000);
+
+        const fileName = 'cmrs.zip';
+        cy.readFile(`${downloadsFolder}/${fileName}`).should('exist');
+    });
+
+    it('Should open selected cmr pdf', () => {
+        cy.window().then((win) => {
+            cy.stub(win, 'open').as('windowOpen');
+        });
+        cy.dataCy(selectors.viewCmr).last().click();
+        cy.get('@windowOpen').should('be.calledWithMatch', '\/api\/Cmrs\/3');
+    });
+
+    describe('Ticket pop-ups', () => {
+        it('Should redirect to the ticket summary from the ticket descriptor pop-up', () => {
+            cy.get(selectors.ticket).should('be.visible').click();
+            cy.containContent(selectors.descriptorId, data.ticket);
+            cy.get(selectors.descriptorGoToSummaryBtn).should('be.visible').click();
+            cy.url().should('include', '/ticket/1/summary');
+            cy.containContent(selectors.summaryTitle, data.client);
+        });
+
+        it('Should redirect to the ticket summary from summary pop-up from the ticket descriptor pop-up', () => {
+            cy.get(selectors.ticket).should('be.visible').click();
+            cy.containContent(selectors.descriptorId, data.ticket);
+            cy.get(selectors.descriptorOpenSummaryBtn).should('be.visible').click();
+            cy.containContent(selectors.summaryTitle, data.client);
+            cy.get(selectors.summaryGoToSummaryBtn).should('be.visible').click();
+            cy.url().should('include', '/ticket/1/summary');
+            cy.containContent(selectors.summaryTitle, data.client);
+        });
+    });
+
+    describe('Client pop-ups', () => {
+        it('Should redirect to the client summary from the client descriptor pop-up', () => {
+            cy.get(selectors.client).should('be.visible').click();
+            cy.containContent(selectors.descriptorTitle, data.client);
+            cy.get(selectors.descriptorGoToSummaryBtn).should('be.visible').click();
+            cy.url().should('include', '/customer/1101/summary');
+            cy.containContent(selectors.summaryTitle, data.client);
+        });
+
+        it('Should redirect to the client summary from summary pop-up from the client descriptor pop-up', () => {
+            cy.get(selectors.client).should('be.visible').click();
+            cy.containContent(selectors.descriptorTitle, data.client);
+            cy.get(selectors.descriptorOpenSummaryBtn).should('be.visible').click();
+            cy.containContent(selectors.summaryTitle, data.client);
+            cy.get(selectors.summaryGoToSummaryBtn).should('be.visible').click();
+            cy.url().should('include', '/customer/1101/summary');
+            cy.containContent(selectors.summaryTitle, data.client);
+        });
+    });
+});
diff --git a/test/cypress/integration/route/roadMap/roadmapList.spec.js b/test/cypress/integration/route/roadMap/roadmapList.spec.js
index 6d46b2cf6..35c0c2b02 100644
--- a/test/cypress/integration/route/roadMap/roadmapList.spec.js
+++ b/test/cypress/integration/route/roadMap/roadmapList.spec.js
@@ -1,12 +1,74 @@
 describe('RoadMap', () => {
+    const getSelector = (colField) =>
+        `tr:last-child > [data-col-field="${colField}"] > .no-padding`;
+
+    const selectors = {
+        roadmap: getSelector('name'),
+        id: getSelector('id'),
+        etd: getSelector('etd'),
+        summaryHeader: '.summaryHeader > :nth-child(2)',
+        summaryGoToSummaryBtn: '.summaryHeader > a > .q-icon',
+        summaryBtn: 'tableAction-0',
+        inputRoadmap: 'Roadmap_input',
+        checkbox: '.q-virtual-scroll__content  tr:last-child .q-checkbox',
+        cloneFormBtn: '.q-card__actions > .q-btn--standard',
+        cloneBtn: '#subToolbar > :nth-child(3)',
+        deleteBtn: ':nth-child(4) > .q-btn__content',
+        confirmBtn: 'VnConfirm_confirm',
+        inputEtd: 'ETD_inputDate',
+    };
+
+    const data = {
+        roadmap: 'TEST-ROADMAP',
+        etd: '01/01/2025',
+    };
+
+    const dataCreated = 'Data created';
+    const summaryUrl = '/summary';
+
     beforeEach(() => {
+        cy.viewport(1920, 1080);
         cy.login('developer');
         cy.visit(`/#/route/roadmap`);
+        cy.typeSearchbar('{enter}');
     });
+
+    it('Should list roadmaps', () => {
+        cy.get('.q-table')
+            .children()
+            .should('be.visible')
+            .should('have.length.greaterThan', 0);
+    });
+
     it('Route list create roadmap and redirect', () => {
         cy.addBtnClick();
-        cy.get('input[name="name"]').type('roadMapTestOne{enter}');
-        cy.get('.q-notification__message').should('have.text', 'Data created');
-        cy.url().should('include', '/summary');
+        cy.dataCy(selectors.inputRoadmap).type(`${data.roadmap}{enter}`);
+        cy.checkNotification(dataCreated);
+        cy.url().should('include', summaryUrl);
+    });
+
+    it('open summary', () => {
+        cy.dataCy(selectors.summaryBtn).last().click();
+        cy.get(selectors.summaryHeader).should('contain', data.roadmap);
+        cy.get(selectors.summaryGoToSummaryBtn).click();
+        cy.get(selectors.summaryHeader).should('contain', data.roadmap);
+    });
+
+    it('Should clone selected roadmap with new ETD', () => {
+        cy.get(selectors.checkbox).click();
+        cy.get(selectors.cloneBtn).click();
+        cy.dataCy(selectors.inputEtd).click().type(`${data.etd}{enter}`);
+        cy.get(selectors.cloneFormBtn).click();
+        cy.get(selectors.etd).should('contain', data.etd);
+    });
+
+    it('Should delete selected roadmap', () => {
+        cy.get(selectors.id).then(($el) => {
+            cy.get(selectors.checkbox).click();
+            cy.get(selectors.deleteBtn).click();
+            cy.dataCy(selectors.confirmBtn).click();
+            cy.typeSearchbar('{enter}');
+            cy.get(selectors.id).should('not.have.text', $el.text);
+        });
     });
 });
diff --git a/test/cypress/integration/route/routeAutonomous.spec.js b/test/cypress/integration/route/routeAutonomous.spec.js
index acf82bd95..d77584c04 100644
--- a/test/cypress/integration/route/routeAutonomous.spec.js
+++ b/test/cypress/integration/route/routeAutonomous.spec.js
@@ -1,4 +1,4 @@
-describe('RouteAutonomous', () => {
+describe.skip('RouteAutonomous', () => {
     const getLinkSelector = (colField) =>
         `tr:first-child > [data-col-field="${colField}"] > .no-padding > .link`;
 
@@ -49,12 +49,12 @@ describe('RouteAutonomous', () => {
         cy.get(selectors.firstRowCheckbox).click();
         cy.get(selectors.createInvoiceBtn).click();
         cy.dataCy(selectors.reference).type(data.reference);
+        cy.dataCy('attachFile').click();
         cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', {
             force: true,
         });
-        cy.dataCy(selectors.saveFormBtn).click();
+        cy.dataCy(selectors.saveFormBtn).should('be.visible').click();
         cy.checkNotification(dataSaved);
-        cy.typeSearchbar('{enter}');
     });
 
     it('Should display the total price of the selected rows', () => {
diff --git a/test/cypress/integration/route/routeExtendedList.spec.js b/test/cypress/integration/route/routeExtendedList.spec.js
index e3505ad60..97735ca4b 100644
--- a/test/cypress/integration/route/routeExtendedList.spec.js
+++ b/test/cypress/integration/route/routeExtendedList.spec.js
@@ -8,6 +8,8 @@ describe.skip('Route extended list', () => {
         date: getSelector('dated'),
         description: getSelector('description'),
         served: getSelector('isOk'),
+        firstRowSelectCheckBox:
+            'tbody > tr:first-child > :nth-child(1) .q-checkbox__inner',
         lastRowSelectCheckBox: 'tbody > tr:last-child > :nth-child(1) .q-checkbox__inner',
         removeBtn: '[title="Remove"]',
         resetBtn: '[title="Reset"]',
@@ -19,7 +21,7 @@ describe.skip('Route extended list', () => {
         markServedBtn: '#st-actions > .q-btn-group > :nth-child(3)',
         searchbar: 'searchbar',
         firstTicketsRowSelectCheckBox:
-            '.q-card > :nth-child(2) > .q-table__container > .q-table__middle > .q-table > tbody > :nth-child(1) > .q-table--col-auto-width > .q-checkbox > .q-checkbox__inner > .q-checkbox__bg > .q-checkbox__svg',
+            '.q-card .q-table > tbody > :nth-child(1)  .q-checkbox',
     };
 
     const checkboxState = {
@@ -32,18 +34,18 @@ describe.skip('Route extended list', () => {
 
     const originalFields = [
         { selector: selectors.worker, type: 'select', value: 'logistic' },
-        { selector: selectors.agency, type: 'select', value: 'Super-Man delivery' },
+        { selector: selectors.agency, type: 'select', value: 'inhouse pickup' },
         { selector: selectors.vehicle, type: 'select', value: '3333-IMK' },
-        { selector: selectors.date, type: 'date', value: '01/02/2024' },
+        { selector: selectors.date, type: 'date', value: '01/01/2001' },
         { selector: selectors.description, type: 'input', value: 'Test route' },
         { selector: selectors.served, type: 'checkbox', value: checkboxState.uncheck },
     ];
 
     const updateFields = [
         { selector: selectors.worker, type: 'select', value: 'salesperson' },
-        { selector: selectors.agency, type: 'select', value: 'inhouse pickup' },
+        { selector: selectors.agency, type: 'select', value: 'Super-Man delivery' },
         { selector: selectors.vehicle, type: 'select', value: '1111-IMK' },
-        { selector: selectors.date, type: 'date', value: '01/01/2001' },
+        { selector: selectors.date, type: 'date', value: '11/01/2001' },
         { selector: selectors.description, type: 'input', value: 'Description updated' },
         { selector: selectors.served, type: 'checkbox', value: checkboxState.check },
     ];
@@ -51,17 +53,20 @@ describe.skip('Route extended list', () => {
     function fillField(selector, type, value) {
         switch (type) {
             case 'select':
-                cy.get(selector).should('be.visible').click();
-                cy.dataCy('null_select').clear().type(value);
+                cy.get(selector).should('be.visible').click().clear().type(value);
                 cy.get('.q-item').contains(value).click();
                 break;
             case 'input':
-                cy.get(selector).should('be.visible').click();
-                cy.dataCy('null_input').clear().type(`${value}{enter}`);
+                cy.get(selector)
+                    .should('be.visible')
+                    .click()
+                    .type(`{selectall}{backspace}${value}`);
                 break;
             case 'date':
-                cy.get(selector).should('be.visible').click();
-                cy.dataCy('null_inputDate').clear().type(`${value}{enter}`);
+                cy.get(selector)
+                    .should('be.visible')
+                    .click()
+                    .type(`{selectall}{backspace}${value}`);
                 break;
             case 'checkbox':
                 cy.get(selector).should('be.visible').click().click();
@@ -76,15 +81,6 @@ describe.skip('Route extended list', () => {
         cy.typeSearchbar('{enter}');
     });
 
-    after(() => {
-        cy.visit(url);
-        cy.typeSearchbar('{enter}');
-        cy.get(selectors.lastRowSelectCheckBox).click();
-
-        cy.get(selectors.removeBtn).click();
-        cy.dataCy(selectors.confirmBtn).click();
-    });
-
     it('Should list routes', () => {
         cy.get('.q-table')
             .children()
@@ -97,9 +93,9 @@ describe.skip('Route extended list', () => {
 
         const data = {
             Worker: { val: 'logistic', type: 'select' },
-            Agency: { val: 'Super-Man delivery', type: 'select' },
+            Agency: { val: 'inhouse pickup', type: 'select' },
             Vehicle: { val: '3333-IMK', type: 'select' },
-            Date: { val: '02-01-2024', type: 'date' },
+            Date: { val: '01-01-2001', type: 'date' },
             From: { val: '01-01-2024', type: 'date' },
             To: { val: '10-01-2024', type: 'date' },
             'Km start': { val: 1000 },
@@ -110,8 +106,8 @@ describe.skip('Route extended list', () => {
         cy.fillInForm(data);
 
         cy.dataCy(selectors.saveFormBtn).click();
-        cy.checkNotification(dataCreated);
         cy.url().should('include', '/summary');
+        cy.checkNotification(dataCreated);
     });
 
     it('Should reset changed values when click reset button', () => {
@@ -126,26 +122,31 @@ describe.skip('Route extended list', () => {
         });
     });
 
-    it('Should clone selected route', () => {
-        cy.get(selectors.lastRowSelectCheckBox).click();
+    it('Should clone selected route and add ticket', () => {
+        cy.get(selectors.firstRowSelectCheckBox).click();
         cy.get(selectors.cloneBtn).click();
-        cy.dataCy('route.Starting date_inputDate').type('10-05-2001{enter}');
+        cy.dataCy('Starting date_inputDate').type('01-01-2001');
         cy.get('.q-card__actions > .q-btn--standard > .q-btn__content').click();
-        cy.validateContent(selectors.date, '05/10/2001');
+        cy.validateContent(selectors.date, '01/01/2001');
+
+        cy.dataCy('tableAction-0').last().click();
+        cy.get(selectors.firstTicketsRowSelectCheckBox).click();
+        cy.get('.q-card__actions > .q-btn--standard > .q-btn__content').click();
+        cy.checkNotification(dataSaved);
+
+        cy.get(selectors.lastRowSelectCheckBox).click();
+        cy.get(selectors.removeBtn).click();
+        cy.dataCy(selectors.confirmBtn).click();
     });
 
     it('Should download selected route', () => {
         const downloadsFolder = Cypress.config('downloadsFolder');
         cy.get(selectors.lastRowSelectCheckBox).click();
         cy.get(selectors.downloadBtn).click();
-        cy.wait(5000);
+        cy.wait(3000);
 
         const fileName = 'download.zip';
         cy.readFile(`${downloadsFolder}/${fileName}`).should('exist');
-
-        cy.task('deleteFile', `${downloadsFolder}/${fileName}`).then((deleted) => {
-            expect(deleted).to.be.true;
-        });
     });
 
     it('Should mark as served the selected route', () => {
@@ -158,7 +159,6 @@ describe.skip('Route extended list', () => {
 
     it('Should delete the selected route', () => {
         cy.get(selectors.lastRowSelectCheckBox).click();
-
         cy.get(selectors.removeBtn).click();
         cy.dataCy(selectors.confirmBtn).click();
 
@@ -175,18 +175,15 @@ describe.skip('Route extended list', () => {
 
         cy.typeSearchbar('{enter}');
 
-        updateFields.forEach(({ selector, value }) => {
-            cy.validateContent(selector, value);
+        updateFields.forEach(({ selector, value, type }) => {
+            if (type === 'date') {
+                const [month, day, year] = value.split('/');
+                value = `${day}/${month}/${year}`;
+            }
+            cy.get(selector).should('contain', value);
         });
     });
 
-    it('Should add ticket to route', () => {
-        cy.dataCy('tableAction-0').last().click();
-        cy.get(selectors.firstTicketsRowSelectCheckBox).click();
-        cy.get('.q-card__actions > .q-btn--standard > .q-btn__content').click();
-        cy.checkNotification(dataSaved);
-    });
-
     it('Should open summary pop-up when click summuary icon', () => {
         cy.dataCy('tableAction-1').last().click();
         cy.get('.summaryHeader > :nth-child(2').should('contain', updateFields[4].value);
diff --git a/test/cypress/integration/route/routeList.spec.js b/test/cypress/integration/route/routeList.spec.js
index 04278cfc5..f08c267a4 100644
--- a/test/cypress/integration/route/routeList.spec.js
+++ b/test/cypress/integration/route/routeList.spec.js
@@ -1,37 +1,205 @@
 describe('Route', () => {
+    const getSelector = (colField) =>
+        `tr:last-child > [data-col-field="${colField}"] > .no-padding > .link`;
+
+    const selectors = {
+        lastRow: 'tr:last-child > [data-col-field="workerFk"]',
+        workerLink: getSelector('workerFk'),
+        agencyLink: getSelector('agencyModeFk'),
+        vehicleLink: getSelector('vehicleFk'),
+        assignedTicketsBtn: 'tableAction-0',
+        rowSummaryBtn: 'tableAction-1',
+        summaryTitle: '.summaryHeader',
+        descriptorTitle: '.descriptor .title',
+        descriptorOpenSummaryBtn: '.descriptor [data-cy="openSummaryBtn"]',
+        descriptorGoToSummaryBtn: '.descriptor [data-cy="goToSummaryBtn"]',
+        SummaryGoToSummaryBtn: '.summaryHeader [data-cy="goToSummaryBtn"]',
+    };
+
+    const data = {
+        Worker: { val: 'logistic', type: 'select' },
+        Agency: { val: 'Walking', type: 'select' },
+        Vehicle: { val: '3333-BAT', type: 'select' },
+        Description: { val: 'routeTest' },
+    };
+
+    const summaryUrl = '/summary';
+
     beforeEach(() => {
         cy.viewport(1920, 1080);
         cy.login('developer');
-        cy.visit(`/#/route/extended-list`);
+        cy.visit(`/#/route/list`);
+        cy.typeSearchbar('{enter}');
     });
 
-    it('Route list create route', () => {
+    it('Should list routes', () => {
+        cy.get('.q-table')
+            .children()
+            .should('be.visible')
+            .should('have.length.greaterThan', 0);
+    });
+
+    it('Should create new route', () => {
         cy.addBtnClick();
-        cy.get('.q-card input[name="description"]').type('routeTestOne{enter}');
-        cy.get('.q-notification__message').should('have.text', 'Data created');
-        cy.url().should('include', '/summary');
+
+        cy.fillInForm(data);
+
+        cy.dataCy('FormModelPopup_save').should('be.visible').click();
+
+        cy.checkNotification('Data created');
+        cy.url().should('include', summaryUrl);
+        cy.get(selectors.summaryTitle)
+            .invoke('text')
+            .then((text) => {
+                expect(text).to.include(data.Description.val);
+            });
     });
 
-    it('Route list search and edit', () => {
-        cy.get('#searchbar input').type('{enter}');
-        cy.get('[data-col-field="description"][data-row-index="0"]')
-            .click()
-            .type('routeTestOne{enter}');
-        cy.get('.q-table tr')
-            .its('length')
-            .then((rowCount) => {
-                expect(rowCount).to.be.greaterThan(0);
+    it('Should open route summary by clicking a route', () => {
+        cy.get(selectors.lastRow).should('be.visible').click();
+        cy.url().should('include', summaryUrl);
+        cy.get(selectors.summaryTitle)
+            .invoke('text')
+            .then((text) => {
+                expect(text).to.include(data.Description.val);
             });
-        cy.get('[data-col-field="workerFk"][data-row-index="0"]')
-            .click()
-            .type('{downArrow}{enter}');
-        cy.get('[data-col-field="agencyModeFk"][data-row-index="0"]')
-            .click()
-            .type('{downArrow}{enter}');
-        cy.get('[data-col-field="vehicleFk"][data-row-index="0"]')
-            .click()
-            .type('{downArrow}{enter}');
-        cy.get('button[title="Save"]').click();
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
+    });
+
+    it('Should redirect to the summary from the route pop-up summary', () => {
+        cy.dataCy(selectors.rowSummaryBtn).last().should('be.visible').click();
+        cy.get(selectors.summaryTitle)
+            .invoke('text')
+            .then((text) => {
+                expect(text).to.include(data.Description.val);
+            });
+        cy.get(selectors.SummaryGoToSummaryBtn).click();
+        cy.get(selectors.summaryTitle)
+            .invoke('text')
+            .then((text) => {
+                expect(text).to.include(data.Description.val);
+            });
+    });
+
+    it('Should redirect to the route assigned tickets from the row assignedTicketsBtn', () => {
+        cy.dataCy(selectors.assignedTicketsBtn).first().should('be.visible').click();
+        cy.url().should('include', '1/tickets');
+        cy.get('.q-table')
+            .children()
+            .should('be.visible')
+            .should('have.length.greaterThan', 0);
+    });
+
+    describe('Worker pop-ups', () => {
+        it('Should redirect to summary from the worker pop-up descriptor', () => {
+            cy.get(selectors.workerLink).click();
+            cy.get(selectors.descriptorTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Worker.val);
+                });
+            cy.get(selectors.descriptorGoToSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Worker.val);
+                });
+        });
+
+        it('Should redirect to the summary from the worker pop-up summary', () => {
+            cy.get(selectors.workerLink).click();
+            cy.get(selectors.descriptorTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Worker.val);
+                });
+            cy.get(selectors.descriptorOpenSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Worker.val);
+                });
+            cy.get(selectors.SummaryGoToSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Worker.val);
+                });
+        });
+    });
+
+    describe('Agency pop-ups', () => {
+        it('Should redirect to summary from the agency pop-up descriptor', () => {
+            cy.get(selectors.agencyLink).click();
+            cy.get(selectors.descriptorTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Agency.val);
+                });
+            cy.get(selectors.descriptorGoToSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Agency.val);
+                });
+        });
+
+        it('Should redirect to the summary from the agency pop-up summary', () => {
+            cy.get(selectors.agencyLink).click();
+            cy.get(selectors.descriptorTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Agency.val);
+                });
+            cy.get(selectors.descriptorOpenSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Agency.val);
+                });
+            cy.get(selectors.SummaryGoToSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Agency.val);
+                });
+        });
+    });
+
+    describe('Vehicle pop-ups', () => {
+        it('Should redirect to summary from the vehicle pop-up descriptor', () => {
+            cy.get(selectors.vehicleLink).click();
+            cy.get(selectors.descriptorTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Vehicle.val);
+                });
+            cy.get(selectors.descriptorGoToSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Vehicle.val);
+                });
+        });
+
+        it('Should redirect to the summary from the vehicle pop-up summary', () => {
+            cy.get(selectors.vehicleLink).click();
+            cy.get(selectors.descriptorTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Vehicle.val);
+                });
+            cy.get(selectors.descriptorOpenSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Vehicle.val);
+                });
+            cy.get(selectors.SummaryGoToSummaryBtn).click();
+            cy.get(selectors.summaryTitle)
+                .invoke('text')
+                .then((text) => {
+                    expect(text).to.include(data.Vehicle.val);
+                });
+        });
     });
 });
diff --git a/test/cypress/integration/route/vehicle/vehicleDescriptor.spec.js b/test/cypress/integration/route/vehicle/vehicleDescriptor.spec.js
index 64b9ca0a0..3e9c816c4 100644
--- a/test/cypress/integration/route/vehicle/vehicleDescriptor.spec.js
+++ b/test/cypress/integration/route/vehicle/vehicleDescriptor.spec.js
@@ -2,11 +2,11 @@ describe('Vehicle', () => {
     beforeEach(() => {
         cy.viewport(1920, 1080);
         cy.login('deliveryAssistant');
-        cy.visit(`/#/route/vehicle/7`);
+        cy.visit(`/#/route/vehicle/7/summary`);
     });
 
     it('should delete a vehicle', () => {
-        cy.openActionsDescriptor();
+        cy.dataCy('descriptor-more-opts').click();
         cy.get('[data-cy="delete"]').click();
         cy.checkNotification('Vehicle removed');
     });
diff --git a/test/cypress/integration/route/vehicle/vehicleNotes.spec.js b/test/cypress/integration/route/vehicle/vehicleNotes.spec.js
new file mode 100644
index 000000000..cd92cc4af
--- /dev/null
+++ b/test/cypress/integration/route/vehicle/vehicleNotes.spec.js
@@ -0,0 +1,28 @@
+describe('Vehicle Notes', () => {
+    const selectors = {
+        addNoteInput: 'Add note here..._input',
+        saveNoteBtn: 'saveNote',
+        deleteNoteBtn: 'notesRemoveNoteBtn',
+        noteCard: '.column.full-width > :nth-child(1) > .q-card__section--vert',
+    };
+
+    const noteText = 'Golpe parachoques trasero';
+    const newNoteText = 'probando';
+
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('developer');
+        cy.visit(`/#/route/vehicle/1/notes`);
+    });
+
+    it('Should add new note', () => {
+        cy.dataCy(selectors.addNoteInput).should('be.visible').type(newNoteText);
+        cy.dataCy(selectors.saveNoteBtn).click();
+        cy.validateContent(selectors.noteCard, newNoteText);
+    });
+
+    it('Should delete note', () => {
+        cy.dataCy(selectors.deleteNoteBtn).first().should('be.visible').click();
+        cy.get(selectors.noteCard).first().should('have.text', noteText);
+    });
+});
diff --git a/test/cypress/integration/shelving/parking/parkingList.spec.js b/test/cypress/integration/shelving/parking/parkingList.spec.js
index ca1877621..7372da164 100644
--- a/test/cypress/integration/shelving/parking/parkingList.spec.js
+++ b/test/cypress/integration/shelving/parking/parkingList.spec.js
@@ -2,7 +2,7 @@
 describe('ParkingList', () => {
     const searchbar = '#searchbar input';
     const firstCard = ':nth-child(1) > .q-card > .no-margin > .q-py-none';
-    const summaryHeader = '.summaryBody .header';
+    const summaryHeader = '.header-link';
 
     beforeEach(() => {
         cy.viewport(1920, 1080);
diff --git a/test/cypress/integration/shelving/shelvingList.spec.js b/test/cypress/integration/shelving/shelvingList.spec.js
index 745dd1b78..20b72e419 100644
--- a/test/cypress/integration/shelving/shelvingList.spec.js
+++ b/test/cypress/integration/shelving/shelvingList.spec.js
@@ -16,8 +16,8 @@ describe('ShelvingList', () => {
     it('should redirect from preview to basic-data', () => {
         cy.typeSearchbar('{enter}');
         cy.dataCy('cardBtn').eq(0).click();
-        cy.get('.q-card > .header').click();
-        cy.url().should('include', '/shelving/1/basic-data');
+        cy.get('.summaryHeader > .header > .q-icon').click();
+        cy.url().should('include', '/shelving/1/summary');
     });
 
     it('should filter and redirect if only one result', () => {
diff --git a/test/cypress/integration/Supplier/SupplierBalance.spec.js b/test/cypress/integration/supplier/SupplierBalance.spec.js
similarity index 100%
rename from test/cypress/integration/Supplier/SupplierBalance.spec.js
rename to test/cypress/integration/supplier/SupplierBalance.spec.js
diff --git a/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js b/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js
index 19f4dc3b2..b4997fa69 100644
--- a/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js
+++ b/test/cypress/integration/ticket/negative/TicketLackDetail.spec.js
@@ -138,7 +138,7 @@ describe.skip('Ticket Lack detail', () => {
             cy.get('[data-cy="itemProposal"]').click();
             cy.wait('@getItemGetSimilar');
         });
-        describe('Replace item if', () => {
+        describe.skip('Replace item if', () => {
             it('Quantity is less than available', () => {
                 cy.get(':nth-child(1) > .text-right  > .q-btn').click();
             });
diff --git a/test/cypress/integration/ticket/ticketBasicData.spec.js b/test/cypress/integration/ticket/ticketBasicData.spec.js
new file mode 100644
index 000000000..443e9569b
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketBasicData.spec.js
@@ -0,0 +1,46 @@
+/// <reference types="cypress" />
+describe('TicketBasicData', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/31/basic-data');
+    });
+
+    it('Should redirect to customer basic data', () => {
+        cy.get('.q-page').should('be.visible');
+        cy.get(':nth-child(2) > div > .text-primary').click();
+        cy.dataCy('Address_select').click();
+        cy.get('.q-btn-group ').find('.q-btn__content > .q-icon').click();
+        cy.get(
+            '[data-cy="CustomerBasicData-menu-item"] > .q-item__section--main',
+        ).click();
+        cy.url().should('include', '/customer/1104/basic-data');
+    });
+    it.only('stepper', () => {
+        cy.get('.q-stepper__tab--active').should('have.class', 'q-stepper__tab--active');
+
+        cy.get('.q-stepper__nav > .q-btn--standard').click();
+        cy.get('.q-stepper__tab--done').should('have.class', 'q-stepper__tab--done');
+        cy.get('.q-stepper__tab--active').should('have.class', 'q-stepper__tab--active');
+        cy.get('tr:nth-child(1)>:nth-child(1)>span').should('have.class', 'link').click();
+        cy.dataCy('ItemDescriptor').should('exist');
+
+        cy.get('.q-drawer__content > :nth-child(1)').each(() => {
+            cy.get('span').should('contain.text', 'Price: €');
+            cy.get('span').should('contain.text', 'New price: €');
+            cy.get('span').should('contain.text', 'Difference: €');
+        });
+        cy.get(
+            ':nth-child(3) > .q-radio > .q-radio__inner > .q-radio__bg > .q-radio__check',
+        ).should('have.class', 'q-radio__check');
+        cy.get(
+            '.q-stepper__step-inner > .q-drawer-container > .q-drawer > .q-drawer__content',
+        ).click();
+        cy.get(':nth-child(2) > :nth-child(1) > .text-weight-bold').click();
+        cy.get(':nth-child(3) > .q-radio > .q-radio__inner').should(
+            'have.class',
+            'q-radio__inner--truthy',
+        );
+        cy.get('.q-drawer__content > :nth-child(2)').click();
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketComponents.spec.js b/test/cypress/integration/ticket/ticketComponents.spec.js
new file mode 100644
index 000000000..23dbf8bcd
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketComponents.spec.js
@@ -0,0 +1,30 @@
+/// <reference types="cypress" />
+
+describe('TicketComponents', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/1/components');
+    });
+    it('Should load layout', () => {
+        cy.get('.q-page').should('be.visible');
+        cy.validateScrollContent([
+            { row: 2, col: 2, text: 'Base to commission: €799.20' },
+            { row: 2, col: 3, text: 'Total without VAT: €807.20' },
+            { row: 3, col: 2, text: 'valor de compra: €425.000' },
+            { row: 3, col: 4, text: 'maná auto: €7.998' },
+            { row: 4, col: 2, text: 'Price: €5.00' },
+            { row: 4, col: 3, text: 'Bonus: €1.00' },
+            { row: 4, col: 5, text: 'Packages: 6' },
+            { row: 4, col: 4, text: 'Zone: Zone pickup A ' },
+            { row: 5, col: 2, text: 'Total price: €16.00' },
+        ]);
+        cy.get(':nth-child(4) > .link').click();
+
+        cy.dataCy('ZoneDescriptor').should('exist');
+        cy.getRowCol('total').should('have.text', '€250.000€247.000€4.970');
+        cy.getRowCol('import').should('have.text', '€50.000€49.400€0.994');
+        cy.getRowCol('components').should('have.text', 'valor de compramargenmaná auto');
+        cy.getRowCol('serie').should('have.text', 'costeempresacartera_comercial');
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketDescriptor.spec.js b/test/cypress/integration/ticket/ticketDescriptor.spec.js
index 0ba2723a2..b5c95c463 100644
--- a/test/cypress/integration/ticket/ticketDescriptor.spec.js
+++ b/test/cypress/integration/ticket/ticketDescriptor.spec.js
@@ -3,10 +3,10 @@ describe('Ticket descriptor', () => {
     const listItem = '[role="menu"] .q-list .q-item';
     const toCloneOpt = 'To clone ticket';
     const setWeightOpt = 'Set weight';
-    const warehouseValue = ':nth-child(1) > :nth-child(6) > .value > span';
+    const warehouseValue = ':nth-child(1) > [data-cy="vnLvWarehouse"]';
     const summaryHeader = '.summaryHeader > div';
     const weight = 25;
-    const weightValue = '.summaryBody.row :nth-child(1) > :nth-child(9) > .value > span';
+    const weightValue = '[data-cy="vnLvWeight"]';
     beforeEach(() => {
         cy.login('developer');
         cy.viewport(1920, 1080);
diff --git a/test/cypress/integration/ticket/ticketList.spec.js b/test/cypress/integration/ticket/ticketList.spec.js
index 25ee05033..e18025319 100644
--- a/test/cypress/integration/ticket/ticketList.spec.js
+++ b/test/cypress/integration/ticket/ticketList.spec.js
@@ -1,7 +1,5 @@
 /// <reference types="cypress" />
 describe('TicketList', () => {
-    const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)';
-
     beforeEach(() => {
         cy.login('developer');
         cy.viewport(1920, 1080);
@@ -11,7 +9,7 @@ describe('TicketList', () => {
     const searchResults = (search) => {
         if (search) cy.typeSearchbar().type(search);
         cy.dataCy('vn-searchbar').find('input').type('{enter}');
-        cy.get(firstRow).should('exist');
+        cy.getRow().should('exist');
     };
 
     it('should search results', () => {
@@ -24,13 +22,13 @@ describe('TicketList', () => {
         cy.window().then((win) => {
             cy.stub(win, 'open').as('windowOpen');
         });
-        cy.get(firstRow).should('be.visible').find('.q-btn:first').click();
+        cy.getRow().should('be.visible').find('.q-btn:first').click();
         cy.get('@windowOpen').should('be.calledWithMatch', /\/ticket\/\d+\/sale/);
     });
 
     it('should open ticket summary', () => {
         searchResults();
-        cy.get(firstRow).find('.q-btn:last').click();
+        cy.getRow().find('.q-btn:last').click();
         cy.get('.summaryHeader').should('exist');
         cy.get('.summaryBody').should('exist');
     });
@@ -38,12 +36,14 @@ describe('TicketList', () => {
     it('filter client and create ticket', () => {
         cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar');
         searchResults();
+        cy.wait('@ticketSearchbar');
 
-        cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketFilter');
         cy.dataCy('Customer ID_input').clear('1');
         cy.dataCy('Customer ID_input').type('1101{enter}');
 
-        cy.get('[data-cy="vnTableCreateBtn"] > .q-btn__content > .q-icon').click();
+        cy.intercept('GET', /\/api\/Clients\?filter/).as('clientFilter');
+        cy.vnTableCreateBtn();
+        cy.wait('@clientFilter');
         cy.dataCy('Customer_select').should('have.value', 'Bruce Wayne');
         cy.dataCy('Address_select').click();
 
@@ -51,8 +51,7 @@ describe('TicketList', () => {
         cy.dataCy('Address_select').should('have.value', 'Bruce Wayne');
     });
     it('Client list create new ticket', () => {
-        cy.dataCy('vnTableCreateBtn').should('exist');
-        cy.dataCy('vnTableCreateBtn').click();
+        cy.vnTableCreateBtn();
         const data = {
             Customer: { val: 1, type: 'select' },
             Warehouse: { val: 'Warehouse One', type: 'select' },
diff --git a/test/cypress/integration/ticket/ticketNotes.spec.js b/test/cypress/integration/ticket/ticketNotes.spec.js
index 5b44f9e1f..df1ff9137 100644
--- a/test/cypress/integration/ticket/ticketNotes.spec.js
+++ b/test/cypress/integration/ticket/ticketNotes.spec.js
@@ -19,7 +19,7 @@ describe('TicketNotes', () => {
         cy.checkNotification('Data saved');
         cy.dataCy('ticketNotesRemoveNoteBtn').should('exist');
         cy.dataCy('ticketNotesRemoveNoteBtn').click();
-        cy.dataCy('VnConfirm_confirm').click();
+        cy.confirmVnConfirm();
         cy.checkNotification('Data saved');
     });
 });
diff --git a/test/cypress/integration/ticket/ticketPackage.spec.js b/test/cypress/integration/ticket/ticketPackage.spec.js
new file mode 100644
index 000000000..992efd53b
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketPackage.spec.js
@@ -0,0 +1,21 @@
+/// <reference types="cypress" />
+describe('TicketPackages', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/31/package');
+    });
+
+    it('Should load layout', () => {
+        cy.get('.q-page').should('be.visible');
+        cy.get('.vn-row > .q-btn > .q-btn__content > .q-icon').click();
+        cy.dataCy('Package_select').click();
+        cy.get('.q-menu :nth-child(1) >.q-item__section').click();
+        cy.dataCy('Quantity_input').clear().type('5');
+        cy.saveCrudModel();
+        cy.checkNotification('Data saved');
+        cy.get('.q-mb-md > .text-primary').click();
+        cy.confirmVnConfirm();
+        cy.checkNotification('Data saved');
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketPictures.spec.js b/test/cypress/integration/ticket/ticketPictures.spec.js
new file mode 100644
index 000000000..1165b54bf
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketPictures.spec.js
@@ -0,0 +1,18 @@
+/// <reference types="cypress" />
+describe('TicketPictures', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/31/picture');
+    });
+    it('Should load layout', () => {
+        cy.get(':nth-child(1) > .q-card > .content').should('be.visible');
+        cy.get('.content > .link').should('be.visible').click();
+        cy.dataCy('ItemDescriptor').should('exist');
+        cy.dataCy('vnLvColor:');
+        cy.dataCy('vnLvColor:');
+        cy.dataCy('vnLvTallos:');
+        cy.get('.q-mt-md').should('be.visible');
+        cy.get(':nth-child(1) > .q-card > .img-wrapper').should('be.visible');
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketRequest.spec.js b/test/cypress/integration/ticket/ticketRequest.spec.js
index b9dc509ef..3b237826e 100644
--- a/test/cypress/integration/ticket/ticketRequest.spec.js
+++ b/test/cypress/integration/ticket/ticketRequest.spec.js
@@ -7,8 +7,7 @@ describe('TicketRequest', () => {
     });
 
     it('Creates a new request', () => {
-        cy.dataCy('vnTableCreateBtn').should('exist');
-        cy.dataCy('vnTableCreateBtn').click();
+        cy.vnTableCreateBtn();
         const data = {
             Description: { val: 'Purchase description' },
             Atender: { val: 'buyerNick', type: 'select' },
diff --git a/test/cypress/integration/ticket/ticketSale.spec.js b/test/cypress/integration/ticket/ticketSale.spec.js
index 81ea761c4..f433f0d11 100644
--- a/test/cypress/integration/ticket/ticketSale.spec.js
+++ b/test/cypress/integration/ticket/ticketSale.spec.js
@@ -1,20 +1,112 @@
 /// <reference types="cypress" />
+const firstRow = 'tbody > :nth-child(1)';
 
 describe('TicketSale', () => {
-    describe.skip('Free ticket #31', () => {
+    describe('#23', () => {
+        beforeEach(() => {
+            cy.login('salesBoss');
+            cy.viewport(1920, 1080);
+            cy.visit('/#/ticket/23/sale');
+        });
+
+        it('update price', () => {
+            const price = Number((Math.random() * 99 + 1).toFixed(2));
+            cy.waitForElement(firstRow);
+            cy.get('[data-col-field="price"]').find('.q-btn').click();
+            cy.waitForElement('[data-cy="ticketEditManaProxy"]');
+            cy.dataCy('ticketEditManaProxy').should('exist');
+            cy.waitForElement('[data-cy="Price_input"]');
+            cy.dataCy('Price_input').clear().type(price);
+            cy.intercept('POST', /\/api\/Sales\/\d+\/updatePrice/).as('updatePrice');
+
+            cy.dataCy('saveManaBtn').click();
+            handleVnConfirm();
+            cy.wait('@updatePrice').its('response.statusCode').should('eq', 200);
+
+            cy.get('[data-col-field="price"]')
+                .find('.q-btn > .q-btn__content')
+                .should('contain.text', `€${price}`);
+        });
+        it('update discount', () => {
+            const discount = Math.floor(Math.random() * 100) + 1;
+            selectFirstRow();
+            cy.get('[data-col-field="discount"]').find('.q-btn').click();
+            cy.waitForElement('[data-cy="ticketEditManaProxy"]');
+            cy.dataCy('ticketEditManaProxy').should('exist');
+            cy.waitForElement('[data-cy="Disc_input"]');
+            cy.dataCy('Disc_input').clear().type(discount);
+            cy.intercept('POST', /\/api\/Tickets\/\d+\/updateDiscount/).as(
+                'updateDiscount',
+            );
+
+            cy.dataCy('saveManaBtn').click();
+            handleVnConfirm();
+            cy.wait('@updateDiscount').its('response.statusCode').should('eq', 204);
+
+            cy.get('[data-col-field="discount"]')
+                .find('.q-btn > .q-btn__content')
+                .should('have.text', `${discount}.00%`);
+        });
+
+        it('change concept', () => {
+            const concept = Math.floor(Math.random() * 100) + 1;
+            cy.waitForElement(firstRow);
+            cy.get('[data-col-field="item"]').click();
+            cy.intercept('POST', '**/api').as('postRequest');
+
+            cy.get('.q-menu')
+                .find('[data-cy="undefined_input"]')
+                .type(concept)
+                .type('{enter}');
+            handleVnConfirm();
+
+            cy.get('[data-col-field="item"]').should('contain.text', `${concept}`);
+        });
+        it('change quantity ', () => {
+            const quantity = Math.floor(Math.random() * 100) + 1;
+            cy.waitForElement(firstRow);
+            cy.dataCy('ticketSaleQuantityInput').find('input').clear();
+            cy.intercept('POST', '**/api').as('postRequest');
+
+            cy.dataCy('ticketSaleQuantityInput')
+                .find('input')
+                .type(quantity)
+                .trigger('tab');
+            cy.get('.q-page > :nth-child(6)').click();
+
+            handleVnConfirm();
+
+            cy.get('[data-cy="ticketSaleQuantityInput"]')
+                .find('input')
+                .should('have.value', `${quantity}`);
+        });
+    });
+    describe('#24 add claim', () => {
+        beforeEach(() => {
+            cy.login('developer');
+            cy.viewport(1920, 1080);
+            cy.visit('/#/ticket/24/sale');
+        });
+
+        it('adds claim', () => {
+            selectFirstRow();
+            cy.dataCy('ticketSaleMoreActionsDropdown').click();
+            cy.dataCy('createClaimItem').click();
+            cy.confirmVnConfirm();
+            cy.url().should('contain', 'claim/');
+            // Delete created claim to avoid cluttering the database
+            cy.dataCy('descriptor-more-opts').click();
+            cy.dataCy('deleteClaim').click();
+            cy.confirmVnConfirm();
+        });
+    });
+    describe('#31 free ticket', () => {
         beforeEach(() => {
             cy.login('developer');
             cy.viewport(1920, 1080);
             cy.visit('/#/ticket/31/sale');
         });
 
-        const firstRow = 'tbody > :nth-child(1)';
-
-        const selectFirstRow = () => {
-            cy.waitForElement(firstRow);
-            cy.get(firstRow).find('.q-checkbox__inner').click();
-        };
-
         it('it should add item to basket', () => {
             cy.window().then((win) => {
                 cy.stub(win, 'open').as('windowOpen');
@@ -44,9 +136,12 @@ describe('TicketSale', () => {
             cy.dataCy('recalculatePriceItem').click();
             cy.wait('@recalculatePrice').its('response.statusCode').should('eq', 200);
             cy.checkNotification('Data saved');
+            cy.dataCy('ticketSaleMoreActionsDropdown').should('be.disabled');
         });
 
-        it('should update discount when "Update discount" is clicked', () => {
+        it.only('should update discount when "Update discount" is clicked', () => {
+            const discount = Number((Math.random() * 99 + 1).toFixed(2));
+
             selectFirstRow();
             cy.dataCy('ticketSaleMoreActionsDropdown').click();
             cy.waitForElement('[data-cy="updateDiscountItem"]');
@@ -54,39 +149,23 @@ describe('TicketSale', () => {
             cy.dataCy('updateDiscountItem').click();
             cy.waitForElement('[data-cy="ticketSaleDiscountInput"]');
             cy.dataCy('ticketSaleDiscountInput').find('input').focus();
-            cy.dataCy('ticketSaleDiscountInput').find('input').type('10');
+            cy.intercept('POST', /\/api\/Tickets\/\d+\/updateDiscount/).as(
+                'updateDiscount',
+            );
+            cy.dataCy('ticketSaleDiscountInput').find('input').type(discount);
+
             cy.dataCy('saveManaBtn').click();
-            cy.waitForElement('.q-notification__message');
+            cy.wait('@updateDiscount').its('response.statusCode').should('eq', 204);
             cy.checkNotification('Data saved');
+            cy.dataCy('ticketSaleMoreActionsDropdown').should('be.disabled');
         });
 
         it('adds claim', () => {
             selectFirstRow();
             cy.dataCy('ticketSaleMoreActionsDropdown').click();
             cy.dataCy('createClaimItem').click();
-            cy.dataCy('VnConfirm_confirm').click();
-            cy.url().should('contain', 'claim/');
-            // Delete created claim to avoid cluttering the database
-            cy.dataCy('descriptor-more-opts').click();
-            cy.dataCy('deleteClaim').click();
-            cy.dataCy('VnConfirm_confirm').click();
-            cy.checkNotification('Data deleted');
-        });
-
-        it('marks row as reserved', () => {
-            selectFirstRow();
-            cy.dataCy('ticketSaleMoreActionsDropdown').click();
-            cy.waitForElement('[data-cy="markAsReservedItem"]');
-            cy.dataCy('markAsReservedItem').click();
-            cy.dataCy('ticketSaleReservedIcon').should('exist');
-        });
-
-        it('unmarks row as reserved', () => {
-            selectFirstRow();
-            cy.dataCy('ticketSaleMoreActionsDropdown').click();
-            cy.waitForElement('[data-cy="unmarkAsReservedItem"]');
-            cy.dataCy('unmarkAsReservedItem').click();
-            cy.dataCy('ticketSaleReservedIcon').should('not.exist');
+            cy.confirmVnConfirm();
+            cy.checkNotification('Future ticket date not allowed');
         });
 
         it('refunds row with warehouse', () => {
@@ -105,8 +184,18 @@ describe('TicketSale', () => {
             cy.checkNotification('The following refund ticket have been created');
         });
 
-        it('transfer sale to a new ticket', () => {
+        it('should redirect to ticket logs', () => {
+            cy.get(firstRow).find('.q-btn:last').click();
+            cy.url().should('match', /\/ticket\/31\/log/);
+        });
+    });
+    describe('#32 transfer', () => {
+        beforeEach(() => {
+            cy.login('developer');
+            cy.viewport(1920, 1080);
             cy.visit('/#/ticket/32/sale');
+        });
+        it('transfer sale to a new ticket', () => {
             cy.get('.q-item > .q-item__label').should('have.text', ' #32');
             selectFirstRow();
             cy.dataCy('ticketSaleTransferBtn').click();
@@ -114,94 +203,14 @@ describe('TicketSale', () => {
             cy.dataCy('ticketTransferNewTicketBtn').click();
             cy.get('.q-item > .q-item__label').should('not.have.text', ' #32');
         });
-
-        it('should redirect to ticket logs', () => {
-            cy.get(firstRow).find('.q-btn:last').click();
-            cy.url().should('match', /\/ticket\/31\/log/);
-        });
-    });
-    describe.skip('Ticket prepared #23', () => {
-        beforeEach(() => {
-            cy.login('developer');
-            cy.viewport(1920, 1080);
-            cy.visit('/#/ticket/23/sale');
-        });
-
-        const firstRow = 'tbody > :nth-child(1)';
-
-        const selectFirstRow = () => {
-            cy.waitForElement(firstRow);
-            cy.get(firstRow).find('.q-checkbox__inner').click();
-        };
-
-        it('update price', () => {
-            const price = Number((Math.random() * 99 + 1).toFixed(2));
-            cy.waitForElement(firstRow);
-            cy.get('[data-col-field="price"]').find('.q-btn').click();
-            cy.waitForElement('[data-cy="ticketEditManaProxy"]');
-            cy.dataCy('ticketEditManaProxy').should('exist');
-            cy.waitForElement('[data-cy="Price_input"]');
-            cy.dataCy('Price_input').clear();
-            cy.dataCy('Price_input').type(price);
-            cy.dataCy('saveManaBtn').click();
-            handleVnConfirm();
-
-            cy.get('[data-col-field="price"]')
-                .find('.q-btn > .q-btn__content')
-                .should('have.text', `€${price}`);
-        });
-        it('update discount', () => {
-            const discount = Math.floor(Math.random() * 100) + 1;
-            selectFirstRow();
-            cy.get('[data-col-field="discount"]').find('.q-btn').click();
-            cy.waitForElement('[data-cy="ticketEditManaProxy"]');
-            cy.dataCy('ticketEditManaProxy').should('exist');
-            cy.waitForElement('[data-cy="Disc_input"]');
-            cy.dataCy('Disc_input').clear();
-            cy.dataCy('Disc_input').type(discount);
-            cy.dataCy('saveManaBtn').click();
-            handleVnConfirm();
-
-            cy.get('[data-col-field="discount"]')
-                .find('.q-btn > .q-btn__content')
-                .should('have.text', `${discount}.00%`);
-        });
-
-        it('change concept', () => {
-            const concept = Math.floor(Math.random() * 100) + 1;
-            cy.waitForElement(firstRow);
-            cy.get('[data-col-field="item"]').click();
-            cy.get('.q-menu')
-                .find('[data-cy="undefined_input"]')
-                .type(concept)
-                .type('{enter}');
-            handleVnConfirm();
-
-            cy.get('[data-col-field="item"]').should('contain.text', `${concept}`);
-        });
-        it('change quantity ', () => {
-            const quantity = Math.floor(Math.random() * 100) + 1;
-            cy.waitForElement(firstRow);
-            cy.dataCy('ticketSaleQuantityInput').find('input').clear();
-            cy.dataCy('ticketSaleQuantityInput')
-                .find('input')
-                .type(quantity)
-                .trigger('tab');
-            cy.get('.q-page > :nth-child(6)').click();
-
-            handleVnConfirm();
-
-            cy.get('[data-cy="ticketSaleQuantityInput"]')
-                .find('input')
-                .should('have.value', `${quantity}`);
-        });
     });
 });
-
+function selectFirstRow() {
+    cy.waitForElement(firstRow);
+    cy.get(firstRow).find('.q-checkbox__inner').click();
+}
 function handleVnConfirm() {
-    cy.get('[data-cy="VnConfirm_confirm"]').click();
-    cy.waitForElement('.q-notification__message');
+    cy.confirmVnConfirm();
 
-    cy.get('.q-notification__message').should('be.visible');
     cy.checkNotification('Data saved');
 }
diff --git a/test/cypress/integration/ticket/ticketSaleTracking.spec.js b/test/cypress/integration/ticket/ticketSaleTracking.spec.js
new file mode 100644
index 000000000..9ee9f8824
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketSaleTracking.spec.js
@@ -0,0 +1,53 @@
+/// <reference types="cypress" />
+function uncheckedSVG(className, state) {
+    cy.get(`${className} .q-checkbox__svg`).should(
+        state === 'checked' ? 'not.have.attr' : 'have.attr',
+        'fill',
+        'none',
+    );
+}
+function checkedSVG(className, state) {
+    cy.get(`${className} .q-checkbox__svg> .q-checkbox__truthy`).should(
+        state === 'checked' ? 'not.have.attr' : 'have.attr',
+        'fill',
+        'none',
+    );
+}
+
+function clickIconAndCloseDialog(n) {
+    cy.get(
+        `:nth-child(1) > :nth-child(6) > :nth-child(${n}) > .q-btn__content > .q-icon`,
+    ).click();
+}
+
+describe('TicketSaleTracking', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/1/sale-tracking');
+    });
+
+    it('Should load layout', () => {
+        cy.get('.q-page').should('be.visible');
+        // Check checkbox states
+        uncheckedSVG('.pink', 'checked');
+        uncheckedSVG('.cyan', 'checked');
+        uncheckedSVG('.warning', 'checked');
+        uncheckedSVG('.info', 'checked');
+        checkedSVG('.yellow', 'unchecked');
+
+        cy.get('.q-page').click();
+        cy.get(
+            ':nth-child(1) > :nth-child(6) > :nth-child(2) > .q-btn__content > .q-icon',
+        ).click();
+        cy.get('body').type('{esc}');
+        cy.get(
+            ':nth-child(1) > :nth-child(6) > :nth-child(1) > .q-btn__content > .q-icon',
+        ).click();
+        cy.get(
+            '.q-dialog__inner > .q-table__container   :nth-child(1) > :nth-child(2) .link.q-btn',
+        ).click();
+
+        cy.dataCy('WorkerDescriptor').should('exist');
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketService.spec.js b/test/cypress/integration/ticket/ticketService.spec.js
new file mode 100644
index 000000000..5bf8e2aab
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketService.spec.js
@@ -0,0 +1,23 @@
+/// <reference types="cypress" />
+describe('TicketService', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/31/service');
+    });
+
+    it('Add and remove service', () => {
+        cy.get('.q-page').should('be.visible');
+        cy.addBtnClick();
+        cy.dataCy('Description_icon').click();
+        cy.dataCy('Description_input').clear().type('test');
+        cy.saveFormModel();
+        cy.selectOption('[data-cy="Description_select"]', 'test');
+
+        cy.dataCy('Quantity_input').clear().type('1');
+        cy.dataCy('Price_input').clear().type('2');
+        cy.saveCrudModel();
+        cy.checkNotification('Data saved');
+        cy.get(':nth-child(5) > .q-icon').click();
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketSms.spec.js b/test/cypress/integration/ticket/ticketSms.spec.js
new file mode 100644
index 000000000..feafb2157
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketSms.spec.js
@@ -0,0 +1,22 @@
+/// <reference types="cypress" />
+describe('TicketSms', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/32/sms');
+    });
+
+    it('Should load layout', () => {
+        cy.get('.q-page').should('be.visible');
+        cy.get('.q-infinite-scroll > :nth-child(1)').should(
+            'contain.text',
+            '0004 444444444Lorem ipsum dolor sit amet, consectetur adipiscing elit.2001-01-01 00:00:00OK',
+        );
+        cy.get(
+            ':nth-child(1) > .q-item > .q-item__section--top > .column > .q-avatar',
+        ).should('be.visible');
+        cy.get(
+            ':nth-child(1) > .q-item > .q-item__section--side.justify-center > .center > .q-chip > .q-chip__content',
+        ).should('have.class', 'q-chip__content');
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketTracking.spec.js b/test/cypress/integration/ticket/ticketTracking.spec.js
new file mode 100644
index 000000000..f351ee0a1
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketTracking.spec.js
@@ -0,0 +1,25 @@
+/// <reference types="cypress" />
+describe('Ticket tracking', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/31/tracking');
+    });
+
+    it('Add new tracking', () => {
+        cy.get('.q-page').should('be.visible');
+
+        cy.getRowCol('worker').find('span').should('have.class', 'link').click();
+        cy.dataCy('WorkerDescriptor').should('exist');
+        cy.vnTableCreateBtn();
+        cy.selectOption('.q-field--float [data-cy="State_select"]', 'OK').click();
+        cy.saveFormModel();
+        cy.get(
+            ':last-child > [data-col-field="state"] > [data-cy="vnTableCell_state"]',
+        ).should('have.text', 'OK');
+        cy.get(':last-child > [data-col-field="worker"]').should(
+            'have.text',
+            'developer ',
+        );
+    });
+});
diff --git a/test/cypress/integration/ticket/ticketVolume.spec.js b/test/cypress/integration/ticket/ticketVolume.spec.js
new file mode 100644
index 000000000..59ff6dcb2
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketVolume.spec.js
@@ -0,0 +1,27 @@
+/// <reference types="cypress" />
+function checkRightLabel(index, value, tag = 'Volume: ') {
+    cy.get(`.q-scrollarea__content > :nth-child(${index}) > :nth-child(2) > span`)
+        .should('be.visible')
+        .should('have.text', `${tag}${value}`);
+}
+describe('TicketVolume', () => {
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+        cy.visit('/#/ticket/1/volume');
+    });
+
+    it('Check right panel info', () => {
+        cy.get('.q-page').should('be.visible');
+        checkRightLabel(2, '0.028');
+        checkRightLabel(3, '0.014');
+        checkRightLabel(4, '1.526');
+    });
+    it('Descriptors', () => {
+        cy.get(':nth-child(1) > [data-col-field="itemFk"]')
+            .find('span')
+            .should('have.class', 'link')
+            .click();
+        cy.dataCy('ItemDescriptor').should('exist');
+    });
+});
diff --git a/test/cypress/integration/vnComponent/UserPanel.spec.js b/test/cypress/integration/vnComponent/UserPanel.spec.js
index 25724e873..8722fe37e 100644
--- a/test/cypress/integration/vnComponent/UserPanel.spec.js
+++ b/test/cypress/integration/vnComponent/UserPanel.spec.js
@@ -39,11 +39,11 @@ describe('UserPanel', () => {
         cy.get(userCompany).should('have.value', 'Warehouse One').click();
 
         //Actualizo la opción
-        cy.getOption(2);
+        cy.getOption(3);
 
         //Compruebo la notificación
         cy.get('.q-notification').should('be.visible');
-        cy.get(userCompany).should('have.value', 'Warehouse Two');
+        cy.get(userCompany).should('have.value', 'TestingWarehouse');
 
         //Restauro el valor
         cy.get(userCompany).click();
diff --git a/test/cypress/integration/vnComponent/VnAccountNumber.spec.js b/test/cypress/integration/vnComponent/VnAccountNumber.spec.js
deleted file mode 100644
index 053902f35..000000000
--- a/test/cypress/integration/vnComponent/VnAccountNumber.spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-describe('VnAccountNumber', () => {
-    const accountInput = 'input[data-cy="supplierFiscalDataAccount_input"]';
-    beforeEach(() => {
-        cy.login('developer');
-        cy.viewport(1920, 1080);
-        cy.visit('/#/supplier/1/fiscal-data');
-    });
-
-    describe('VnInput handleInsertMode()', () => {
-        it('should replace character at cursor position in insert mode', () => {
-            cy.get(accountInput).type('{selectall}4100000001');
-            cy.get(accountInput).type('{movetostart}');
-            cy.get(accountInput).type('999');
-            cy.get(accountInput).should('have.value', '9990000001');
-        });
-
-        it('should replace character at cursor position in insert mode', () => {
-            cy.get(accountInput).clear();
-            cy.get(accountInput).type('4100000001');
-            cy.get(accountInput).type('{movetostart}');
-            cy.get(accountInput).type('999');
-            cy.get(accountInput).should('have.value', '9990000001');
-        });
-
-        it('should respect maxlength prop', () => {
-            cy.get(accountInput).clear();
-            cy.get(accountInput).type('123456789012345');
-            cy.get(accountInput).should('have.value', '1234567890');
-        });
-    });
-
-    it('should convert short account number to standard format', () => {
-        cy.get(accountInput).clear();
-        cy.get(accountInput).type('123.');
-        cy.get(accountInput).should('have.value', '1230000000');
-    });
-});
diff --git a/test/cypress/integration/vnComponent/VnLog.spec.js b/test/cypress/integration/vnComponent/VnLog.spec.js
index 80b9d07df..57faeac85 100644
--- a/test/cypress/integration/vnComponent/VnLog.spec.js
+++ b/test/cypress/integration/vnComponent/VnLog.spec.js
@@ -1,25 +1,28 @@
 /// <reference types="cypress" />
 describe('VnLog', () => {
-    const chips = [
-        ':nth-child(1) > :nth-child(1) > .q-item__label > .q-chip > .q-chip__content',
-        ':nth-child(2) > :nth-child(1) > .q-item__label > .q-chip > .q-chip__content',
-    ];
     beforeEach(() => {
         cy.login('developer');
         cy.visit(`/#/claim/${1}/log`);
-        cy.openRightMenu();
     });
 
     it('should filter by insert actions', () => {
-        cy.checkOption(':nth-child(7) > .q-checkbox');
-        cy.get('.q-page').click();
-        cy.validateContent(chips[0], 'Document');
-        cy.validateContent(chips[1], 'Beginning');
+        cy.get('[data-cy="vnLog-checkbox"]').eq(0).click();
+        cy.get('[data-cy="vnLog-action-icon"]').each(($el) => {
+            cy.wrap($el).should('have.attr', 'title', 'Creates');
+        });
     });
 
     it('should filter by entity', () => {
-        cy.selectOption('.q-drawer--right .q-item > .q-select', 'Claim');
-        cy.get('.q-page').click();
-        cy.validateContent(chips[0], 'Claim');
+        const entity = 'Document';
+        cy.selectOption('[data-cy="vnLog-entity"]', entity);
+        cy.get('[data-cy="vnLog-model-chip"]').each(($el) => {
+            cy.wrap($el).should('have.text', entity);
+        });
+    });
+
+    it('should show claimDescriptor', () => {
+        cy.dataCy('iconLaunch-claimFk').first().click();
+        cy.dataCy('vnDescriptor_subtitle').contains('1');
+        cy.dataCy('iconLaunch-claimFk').first().click();
     });
 });
diff --git a/test/cypress/integration/vnComponent/VnShortcut.spec.js b/test/cypress/integration/vnComponent/VnShortcut.spec.js
index e08c44635..cc5cacbe4 100644
--- a/test/cypress/integration/vnComponent/VnShortcut.spec.js
+++ b/test/cypress/integration/vnComponent/VnShortcut.spec.js
@@ -1,6 +1,6 @@
 /// <reference types="cypress" />
-
-describe('VnShortcuts', () => {
+// https://redmine.verdnatura.es/issues/8848
+describe.skip('VnShortcuts', () => {
     const modules = {
         item: 'a',
         customer: 'c',
@@ -27,12 +27,15 @@ describe('VnShortcuts', () => {
                 code: `Key${shortcut.toUpperCase()}`,
             });
 
+            cy.waitSpinner();
             cy.url().should('include', module);
             if (['monitor', 'claim'].includes(module)) {
                 return;
             }
             cy.waitForElement('.q-page').should('exist');
             cy.dataCy('vnTableCreateBtn').should('exist');
+            cy.waitSpinner();
+
             cy.get('.q-page').trigger('keydown', {
                 ctrlKey: true,
                 altKey: true,
diff --git a/test/cypress/integration/vnComponent/crudModel.commands.js b/test/cypress/integration/vnComponent/crudModel.commands.js
new file mode 100644
index 000000000..9d08f064a
--- /dev/null
+++ b/test/cypress/integration/vnComponent/crudModel.commands.js
@@ -0,0 +1,3 @@
+Cypress.Commands.add('saveCrudModel', () =>
+    cy.dataCy('crudModelDefaultSaveBtn').should('exist').click(),
+);
diff --git a/test/cypress/integration/vnComponent/formModel.commands.js b/test/cypress/integration/vnComponent/formModel.commands.js
new file mode 100644
index 000000000..2814b0091
--- /dev/null
+++ b/test/cypress/integration/vnComponent/formModel.commands.js
@@ -0,0 +1,3 @@
+Cypress.Commands.add('saveFormModel', () =>
+    cy.dataCy('FormModelPopup_save').should('exist').click(),
+);
diff --git a/test/cypress/integration/vnComponent/vnConfirm.commands.js b/test/cypress/integration/vnComponent/vnConfirm.commands.js
new file mode 100644
index 000000000..9f93967d6
--- /dev/null
+++ b/test/cypress/integration/vnComponent/vnConfirm.commands.js
@@ -0,0 +1,3 @@
+Cypress.Commands.add('confirmVnConfirm', () =>
+    cy.dataCy('VnConfirm_confirm').should('exist').click(),
+);
diff --git a/test/cypress/integration/vnComponent/vnSelect.commands.js b/test/cypress/integration/vnComponent/vnSelect.commands.js
new file mode 100644
index 000000000..017b6e7ea
--- /dev/null
+++ b/test/cypress/integration/vnComponent/vnSelect.commands.js
@@ -0,0 +1,3 @@
+Cypress.Commands.add('clickOption', (index = 1) =>
+    cy.get(`.q-menu :nth-child(${index}) >.q-item__section`).click(),
+);
diff --git a/test/cypress/integration/vnComponent/vnTable.commands.js b/test/cypress/integration/vnComponent/vnTable.commands.js
new file mode 100644
index 000000000..6c7e71e13
--- /dev/null
+++ b/test/cypress/integration/vnComponent/vnTable.commands.js
@@ -0,0 +1,16 @@
+Cypress.Commands.add('getRow', (index = 1) =>
+    cy.get(`.vnTable .q-virtual-scroll__content tr:nth-child(${index})`),
+);
+Cypress.Commands.add('getRowCol', (field, index = 1) =>
+    cy.get(
+        `.vnTable .q-virtual-scroll__content > :nth-child(${index}) > [data-col-field="${field}"]`,
+    ),
+);
+
+Cypress.Commands.add('vnTableCreateBtn', () =>
+    cy.dataCy('vnTableCreateBtn').should('exist').click(),
+);
+
+Cypress.Commands.add('waitTableScrollLoad', () =>
+    cy.waitForElement('[data-q-vs-anchor]'),
+);
diff --git a/test/cypress/integration/wagon/wagonCreate.spec.js b/test/cypress/integration/wagon/wagonCreate.spec.js
index 6d185ea69..88855fdf9 100644
--- a/test/cypress/integration/wagon/wagonCreate.spec.js
+++ b/test/cypress/integration/wagon/wagonCreate.spec.js
@@ -1,4 +1,4 @@
-describe.skip('WagonCreate', () => {
+describe('WagonCreate', () => {
     beforeEach(() => {
         cy.viewport(1280, 720);
         cy.login('developer');
@@ -17,7 +17,7 @@ describe.skip('WagonCreate', () => {
             '.grid-create > [label="Volume"] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="Volume_input"]',
         ).type('100');
         cy.selectOption('[data-cy="Type_select"]', '1');
-
+        cy.dataCy('FormModelPopup_save').click();
         cy.get('[title="Remove"] > .q-btn__content > .q-icon').first().click();
     });
 });
diff --git a/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js b/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js
index 49d7d9f01..915927a6d 100644
--- a/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js
+++ b/test/cypress/integration/wagon/wagonType/wagonTypeCreate.spec.js
@@ -2,7 +2,7 @@ describe('WagonTypeCreate', () => {
     beforeEach(() => {
         cy.viewport(1920, 1080);
         cy.login('developer');
-        cy.visit('/#/wagon/type/create');
+        cy.visit('/#/wagon/type/list');
         cy.waitForElement('.q-page', 6000);
     });
 
diff --git a/test/cypress/integration/worker/workerBasicData.spec.js b/test/cypress/integration/worker/workerBasicData.spec.js
new file mode 100644
index 000000000..cf452a044
--- /dev/null
+++ b/test/cypress/integration/worker/workerBasicData.spec.js
@@ -0,0 +1,15 @@
+describe('WorkerBasicData', () => {
+    beforeEach(() => {
+        cy.viewport(1280, 720);
+        cy.login('developer');
+        cy.visit('/#/worker/1107/basic-data');
+    });
+
+    it('should modify worker summary', () => {
+        cy.dataCy('MaritalStatus').type('Married');
+        cy.dataCy('fi').type('42572374H');
+        cy.dataCy('country').type('Alemania');
+        cy.saveCard();
+        cy.checkNotification('Data saved');
+    });
+});
diff --git a/test/cypress/integration/worker/workerBusiness.spec.js b/test/cypress/integration/worker/workerBusiness.spec.js
new file mode 100644
index 000000000..46da28cd6
--- /dev/null
+++ b/test/cypress/integration/worker/workerBusiness.spec.js
@@ -0,0 +1,34 @@
+describe.skip('WorkerBusiness', () => {
+    const saveBtn = '.q-mt-lg > .q-btn--standard';
+    const contributionCode = `Representantes de comercio`;
+    const contractType = `INDEFINIDO A TIEMPO COMPLETO`;
+
+    const Business = {
+        'Start Date': { val: '26-12-2002', type: 'date' },
+        Company: { val: `VNL`, type: 'select' },
+        Department: { val: `RECICLAJE`, type: 'select' },
+        'Professional Category': { val: `employee`, type: 'select' },
+        'Work Calendar': { val: `General schedule`, type: 'select' },
+        'Work Center': { val: `Silla`, type: 'select' },
+        'Contract Category': { val: `INFORMATICA`, type: 'select' },
+        'Contribution Code': { val: contributionCode, type: 'select' },
+        Rate: { val: `5` },
+        'Contract Type': { val: contractType, type: 'select' },
+        'Transport Workers Salary': { val: `1000` },
+    };
+
+    beforeEach(() => {
+        cy.viewport(1280, 720);
+        cy.login('hr');
+        cy.visit('/#/worker/1107/business');
+        cy.addCard();
+    });
+
+    it('should create a business', () => {
+        cy.fillInForm({
+            ...Business,
+        });
+        cy.get(saveBtn).click();
+        cy.checkNotification('Data created');
+    });
+});
diff --git a/test/cypress/integration/worker/workerList.spec.js b/test/cypress/integration/worker/workerList.spec.js
index 0a45441c1..d964c3dc8 100644
--- a/test/cypress/integration/worker/workerList.spec.js
+++ b/test/cypress/integration/worker/workerList.spec.js
@@ -1,4 +1,5 @@
-describe('WorkerList', () => {
+// https://redmine.verdnatura.es/issues/8848
+describe.skip('WorkerList', () => {
     const inputName = '.q-drawer .q-form input[aria-label="First Name"]';
     const searchBtn = '.q-drawer button:nth-child(3)';
     const descriptorTitle = '.descriptor .title span';
@@ -13,7 +14,7 @@ describe('WorkerList', () => {
         cy.intercept('GET', /\/api\/Workers\/summary+/).as('worker');
         cy.get(searchBtn).click();
         cy.wait('@worker').then(() =>
-            cy.get(descriptorTitle).should('include.text', 'Jessica')
+            cy.get(descriptorTitle).should('include.text', 'Jessica'),
         );
     });
 });
diff --git a/test/cypress/integration/worker/workerMutual.spec.js b/test/cypress/integration/worker/workerMutual.spec.js
new file mode 100644
index 000000000..a6d2c5f4f
--- /dev/null
+++ b/test/cypress/integration/worker/workerMutual.spec.js
@@ -0,0 +1,23 @@
+/// <reference types="cypress" />
+describe('WorkerMutual', () => {
+    const userId = 1106;
+    const saveBtn = '.q-mt-lg > .q-btn--standard';
+    const medicalReview = {
+        Date: { val: '01-01-2001', type: 'date' },
+        'Formation Center': { val: '1', type: 'select' },
+        Invoice: { val: '24532' },
+        Amount: { val: '540' },
+    };
+    beforeEach(() => {
+        cy.viewport(1280, 720);
+        cy.login('developer');
+        cy.visit(`/#/worker/${userId}/medical`);
+        cy.addCard();
+    });
+
+    it('should create a medical Review', () => {
+        cy.fillInForm(medicalReview);
+        cy.get(saveBtn).click();
+        cy.checkNotification('Data created');
+    });
+});
diff --git a/test/cypress/integration/client/clientBalance.spec.js b/test/cypress/integration/worker/workerNotes.spec.js
similarity index 53%
rename from test/cypress/integration/client/clientBalance.spec.js
rename to test/cypress/integration/worker/workerNotes.spec.js
index abfa74cec..661314ac9 100644
--- a/test/cypress/integration/client/clientBalance.spec.js
+++ b/test/cypress/integration/worker/workerNotes.spec.js
@@ -1,11 +1,13 @@
 /// <reference types="cypress" />
-describe('Client balance', () => {
+describe('WorkerNotes', () => {
+    const userId = 1106;
     beforeEach(() => {
         cy.viewport(1280, 720);
         cy.login('developer');
-        cy.visit('#/customer/1101/balance');
+        cy.visit(`/#/worker/${userId}/notes`);
     });
+
     it('Should load layout', () => {
-        cy.get('.q-page').should('be.visible');
+        cy.get('.q-card').should('be.visible');
     });
 });
diff --git a/test/cypress/integration/worker/workerOperator.spec.js b/test/cypress/integration/worker/workerOperator.spec.js
new file mode 100644
index 000000000..95839aeba
--- /dev/null
+++ b/test/cypress/integration/worker/workerOperator.spec.js
@@ -0,0 +1,19 @@
+/// <reference types="cypress" />
+describe('WorkerOperator', () => {
+    const userId = 1106;
+    beforeEach(() => {
+        cy.viewport(1280, 720);
+        cy.login('hr');
+        cy.visit(`/#/worker/${userId}/operator`);
+    });
+
+    it('should fill the operator form', () => {
+        cy.dataCy('numberOfWagons').type('4');
+        cy.dataCy('linesLimit').type('6');
+        cy.dataCy('volumeLimit').type('3');
+        cy.dataCy('sizeLimit').type('3');
+        cy.saveCard();
+
+        cy.checkNotification('Data saved');
+    });
+});
diff --git a/test/cypress/integration/worker/workerPda.spec.js b/test/cypress/integration/worker/workerPda.spec.js
index 31ec19eda..2623e81cf 100644
--- a/test/cypress/integration/worker/workerPda.spec.js
+++ b/test/cypress/integration/worker/workerPda.spec.js
@@ -1,23 +1,80 @@
 describe('WorkerPda', () => {
-    const select = '[data-cy="pda-dialog-select"]';
+    const deviceId = 4;
     beforeEach(() => {
-        cy.viewport(1920, 1080);
         cy.login('developer');
         cy.visit(`/#/worker/1110/pda`);
     });
 
-    it('assign pda', () => {
-        cy.addBtnClick();
-        cy.get(select).click();
-        cy.get(select).type('{downArrow}{enter}');
-        cy.get('.q-notification__message').should('have.text', 'Data created');
+    it('assign and delete pda', () => {
+        creatNewPDA();
+        cy.checkNotification('Data created');
+        cy.visit(`/#/worker/1110/pda`);
+        removeNewPDA();
+        cy.checkNotification('PDA deallocated');
     });
 
-    it('delete pda', () => {
-        cy.get('.btn-delete').click();
-        cy.get(
-            '.q-card__actions > .q-btn--unelevated > .q-btn__content > .block'
-        ).click();
-        cy.get('.q-notification__message').should('have.text', 'PDA deallocated');
+    it('send and download pdf to docuware', () => {
+        //Send
+        cy.intercept('POST', '/api/Docuwares/upload-pda-pdf', (req) => {
+            req.reply({
+                statusCode: 200,
+                body: {},
+            });
+        });
+
+        creatNewPDA();
+
+        cy.dataCy('workerPda-send').click();
+        cy.clickConfirm();
+        cy.checkNotification('PDF sended to signed');
+
+        //Download
+        cy.intercept('POST', /\/api\/Docuwares\/Jones%20Jessica\/checkFile/, (req) => {
+            req.reply({
+                statusCode: 200,
+                body: {
+                    id: deviceId,
+                    state: 'Firmado',
+                },
+            });
+        });
+        cy.get('#st-actions').contains('refresh').click();
+        cy.intercept('GET', '/api/Docuwares/download-pda-pdf**', (req) => {
+            req.reply({
+                statusCode: 200,
+                body: {},
+            });
+        });
+
+        cy.dataCy('workerPda-download').click();
+        removeNewPDA();
     });
+
+    it('send 2 pdfs to docuware', () => {
+        cy.intercept('POST', '/api/Docuwares/upload-pda-pdf', (req) => {
+            req.reply({
+                statusCode: 200,
+                body: {},
+            });
+        });
+
+        creatNewPDA();
+        creatNewPDA(2);
+        cy.selectRows([1, 2]);
+        cy.get('#st-actions').contains('Send').click();
+        cy.checkNotification('PDF sended to signed');
+
+        removeNewPDA();
+    });
+
+    function creatNewPDA(id = deviceId) {
+        cy.addBtnClick();
+        cy.selectOption('[data-cy="pda-dialog-select"]', id);
+        cy.saveCard();
+    }
+
+    function removeNewPDA() {
+        cy.dataCy('workerPda-remove').first().click();
+        cy.clickConfirm();
+    }
 });
diff --git a/test/cypress/integration/worker/workerPit.spec.js b/test/cypress/integration/worker/workerPit.spec.js
index 19cbebc20..04f232648 100644
--- a/test/cypress/integration/worker/workerPit.spec.js
+++ b/test/cypress/integration/worker/workerPit.spec.js
@@ -1,19 +1,5 @@
 describe('WorkerPit', () => {
-    const familySituationInput = '[data-cy="Family Situation_input"]';
-    const familySituation = '1';
-    const childPensionInput = '[data-cy="Child Pension_input"]';
-    const childPension = '120';
-    const spouseNifInput = '[data-cy="Spouse Pension_input"]';
-    const spouseNif = '65117125P';
-    const spousePensionInput = '[data-cy="Spouse Pension_input"]';
-    const spousePension = '120';
     const addRelative = '[data-cy="addRelative"]';
-    const isDescendantSelect = '[data-cy="Descendant/Ascendant"]';
-    const Descendant = 'Descendiente';
-    const birthedInput = '[data-cy="Birth Year_input"]';
-    const birthed = '2002';
-    const adoptionYearInput = '[data-cy="Adoption Year_input"]';
-    const adoptionYear = '2004';
     const saveRelative = '[data-cy="workerPitRelativeSaveBtn"]';
     const savePIT = '#st-actions > .q-btn-group > .q-btn--standard';
 
@@ -24,15 +10,15 @@ describe('WorkerPit', () => {
     });
 
     it('complete PIT', () => {
-        cy.get(familySituationInput).type(familySituation);
-        cy.get(childPensionInput).type(childPension);
-        cy.get(spouseNifInput).type(spouseNif);
-        cy.get(spousePensionInput).type(spousePension);
+        cy.dataCy('familySituation').type('1');
+        cy.dataCy('childPension').type('120');
+        cy.dataCy('spouseNif').type('65117125P');
+        cy.dataCy('spousePension').type('120');
         cy.get(savePIT).click();
         cy.get(addRelative).click();
-        cy.get(isDescendantSelect).type(Descendant);
-        cy.get(birthedInput).type(birthed);
-        cy.get(adoptionYearInput).type(adoptionYear);
+        cy.dataCy('Descendant/Ascendant').type('Descendiente');
+        cy.dataCy('birthed').type('2002');
+        cy.dataCy('adoptionYear').type('2004');
         cy.get(saveRelative).click();
     });
 });
diff --git a/test/cypress/integration/worker/workerSummary.spec.js b/test/cypress/integration/worker/workerSummary.spec.js
index 3d70fdf96..6071c4cdf 100644
--- a/test/cypress/integration/worker/workerSummary.spec.js
+++ b/test/cypress/integration/worker/workerSummary.spec.js
@@ -1,16 +1,26 @@
 describe('WorkerSummary', () => {
+    const department = ':nth-child(1) > [data-cy="vnLvDepartment"] > .value';
+    const role = '[data-cy="vnLvRole"] > .value';
     beforeEach(() => {
         cy.viewport(1280, 720);
         cy.login('developer');
         cy.visit('/#/worker/19/summary');
     });
 
-    it('should load worker summary', () => {
+    it('should load worker summary and show the department', () => {
         cy.waitForElement('.summaryHeader');
         cy.get('.summaryHeader > div').should('have.text', '19 - salesboss salesboss');
-        cy.get(':nth-child(1) > :nth-child(2) > .value > span').should(
-            'have.text',
-            'salesBossNick'
-        );
+        cy.get(department).should('have.text', 'VENTAS');
+    });
+
+    it('should try descriptors', () => {
+        cy.waitForElement('.summaryHeader');
+        cy.get(department).click();
+        cy.get('.descriptor').should('be.visible');
+        cy.get('.q-item > .q-item__label').should('include.text', '43');
+        cy.get('.summaryBody').click();
+        cy.get(role).click();
+        cy.get('.descriptor').should('be.visible');
+        cy.get('.q-item > .q-item__label').should('include.text', '19');
     });
 });
diff --git a/test/cypress/integration/zone/zoneCalendar.spec.js b/test/cypress/integration/zone/zoneCalendar.spec.js
index d71c29142..68b85d1d2 100644
--- a/test/cypress/integration/zone/zoneCalendar.spec.js
+++ b/test/cypress/integration/zone/zoneCalendar.spec.js
@@ -1,22 +1,19 @@
 describe('ZoneCalendar', () => {
     const addEventBtn = '.q-page-sticky > div > .q-btn';
     const submitBtn = '.q-mt-lg > .q-btn--standard';
-    const deleteBtn = '.q-item__section--side > .q-btn';
-    const from = '.q-field__control-container > [data-cy="ZoneEventsFromDate"]';
-    const to = '.q-field__control-container > [data-cy="ZoneEventsToDate"]';
+    const deleteBtn = 'ZoneEventsPanelDeleteBtn';
 
     beforeEach(() => {
         cy.login('developer');
-        cy.viewport(1920, 1080);
-        cy.visit(`/#/zone/11/events`);
+        cy.visit(`/#/zone/13/events`);
     });
 
     it('should include a one day event, then delete it', () => {
         cy.get(addEventBtn).click();
         cy.dataCy('ZoneEventInclusionDayRadio').click();
-        cy.get('.q-card > :nth-child(5)').type('02/04/2001');
+        cy.get('.q-card > :nth-child(5)').type('01/01/2001');
         cy.get(submitBtn).click();
-        cy.get(deleteBtn).click();
+        cy.dataCy(deleteBtn).click();
         cy.dataCy('VnConfirm_confirm').click();
     });
 
@@ -25,7 +22,7 @@ describe('ZoneCalendar', () => {
         cy.get('.flex > .q-gutter-x-sm > :nth-child(1)').click();
         cy.get('.flex > .q-gutter-x-sm > :nth-child(2)').click();
         cy.get(submitBtn).click();
-        cy.get(deleteBtn).click();
+        cy.dataCy(deleteBtn).click();
         cy.dataCy('VnConfirm_confirm').click();
     });
 
@@ -36,7 +33,7 @@ describe('ZoneCalendar', () => {
         cy.dataCy('From_inputDate').type('01/01/2001');
         cy.dataCy('To_inputDate').type('31/01/2001');
         cy.get(submitBtn).click();
-        cy.get(deleteBtn).click();
+        cy.dataCy(deleteBtn).click();
         cy.dataCy('VnConfirm_confirm').click();
     });
 
@@ -47,7 +44,7 @@ describe('ZoneCalendar', () => {
         cy.get(
             '.q-current-day > .q-calendar-month__day--content > [data-cy="ZoneCalendarDay"]',
         ).click();
-        cy.get('.q-mt-lg > :nth-child(2)').click();
+        cy.dataCy('ZoneEventExclusionDeleteBtn').click();
         cy.dataCy('VnConfirm_confirm').click();
     });
 });
diff --git a/test/cypress/integration/zone/zoneCreate.spec.js b/test/cypress/integration/zone/zoneCreate.spec.js
index 9ef1945bf..fadf5b07f 100644
--- a/test/cypress/integration/zone/zoneCreate.spec.js
+++ b/test/cypress/integration/zone/zoneCreate.spec.js
@@ -1,4 +1,4 @@
-describe.skip('ZoneCreate', () => {
+describe('ZoneCreate', () => {
     const data = {
         Name: { val: 'Zone pickup D' },
         Price: { val: '3' },
diff --git a/test/cypress/integration/zone/zoneDeliveryDays.spec.js b/test/cypress/integration/zone/zoneDeliveryDays.spec.js
index 291c20ce3..a89def12d 100644
--- a/test/cypress/integration/zone/zoneDeliveryDays.spec.js
+++ b/test/cypress/integration/zone/zoneDeliveryDays.spec.js
@@ -37,7 +37,6 @@ describe('ZoneDeliveryDays', () => {
                 cy.get('@focusedElement').blur();
             }
         });
-        cy.get('.q-menu').should('not.exist');
 
         cy.dataCy('ZoneDeliveryDaysAgencySelect').type(agency);
         cy.get('.q-menu .q-item').contains(agency).click();
@@ -49,7 +48,6 @@ describe('ZoneDeliveryDays', () => {
                 cy.get('@focusedElement').blur();
             }
         });
-        cy.get('.q-menu').should('not.exist');
 
         cy.get(submitForm).click();
         cy.wait('@events').then((interception) => {
diff --git a/test/cypress/integration/zone/zoneList.spec.js b/test/cypress/integration/zone/zoneList.spec.js
index b1b0db3fc..c84b1b017 100644
--- a/test/cypress/integration/zone/zoneList.spec.js
+++ b/test/cypress/integration/zone/zoneList.spec.js
@@ -1,26 +1,18 @@
 describe('ZoneList', () => {
     const agency = 'inhouse pickup';
+    const firstSummaryIcon =
+        ':nth-child(1) > .q-table--col-auto-width > [data-cy="tableAction-0"]';
     beforeEach(() => {
         cy.viewport(1280, 720);
         cy.login('developer');
         cy.visit('/#/zone/list');
-    });
-
-    it('should filter by agency', () => {
-        cy.dataCy('zoneFilterPanelAgencySelect').type(agency);
-        cy.get('.q-menu .q-item').contains(agency).click();
-        cy.get(':nth-child(1) > [data-col-field="agencyModeFk"]').should(
-            'include.text',
-            agency,
-        );
+        cy.typeSearchbar('{enter}');
     });
 
     it('should open the zone summary', () => {
-        cy.dataCy('zoneFilterPanelAgencySelect').type(agency);
-        cy.get('.q-menu .q-item').contains(agency).click();
-        cy.dataCy('tableAction-0').eq(1).click();
+        cy.get(firstSummaryIcon).click();
         cy.get('.header > .q-icon').click();
-        cy.url().should('include', 'zone/2/summary');
+        cy.url().should('include', 'zone/1/summary');
     });
 
     it('should clone the zone', () => {
@@ -29,7 +21,5 @@ describe('ZoneList', () => {
         cy.dataCy('VnConfirm_confirm').click();
         cy.url().should('not.include', 'zone/2/');
         cy.url().should('match', /zone\/\d+\/basic-data/);
-        cy.get('.list-box > :nth-child(1)').should('include.text', agency);
-        cy.get('.title > span').should('include.text', 'Zone pickup B');
     });
 });
diff --git a/test/cypress/integration/zone/zoneLocations.spec.js b/test/cypress/integration/zone/zoneLocations.spec.js
index 04b7f1991..dabd3eb2b 100644
--- a/test/cypress/integration/zone/zoneLocations.spec.js
+++ b/test/cypress/integration/zone/zoneLocations.spec.js
@@ -1,23 +1,59 @@
 describe('ZoneLocations', () => {
-    const data = {
-        Warehouse: { val: 'Warehouse One', type: 'select' },
-    };
-
-    const postalCode = '[style=""] > :nth-child(1) > :nth-child(1) > :nth-child(2) > :nth-child(1) > :nth-child(1) > :nth-child(2) > :nth-child(1) > .q-tree__node--parent > .q-tree__node-collapsible > .q-tree__children'
-
+    const cp = 46680;
+    const searchIcon = '.router-link-active > .q-icon';
     beforeEach(() => {
-        cy.viewport(1280, 720);
         cy.login('developer');
         cy.visit(`/#/zone/2/location`);
     });
 
-    it('should show all locations on entry', () => {
-        cy.get('.q-tree > :nth-child(1) > :nth-child(2) > :nth-child(1)').children().should('have.length', 9);
+    it('should be able to search by postal code', () => {
+        cy.get('.q-tree > :nth-child(1) > :nth-child(2) > :nth-child(1)')
+            .should('exist')
+            .should('be.visible');
+
+        cy.intercept('GET', '**/api/Zones/2/getLeaves*', (req) => {
+            req.headers['cache-control'] = 'no-cache';
+            req.headers['pragma'] = 'no-cache';
+            req.headers['expires'] = '0';
+
+            req.on('response', (res) => {
+                delete res.headers['if-none-match'];
+                delete res.headers['if-modified-since'];
+            });
+        }).as('location');
+        cy.get('#searchbarForm').type(cp);
+        cy.get(searchIcon).click();
+        cy.wait('@location').then((interception) => {
+            const data = interception.response.body;
+            expect(data).to.include(cp);
+        });
     });
 
-    it('should be able to search by postal code', () => {
-        cy.get('#searchbarForm').type('46680');
-        cy.get('.router-link-active > .q-icon').click();
-        cy.get(postalCode).should('include.text', '46680')
+    it('should check, uncheck, and set a location to mixed state', () => {
+        cy.get('#searchbarForm').type(cp);
+        cy.get(searchIcon).click();
+
+        cy.get('.q-tree > :nth-child(1) > :nth-child(2) > :nth-child(1)')
+            .as('tree')
+            .within(() => {
+                cy.get('[data-cy="ZoneLocationTreeCheckbox"] > .q-checkbox__inner')
+                    .last()
+                    .as('lastCheckbox');
+
+                const verifyCheckboxState = (state) => {
+                    cy.get('@lastCheckbox')
+                        .parents('.q-checkbox')
+                        .should('have.attr', 'aria-checked', state);
+                };
+
+                cy.get('@lastCheckbox').click();
+                verifyCheckboxState('true');
+
+                cy.get('@lastCheckbox').click();
+                verifyCheckboxState('false');
+
+                cy.get('@lastCheckbox').click();
+                verifyCheckboxState('mixed');
+            });
     });
 });
diff --git a/test/cypress/integration/zone/zoneWarehouse.spec.js b/test/cypress/integration/zone/zoneWarehouse.spec.js
index b2c1c1ed2..d7a9854bb 100644
--- a/test/cypress/integration/zone/zoneWarehouse.spec.js
+++ b/test/cypress/integration/zone/zoneWarehouse.spec.js
@@ -1,4 +1,4 @@
-describe.skip('ZoneWarehouse', () => {
+describe('ZoneWarehouse', () => {
     const data = {
         Warehouse: { val: 'Warehouse Two', type: 'select' },
     };
@@ -18,7 +18,7 @@ describe.skip('ZoneWarehouse', () => {
         cy.checkNotification(dataError);
     });
 
-    it('should create & remove a warehouse', () => {
+    it.skip('should create & remove a warehouse', () => {
         cy.addBtnClick();
         cy.fillInForm(data);
         cy.get(saveBtn).click();
diff --git a/test/cypress/run.sh b/test/cypress/run.sh
deleted file mode 100755
index 1f506aa57..000000000
--- a/test/cypress/run.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-
-cleanup() {
-    if [[ -z "$ended" ]]; then
-        ended=true
-        docker-compose -p e2e --project-directory . -f test/cypress/docker-compose.yml down -v
-    fi
-}
-
-trap cleanup SIGINT
-
-#CLEAN
-rm -rf test/cypress/screenshots
-rm -f test/cypress/results/*
-rm -f test/cypress/reports/*
-rm -f junit/e2e-*.xml
-
-#RUN
-export CI=true
-export TZ=Europe/Madrid
-
-docker-compose -p e2e --project-directory . -f test/cypress/docker-compose.yml up -d
-
-docker run -it --rm \
-    -v "$(pwd)":/app \
-    --network e2e_default \
-    -e CI \
-    -e TZ \
-    lilium-dev \
-    bash -c 'sh test/cypress/cypressParallel.sh 2'
-
-cleanup
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 8437112e0..41f91e855 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -27,8 +27,14 @@
 // DO NOT REMOVE
 // Imports Quasar Cypress AE predefined commands
 // import { registerCommands } from '@quasar/quasar-app-extension-testing-e2e-cypress';
-
+import moment from 'moment';
 import waitUntil from './waitUntil';
+// Importar dinámicamente todos los archivos con el sufijo .commands.js dentro de la carpeta src/test/cypress/integration
+const requireCommands = require.context('../integration', true, /\.commands\.js$/);
+// Iterar sobre cada archivo y requerirlo
+requireCommands.keys().forEach(requireCommands);
+
+// Common comma
 Cypress.Commands.add('waitUntil', { prevSubject: 'optional' }, waitUntil);
 
 Cypress.Commands.add('resetDB', () => {
@@ -62,12 +68,7 @@ Cypress.Commands.overwrite('visit', (originalFn, url, options, waitRequest = tru
     originalFn(url, options);
     cy.waitUntil(() => cy.document().then((doc) => doc.readyState === 'complete'));
     cy.waitUntil(() => cy.get('main').should('exist'));
-    if (waitRequest)
-        cy.get('body').then(($body) => {
-            if ($body.find('[data-cy="loading-spinner"]').length) {
-                cy.get('[data-cy="loading-spinner"]').should('not.be.visible');
-            }
-        });
+    if (waitRequest) cy.waitSpinner();
 });
 
 Cypress.Commands.add('waitForElement', (element) => {
@@ -99,6 +100,14 @@ Cypress.Commands.add('getValue', (selector) => {
     });
 });
 
+Cypress.Commands.add('waitSpinner', () => {
+    cy.get('body').then(($body) => {
+        if ($body.find('[data-cy="loading-spinner"]').length) {
+            cy.get('[data-cy="loading-spinner"]').should('not.be.visible');
+        }
+    });
+});
+
 // Fill Inputs
 Cypress.Commands.add('selectOption', (selector, option, timeout = 2500) => {
     cy.waitForElement(selector, timeout);
@@ -116,11 +125,13 @@ Cypress.Commands.add('selectOption', (selector, option, timeout = 2500) => {
 
 function selectItem(selector, option, ariaControl, hasWrite = true) {
     if (!hasWrite) cy.wait(100);
+    cy.waitSpinner();
 
     getItems(ariaControl).then((items) => {
-        const matchingItem = items
-            .toArray()
-            .find((item) => item.innerText.includes(option));
+        const matchingItem = items.toArray().find((item) => {
+            const val = typeof option == 'string' ? option.toLowerCase() : option;
+            return item.innerText.toLowerCase().includes(val);
+        });
         if (matchingItem) return cy.wrap(matchingItem).click();
 
         if (hasWrite) cy.get(selector).clear().type(option);
@@ -135,6 +146,7 @@ function getItems(ariaControl, startTime = Cypress._.now(), timeout = 2500) {
         .should('exist')
         .find('.q-item')
         .should('exist')
+        .should('be.visible')
         .then(($items) => {
             if (!$items?.length || $items.first().text().trim() === '') {
                 if (Cypress._.now() - startTime > timeout) {
@@ -155,14 +167,20 @@ Cypress.Commands.add('countSelectOptions', (selector, option) => {
     cy.get('.q-menu .q-item').should('have.length', option);
 });
 
-Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
+Cypress.Commands.add('fillInForm', (obj, opts = {}) => {
+    cy.waitSpinner();
+    const { form = '.q-form > .q-card', attr = 'aria-label' } = opts;
     cy.waitForElement(form);
     cy.get(`${form} input`).each(([el]) => {
         cy.wrap(el)
-            .invoke('attr', 'aria-label')
-            .then((ariaLabel) => {
-                const field = obj[ariaLabel];
+            .invoke('attr', attr)
+            .then((key) => {
+                const field = obj[key];
                 if (!field) return;
+                if (typeof field == 'string')
+                    return cy
+                        .wrap(el)
+                        .type(`{selectall}{backspace}${field}`, { delay: 0 });
 
                 const { type, val } = field;
                 switch (type) {
@@ -170,7 +188,9 @@ Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
                         cy.selectOption(el, val);
                         break;
                     case 'date':
-                        cy.get(el).type(val.split('-').join(''));
+                        cy.get(el).type(
+                            `{selectall}{backspace}${val.split('-').join('')}`,
+                        );
                         break;
                     case 'time':
                         cy.get(el).click();
@@ -179,13 +199,47 @@ Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
                         cy.get('.q-time .q-time__link').contains(val.x).click();
                         break;
                     default:
-                        cy.wrap(el).type(val);
+                        cy.wrap(el).type(`{selectall}${val}`, { delay: 0 });
                         break;
                 }
             });
     });
 });
 
+Cypress.Commands.add('validateForm', (obj, opts = {}) => {
+    const { form = '.q-form > .q-card', attr = 'data-cy' } = opts;
+    cy.waitForElement(form);
+    cy.get(`${form} input`).each(([el]) => {
+        cy.wrap(el)
+            .invoke('attr', attr)
+            .then((key) => {
+                const field = obj[key];
+                if (!field) return;
+
+                const { type, val } = field;
+                cy.get(el)
+                    .invoke('val')
+                    .then((elVal) => {
+                        if (typeof field == 'string')
+                            expect(elVal.toLowerCase()).to.equal(field.toLowerCase());
+                        else
+                            switch (type) {
+                                case 'date':
+                                    const elDate = moment(elVal, 'DD-MM-YYYY');
+                                    const mockDate = moment(val, 'DD-MM-YYYY');
+                                    expect(elDate.isSame(mockDate, 'day')).to.be.true;
+                                    break;
+                                default:
+                                    expect(elVal.toLowerCase()).to.equal(
+                                        val.toLowerCase(),
+                                    );
+                                    break;
+                            }
+                    });
+            });
+    });
+});
+
 Cypress.Commands.add('checkOption', (selector) => {
     cy.get(selector).find('.q-checkbox__inner').click();
 });
@@ -202,14 +256,17 @@ Cypress.Commands.add('saveCard', () => {
 Cypress.Commands.add('resetCard', () => {
     cy.get('[title="Reset"]').click();
 });
+
 Cypress.Commands.add('removeCard', () => {
     cy.get('[title="Remove"]').click();
 });
+
 Cypress.Commands.add('addCard', () => {
     cy.waitForElement('tbody');
     cy.waitForElement('.q-page-sticky > div > .q-btn');
     cy.get('.q-page-sticky > div > .q-btn').click();
 });
+
 Cypress.Commands.add('clickConfirm', () => {
     cy.waitForElement('.q-dialog__inner > .q-card');
     cy.get('.q-card__actions > .q-btn--unelevated > .q-btn__content > .block').click();
@@ -290,6 +347,7 @@ Cypress.Commands.add('removeRow', (rowIndex) => {
             });
         });
 });
+
 Cypress.Commands.add('openListSummary', (row) => {
     cy.get('.card-list-body .actions .q-btn:nth-child(2)').eq(row).click();
 });
@@ -317,6 +375,15 @@ Cypress.Commands.add('validateContent', (selector, expectedValue) => {
     cy.get(selector).should('have.text', expectedValue);
 });
 
+Cypress.Commands.add('containContent', (selector, expectedValue) => {
+    cy.get(selector)
+        .should('be.visible')
+        .invoke('text')
+        .then((text) => {
+            expect(text).to.include(expectedValue);
+        });
+});
+
 Cypress.Commands.add('openActionDescriptor', (opt) => {
     cy.openActionsDescriptor();
     const listItem = '[role="menu"] .q-list .q-item';
@@ -324,13 +391,7 @@ Cypress.Commands.add('openActionDescriptor', (opt) => {
 });
 
 Cypress.Commands.add('openActionsDescriptor', () => {
-    cy.get('[data-cy="descriptor-more-opts"]').click();
-});
-
-Cypress.Commands.add('clickButtonDescriptor', (id) => {
-    cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
-        .invoke('removeAttr', 'target')
-        .click();
+    cy.get('[data-cy="vnDescriptor"] [data-cy="descriptor-more-opts"]').click();
 });
 
 Cypress.Commands.add('openUserPanel', () => {
@@ -390,6 +451,7 @@ Cypress.Commands.add('clickButtonWith', (type, value) => {
             break;
     }
 });
+
 Cypress.Commands.add('clickButtonWithIcon', (iconClass) => {
     cy.waitForElement('[data-cy="descriptor_actions"]');
     cy.get('[data-cy="loading-spinner"]', { timeout: 10000 }).should('not.be.visible');
@@ -418,3 +480,142 @@ Cypress.Commands.add('searchBtnFilterPanel', () => {
 Cypress.Commands.add('waitRequest', (alias, cb) => {
     cy.wait(alias).then(cb);
 });
+
+Cypress.Commands.add('validateDescriptor', (toCheck = {}) => {
+    const { title, description, subtitle, listbox = {}, popup = false } = toCheck;
+
+    const popupSelector = popup ? '[role="menu"] ' : '';
+
+    if (title) cy.get(`${popupSelector}[data-cy="vnDescriptor_title"]`).contains(title);
+    if (description)
+        cy.get(`${popupSelector}[data-cy="vnDescriptor_description"]`).contains(
+            description,
+        );
+    if (subtitle)
+        cy.get(`${popupSelector}[data-cy="vnDescriptor_subtitle"]`).contains(subtitle);
+
+    for (const index in listbox)
+        cy.get(`${popupSelector}[data-cy="vnDescriptor_listbox"] > *`)
+            .eq(index)
+            .should('contain.text', listbox[index]);
+});
+
+Cypress.Commands.add('validateVnTableRows', (opts = {}) => {
+    let { cols = [], rows = [] } = opts;
+    if (!Array.isArray(cols)) cols = [cols];
+    const rowSelector = rows.length
+        ? rows.map((row) => `> :nth-child(${row})`).join(', ')
+        : '> *';
+    cy.get(`[data-cy="vnTable"] .q-virtual-scroll__content`).within(() => {
+        cy.get(`${rowSelector}`).each(($el) => {
+            for (const { name, type = 'string', val, operation = 'equal' } of cols) {
+                cy.wrap($el)
+                    .find(`[data-cy="vnTableCell_${name}"]`)
+                    .invoke('text')
+                    .then((text) => {
+                        if (type === 'string')
+                            expect(text.trim().toLowerCase()).to[operation](
+                                val.toLowerCase(),
+                            );
+                        if (type === 'number') cy.checkNumber(text, val, operation);
+                        if (type === 'date') cy.checkDate(text, val, operation);
+                    });
+            }
+        });
+    });
+});
+
+Cypress.Commands.add('checkDate', (rawDate, expectedVal, operation) => {
+    const date = moment(rawDate.trim(), 'MM/DD/YYYY');
+    const compareDate = moment(expectedVal, 'DD/MM/YYYY');
+
+    switch (operation) {
+        case 'equal':
+            expect(text.trim()).to.equal(compareDate);
+            break;
+        case 'before':
+            expect(date.isBefore(compareDate)).to.be.true;
+            break;
+        case 'after':
+            expect(date.isAfter(compareDate)).to.be.true;
+    }
+});
+
+Cypress.Commands.add('selectDescriptorOption', (opt = 1) => {
+    const listItem = '[data-cy="descriptor-more-opts_list"]';
+    cy.get('body').then(($body) => {
+        if (!$body.find(listItem).length) cy.openActionsDescriptor();
+    });
+
+    cy.waitForElement(listItem);
+    cy.get(`${listItem} > :not(template):nth-of-type(${opt})`).click();
+});
+
+Cypress.Commands.add('validateCheckbox', (selector, expectedVal = 'true') => {
+    cy.get(selector).should('have.attr', 'aria-checked', expectedVal.toString());
+});
+
+Cypress.Commands.add('validateDownload', (trigger, opts = {}) => {
+    const {
+        url = /api\/dms\/\d+\/downloadFile\?access_token=.+/,
+        types = ['text/plain', 'image/jpeg'],
+        alias = 'download',
+    } = opts;
+    cy.intercept('GET', url).as(alias);
+    trigger().then(() => {
+        cy.wait(`@${alias}`).then(({ response }) => {
+            expect(response.statusCode).to.equal(200);
+            const isValidType = types.some((type) =>
+                response.headers['content-type'].includes(type),
+            );
+            expect(isValidType).to.be.true;
+        });
+    });
+});
+
+Cypress.Commands.add('validatePdfDownload', (match, trigger) => {
+    cy.window().then((win) => {
+        cy.stub(win, 'open')
+            .callsFake(() => null)
+            .as('pdf');
+    });
+    trigger();
+    cy.get('@pdf')
+        .should('be.calledOnce')
+        .then((stub) => {
+            const [url] = stub.getCall(0).args;
+            expect(url).to.match(match);
+            cy.request(url).then((response) =>
+                expect(response.headers['content-type']).to.include('application/pdf'),
+            );
+        });
+});
+
+Cypress.Commands.add('clicDescriptorAction', (index = 1) => {
+    cy.get(`[data-cy="descriptor_actions"] .q-btn:nth-of-type(${index})`).click();
+});
+
+Cypress.Commands.add('checkQueryParams', (expectedParams = {}) => {
+    cy.url().then((url) => {
+        const urlParams = new URLSearchParams(url.split('?')[1]);
+
+        for (const key in expectedParams) {
+            const expected = expectedParams[key];
+            const param = JSON.parse(decodeURIComponent(urlParams.get(key)));
+
+            if (typeof expected === 'object') {
+                const { subkey, val } = expected;
+                expect(param[subkey]).to.equal(val);
+            } else expect(param).to.equal(expected);
+        }
+    });
+});
+
+Cypress.Commands.add('validateScrollContent', (validations) => {
+    validations.forEach(({ row, col, text }) => {
+        cy.get(`.q-scrollarea__content > :nth-child(${row}) > :nth-child(${col})`).should(
+            'have.text',
+            text,
+        );
+    });
+});
diff --git a/test/cypress/support/index.js b/test/cypress/support/index.js
index 87e869b6d..b0f0fb3b1 100644
--- a/test/cypress/support/index.js
+++ b/test/cypress/support/index.js
@@ -40,6 +40,11 @@ style.innerHTML = `
 `;
 document.head.appendChild(style);
 
+// FIXME: https://redmine.verdnatura.es/issues/8771
+Cypress.on('uncaught:exception', (err) => {
+    if (err.code === 'ERR_CANCELED') return false;
+});
+
 const waitForApiReady = (url, maxRetries = 20, delay = 1000) => {
     let retries = 0;
 
diff --git a/test/vitest/helper.js b/test/vitest/helper.js
index 5e283c1d4..30324a1f9 100644
--- a/test/vitest/helper.js
+++ b/test/vitest/helper.js
@@ -4,8 +4,6 @@ import { createTestingPinia } from '@pinia/testing';
 import { vi } from 'vitest';
 import { i18n } from 'src/boot/i18n';
 import { Notify, Dialog } from 'quasar';
-import axios from 'axios';
-import keyShortcut from 'src/boot/keyShortcut';
 import * as useValidator from 'src/composables/useValidator';
 
 installQuasarPlugin({
@@ -54,8 +52,6 @@ vi.mock('vue-router', () => ({
     onBeforeRouteLeave: () => {},
 }));
 
-vi.mock('axios');
-
 vi.spyOn(useValidator, 'useValidator').mockImplementation(() => {
     return {
         validate: vi.fn(),
@@ -125,5 +121,4 @@ export function createWrapper(component, options) {
 
     return { vm, wrapper };
 }
-
-export { axios, flushPromises };
+export { flushPromises };
diff --git a/test/vitest/setup-file.js b/test/vitest/setup-file.js
index 288f80beb..0ba9e53c2 100644
--- a/test/vitest/setup-file.js
+++ b/test/vitest/setup-file.js
@@ -1 +1,27 @@
 // This file will be run before each test file, don't delete or vitest will not work.
+import { vi } from 'vitest';
+
+vi.mock('axios');
+vi.mock('vue-router', () => ({
+    useRouter: () => ({
+        push: vi.fn(),
+        replace: vi.fn(),
+        currentRoute: {
+            value: {
+                params: {
+                    id: 1,
+                },
+                meta: { moduleName: 'mockName' },
+                matched: [{ path: 'mockName/list' }],
+            },
+        },
+    }),
+    useRoute: () => ({
+        matched: [],
+        query: {},
+        params: {},
+        meta: { moduleName: 'mockName' },
+        path: 'mockSection/list',
+    }),
+    onBeforeRouteLeave: () => {},
+}));
diff --git a/vitest.config.js b/vitest.config.js
index f856a1dc9..c2c3661a9 100644
--- a/vitest.config.js
+++ b/vitest.config.js
@@ -5,12 +5,11 @@ import jsconfigPaths from 'vite-jsconfig-paths';
 import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
 import path from 'path';
 
-let reporters,
-    outputFile;
+let reporters, outputFile;
 
 if (process.env.CI) {
     reporters = ['junit', 'default'];
-    outputFile = {junit: './junit/vitest.xml'};
+    outputFile = { junit: './junit/vitest.xml' };
 } else {
     reporters = 'default';
 }
@@ -18,6 +17,7 @@ if (process.env.CI) {
 // https://vitejs.dev/config/
 export default defineConfig({
     test: {
+        globals: true,
         reporters,
         outputFile,
         environment: 'happy-dom',
@@ -28,6 +28,9 @@ export default defineConfig({
             'src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
         ],
     },
+    server: {
+        hmr: { overlay: false },
+    },
     plugins: [
         vue({
             template: {
@@ -39,8 +42,11 @@ export default defineConfig({
             sassVariables: 'src/quasar-variables.scss',
         }),
         VueI18nPlugin({
+            strictMessage: false,
+
+            runtimeOnly: false,
             include: [
-                path.resolve(__dirname, 'src/i18n/**'),
+                path.resolve(__dirname, 'src/i18n/locale/**'),
                 path.resolve(__dirname, 'src/pages/**/locale/**'),
             ],
         }),