Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8717-reviewAndFixAgencySection
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
868172d208
|
@ -31,6 +31,7 @@ yarn-error.log*
|
||||||
# Cypress directories and files
|
# Cypress directories and files
|
||||||
/test/cypress/videos
|
/test/cypress/videos
|
||||||
/test/cypress/screenshots
|
/test/cypress/screenshots
|
||||||
|
/junit
|
||||||
|
|
||||||
# VitePress directories and files
|
# VitePress directories and files
|
||||||
/docs/.vitepress/cache
|
/docs/.vitepress/cache
|
||||||
|
|
222
CHANGELOG.md
222
CHANGELOG.md
|
@ -1,3 +1,225 @@
|
||||||
|
# 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 🆕
|
||||||
|
|
||||||
|
- feat: add order for table (origin/8681_ticketAdvance_updates) by:Javier Segarra
|
||||||
|
- feat: detect when is descriptor proxy by:Javier Segarra
|
||||||
|
- feat: refs #7356 update CrudModel by:Javier Segarra
|
||||||
|
- feat: refs #8242 remove teleport by:Javier Segarra
|
||||||
|
- feat: refs #8242 use stateStore by:Javier Segarra
|
||||||
|
- fix: fixed negative bases style by:Jon
|
||||||
|
- fix: fixed style when clicking on icons by:Jon
|
||||||
|
- refactor: refs #6897 remove debug logs and unused style (origin/6897-fixSomeCaus) by:pablone
|
||||||
|
- style: refs #7356 eslint format by:Javier Segarra
|
||||||
|
|
||||||
|
### Changed 📦
|
||||||
|
|
||||||
|
- perf: refs #7356 minor changes (origin/7356_ticketService) by:Javier Segarra
|
||||||
|
- refactor: refs #6897 remove debug logs and unused style (origin/6897-fixSomeCaus) by:pablone
|
||||||
|
- refactor: refs #6897 update component props and attributes for consistency and improved functionality (origin/6897-fixMinorIssues) by:pablone
|
||||||
|
- refactor: refs #6897 update component props and improve UI handling in Entry pages by:pablone
|
||||||
|
- refactor: refs #6897 update VnTable components for improved value handling and UI adjustments (origin/6897-minorFixes) by:pablone
|
||||||
|
- refactor: refs #8697 simplify date handling in ItemDiary component by:pablone
|
||||||
|
|
||||||
|
### Fixed 🛠️
|
||||||
|
|
||||||
|
- fix: add datakey by:Javier Segarra
|
||||||
|
- fix: fixed account descriptor menu and created e2e by:Jon
|
||||||
|
- fix: fixed negative bases style by:Jon
|
||||||
|
- fix: fixed style when clicking on icons by:Jon
|
||||||
|
- fix: refs #6553 workerBusiness (origin/6553-fixWorkerBusinessV2) by:carlossa
|
||||||
|
- fix: refs #6553 workerBusiness v3 by:carlossa
|
||||||
|
- fix: refs #6897 prevent default event behavior in autocompleteExpense function by:pablone
|
||||||
|
- fix: refs #7356 chaining params by:Javier Segarra
|
||||||
|
- fix: refs #7356 ticketService by:Javier Segarra
|
||||||
|
- fix: refs #8242 workerDepartmentTree bug (origin/8242_leftMenu_responsive) by:Javier Segarra
|
||||||
|
- fix: workerBasicData by:carlossa
|
||||||
|
- Revert "revert 1015acefb7e400be2d8b5958dba69b4d98276b34" (origin/fix_revert_revert, fix_revert_revert) by:alexm
|
||||||
|
|
||||||
# Version 25.06 - 2025-02-18
|
# Version 25.06 - 2025-02-18
|
||||||
|
|
||||||
### Added 🆕
|
### Added 🆕
|
||||||
|
|
|
@ -26,6 +26,7 @@ node {
|
||||||
// https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
|
// https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
|
||||||
echo "NODE_NAME: ${env.NODE_NAME}"
|
echo "NODE_NAME: ${env.NODE_NAME}"
|
||||||
echo "WORKSPACE: ${env.WORKSPACE}"
|
echo "WORKSPACE: ${env.WORKSPACE}"
|
||||||
|
echo "CHANGE_TARGET: ${env.CHANGE_TARGET}"
|
||||||
|
|
||||||
configFileProvider([
|
configFileProvider([
|
||||||
configFile(fileId: 'salix-front.properties',
|
configFile(fileId: 'salix-front.properties',
|
||||||
|
@ -107,24 +108,32 @@ pipeline {
|
||||||
}
|
}
|
||||||
stage('E2E') {
|
stage('E2E') {
|
||||||
environment {
|
environment {
|
||||||
CREDENTIALS = credentials('docker-registry')
|
CREDS = credentials('docker-registry')
|
||||||
COMPOSE_PROJECT = "${PROJECT_NAME}-${env.BUILD_ID}"
|
COMPOSE_PROJECT = "${PROJECT_NAME}-${env.BUILD_ID}"
|
||||||
COMPOSE_PARAMS = "-p ${env.COMPOSE_PROJECT} -f test/cypress/docker-compose.yml --project-directory ."
|
COMPOSE_PARAMS = "-p ${env.COMPOSE_PROJECT} -f test/cypress/docker-compose.yml --project-directory ."
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
sh 'rm junit/e2e-*.xml || true'
|
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'
|
env.COMPOSE_TAG = PROTECTED_BRANCH.contains(env.CHANGE_TARGET) ? env.CHANGE_TARGET : 'dev'
|
||||||
|
|
||||||
def image = docker.build('lilium-dev', '-f docs/Dockerfile.dev docs')
|
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"
|
sh "docker-compose ${env.COMPOSE_PARAMS} up -d"
|
||||||
image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ") {
|
|
||||||
sh 'cypress run --browser chromium || true'
|
image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") {
|
||||||
|
sh 'sh test/cypress/cypressParallel.sh 2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
sh "docker-compose ${env.COMPOSE_PARAMS} down -v"
|
sh "docker-compose ${env.COMPOSE_PARAMS} down -v"
|
||||||
|
archiveArtifacts artifacts: 'test/cypress/screenshots/**/*', allowEmptyArchive: true
|
||||||
junit(
|
junit(
|
||||||
testResults: 'junit/e2e-*.xml',
|
testResults: 'junit/e2e-*.xml',
|
||||||
allowEmptyResults: true
|
allowEmptyResults: true
|
||||||
|
|
12
README.md
12
README.md
|
@ -32,6 +32,18 @@ pnpm run test:front
|
||||||
pnpm run test:e2e
|
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
|
### Build the app for production
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
import { defineConfig } from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
|
|
||||||
let urlHost, reporter, reporterOptions;
|
let urlHost, reporter, reporterOptions, timeouts;
|
||||||
|
|
||||||
if (process.env.CI) {
|
if (process.env.CI) {
|
||||||
urlHost = 'front';
|
urlHost = 'front';
|
||||||
reporter = 'junit';
|
reporter = 'junit';
|
||||||
reporterOptions = {
|
reporterOptions = {
|
||||||
mochaFile: 'junit/e2e-[hash].xml',
|
mochaFile: 'junit/e2e-[hash].xml',
|
||||||
toConsole: false,
|
};
|
||||||
|
timeouts = {
|
||||||
|
defaultCommandTimeout: 30000,
|
||||||
|
requestTimeout: 30000,
|
||||||
|
responseTimeout: 60000,
|
||||||
|
pageLoadTimeout: 60000,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
urlHost = 'localhost';
|
urlHost = 'localhost';
|
||||||
|
@ -20,17 +25,19 @@ if (process.env.CI) {
|
||||||
reportDir: 'test/cypress/reports',
|
reportDir: 'test/cypress/reports',
|
||||||
inlineAssets: true,
|
inlineAssets: true,
|
||||||
};
|
};
|
||||||
|
timeouts = {
|
||||||
|
defaultCommandTimeout: 10000,
|
||||||
|
requestTimeout: 10000,
|
||||||
|
responseTimeout: 30000,
|
||||||
|
pageLoadTimeout: 60000,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
e2e: {
|
e2e: {
|
||||||
baseUrl: `http://${urlHost}:9000`,
|
baseUrl: `http://${urlHost}:9000`,
|
||||||
experimentalStudio: false,
|
experimentalStudio: false,
|
||||||
defaultCommandTimeout: 10000,
|
|
||||||
trashAssetsBeforeRuns: false,
|
trashAssetsBeforeRuns: false,
|
||||||
requestTimeout: 10000,
|
|
||||||
responseTimeout: 30000,
|
|
||||||
pageLoadTimeout: 60000,
|
|
||||||
defaultBrowser: 'chromium',
|
defaultBrowser: 'chromium',
|
||||||
fixturesFolder: 'test/cypress/fixtures',
|
fixturesFolder: 'test/cypress/fixtures',
|
||||||
screenshotsFolder: 'test/cypress/screenshots',
|
screenshotsFolder: 'test/cypress/screenshots',
|
||||||
|
@ -50,8 +57,8 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
viewportWidth: 1280,
|
viewportWidth: 1280,
|
||||||
viewportHeight: 720,
|
viewportHeight: 720,
|
||||||
|
...timeouts,
|
||||||
|
includeShadowDom: true,
|
||||||
|
waitForAnimations: true,
|
||||||
},
|
},
|
||||||
experimentalMemoryManagement: true,
|
|
||||||
defaultCommandTimeout: 10000,
|
|
||||||
numTestsKeptInMemory: 2,
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,6 +25,8 @@ RUN apt-get update \
|
||||||
libnss3 \
|
libnss3 \
|
||||||
libxss1 \
|
libxss1 \
|
||||||
libxtst6 \
|
libxtst6 \
|
||||||
|
mesa-vulkan-drivers \
|
||||||
|
vulkan-tools \
|
||||||
xauth \
|
xauth \
|
||||||
xvfb \
|
xvfb \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
|
@ -39,7 +41,7 @@ ENV PNPM_HOME="/home/app/.local/share/pnpm"
|
||||||
ENV PATH="$PNPM_HOME:$PATH"
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
|
|
||||||
RUN pnpm setup \
|
RUN pnpm setup \
|
||||||
&& pnpm install --global cypress@13.6.6 \
|
&& pnpm install --global cypress@14.1.0 \
|
||||||
&& cypress install
|
&& cypress install
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
13
package.json
13
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "25.10.0",
|
"version": "25.14.0",
|
||||||
"description": "Salix frontend",
|
"description": "Salix frontend",
|
||||||
"productName": "Salix",
|
"productName": "Salix",
|
||||||
"author": "Verdnatura",
|
"author": "Verdnatura",
|
||||||
|
@ -13,6 +13,8 @@
|
||||||
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||||
"test:e2e": "cypress open",
|
"test:e2e": "cypress open",
|
||||||
"test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
|
"test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
|
||||||
|
"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": "echo \"See package.json => scripts for available tests.\" && exit 0",
|
||||||
"test:front": "vitest",
|
"test:front": "vitest",
|
||||||
"test:front:ci": "vitest run",
|
"test:front:ci": "vitest run",
|
||||||
|
@ -47,18 +49,21 @@
|
||||||
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
|
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
|
||||||
"@vue/test-utils": "^2.4.4",
|
"@vue/test-utils": "^2.4.4",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"cypress": "^13.6.6",
|
"cypress": "^14.1.0",
|
||||||
"cypress-mochawesome-reporter": "^3.8.2",
|
"cypress-mochawesome-reporter": "^3.8.2",
|
||||||
"eslint": "^9.18.0",
|
"eslint": "^9.18.0",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
"eslint-plugin-cypress": "^4.1.0",
|
"eslint-plugin-cypress": "^4.1.0",
|
||||||
"eslint-plugin-vue": "^9.32.0",
|
"eslint-plugin-vue": "^9.32.0",
|
||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
|
"junit-merge": "^2.0.0",
|
||||||
|
"mocha": "^11.1.0",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"sass": "^1.83.4",
|
"sass": "^1.83.4",
|
||||||
"vitepress": "^1.6.3",
|
"vitepress": "^1.6.3",
|
||||||
"vitest": "^0.34.0"
|
"vitest": "^0.34.0",
|
||||||
|
"xunit-viewer": "^10.6.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20 || ^18 || ^16",
|
"node": "^20 || ^18 || ^16",
|
||||||
|
@ -71,4 +76,4 @@
|
||||||
"vite": "^6.0.11",
|
"vite": "^6.0.11",
|
||||||
"vitest": "^0.31.1"
|
"vitest": "^0.31.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
2082
pnpm-lock.yaml
2082
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -181,17 +181,19 @@ async function saveChanges(data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let changes = data || getChanges();
|
let changes = data || getChanges();
|
||||||
if ($props.beforeSaveFn) {
|
if ($props.beforeSaveFn) changes = await $props.beforeSaveFn(changes, getChanges);
|
||||||
changes = await $props.beforeSaveFn(changes, getChanges);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (changes?.creates?.length === 0 && changes?.updates?.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await axios.post($props.saveUrl || $props.url + '/crud', changes);
|
await axios.post($props.saveUrl || $props.url + '/crud', changes);
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
originalData.value = JSON.parse(JSON.stringify(formData.value));
|
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;
|
hasChanges.value = false;
|
||||||
emit('saveChanges', data);
|
emit('saveChanges', data);
|
||||||
|
|
|
@ -188,7 +188,7 @@ const selectItem = ({ id }) => {
|
||||||
>
|
>
|
||||||
<template #body-cell-id="{ row }">
|
<template #body-cell-id="{ row }">
|
||||||
<QTd auto-width @click.stop>
|
<QTd auto-width @click.stop>
|
||||||
<QBtn flat color="blue">{{ row.id }}</QBtn>
|
<QBtn flat class="link">{{ row.id }}</QBtn>
|
||||||
<ItemDescriptorProxy :id="row.id" />
|
<ItemDescriptorProxy :id="row.id" />
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -124,7 +124,7 @@ const selectTravel = ({ id }) => {
|
||||||
<FetchData
|
<FetchData
|
||||||
url="AgencyModes"
|
url="AgencyModes"
|
||||||
@on-fetch="(data) => (agenciesOptions = data)"
|
@on-fetch="(data) => (agenciesOptions = data)"
|
||||||
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
:filter="{ fields: ['id', 'name'], order: ['name ASC'] }"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -196,7 +196,7 @@ const selectTravel = ({ id }) => {
|
||||||
>
|
>
|
||||||
<template #body-cell-id="{ row }">
|
<template #body-cell-id="{ row }">
|
||||||
<QTd auto-width @click.stop data-cy="travelFk-travel-form">
|
<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" />
|
<TravelDescriptorProxy :id="row.id" />
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -77,6 +77,7 @@ watch(
|
||||||
function findMatches(search, item) {
|
function findMatches(search, item) {
|
||||||
const matches = [];
|
const matches = [];
|
||||||
function findRoute(search, item) {
|
function findRoute(search, item) {
|
||||||
|
if (!item?.children) return;
|
||||||
for (const child of item.children) {
|
for (const child of item.children) {
|
||||||
if (search?.indexOf(child.name) > -1) {
|
if (search?.indexOf(child.name) > -1) {
|
||||||
matches.push(child);
|
matches.push(child);
|
||||||
|
@ -92,7 +93,7 @@ function findMatches(search, item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addChildren(module, route, parent) {
|
function addChildren(module, route, parent) {
|
||||||
const menus = route?.meta?.menu ?? route?.menus?.[props.source]; //backwards compatible
|
const menus = route?.meta?.menu;
|
||||||
if (!menus) return;
|
if (!menus) return;
|
||||||
|
|
||||||
const matches = findMatches(menus, route);
|
const matches = findMatches(menus, route);
|
||||||
|
@ -107,11 +108,7 @@ function getRoutes() {
|
||||||
main: getMainRoutes,
|
main: getMainRoutes,
|
||||||
card: getCardRoutes,
|
card: getCardRoutes,
|
||||||
};
|
};
|
||||||
try {
|
handleRoutes[props.source]();
|
||||||
handleRoutes[props.source]();
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error(`Method is not defined`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function getMainRoutes() {
|
function getMainRoutes() {
|
||||||
const modules = Object.assign([], navigation.getModules().value);
|
const modules = Object.assign([], navigation.getModules().value);
|
||||||
|
@ -122,7 +119,6 @@ function getMainRoutes() {
|
||||||
);
|
);
|
||||||
if (!moduleDef) continue;
|
if (!moduleDef) continue;
|
||||||
item.children = [];
|
item.children = [];
|
||||||
|
|
||||||
addChildren(item.module, moduleDef, item.children);
|
addChildren(item.module, moduleDef, item.children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,21 +128,16 @@ function getMainRoutes() {
|
||||||
function getCardRoutes() {
|
function getCardRoutes() {
|
||||||
const currentRoute = route.matched[1];
|
const currentRoute = route.matched[1];
|
||||||
const currentModule = toLowerCamel(currentRoute.name);
|
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;
|
let index = route.matched.length - 1;
|
||||||
while (!menuRoute && index > 0) {
|
while (!moduleDef && index > 0) {
|
||||||
if (route.matched[index]?.meta?.menu) menuRoute = route.matched[index];
|
if (route.matched[index]?.meta?.menu) moduleDef = route.matched[index];
|
||||||
index--;
|
index--;
|
||||||
}
|
}
|
||||||
return menuRoute;
|
|
||||||
|
if (!moduleDef) return;
|
||||||
|
addChildren(currentModule, moduleDef, items.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function togglePinned(item, event) {
|
async function togglePinned(item, event) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ const refresh = () => window.location.reload();
|
||||||
:class="{
|
:class="{
|
||||||
'no-visible': !stateQuery.isLoading().value,
|
'no-visible': !stateQuery.isLoading().value,
|
||||||
}"
|
}"
|
||||||
size="xs"
|
size="sm"
|
||||||
data-cy="loading-spinner"
|
data-cy="loading-spinner"
|
||||||
/>
|
/>
|
||||||
<QSpace />
|
<QSpace />
|
||||||
|
|
|
@ -12,20 +12,42 @@ defineProps({ row: { type: Object, required: true } });
|
||||||
>
|
>
|
||||||
<QIcon name="vn:claims" size="xs">
|
<QIcon name="vn:claims" size="xs">
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('ticketSale.claim') }}:
|
{{ $t('ticketSale.claim') }}:
|
||||||
{{ row.claim?.claimFk }}
|
{{ row.claim?.claimFk }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</router-link>
|
</router-link>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row?.risk"
|
v-if="row?.reserved"
|
||||||
|
color="primary"
|
||||||
|
name="vn:reserva"
|
||||||
|
size="xs"
|
||||||
|
data-cy="ticketSaleReservedIcon"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('ticketSale.reserved') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
v-if="row?.isDeleted"
|
||||||
|
color="primary"
|
||||||
|
name="vn:deletedTicket"
|
||||||
|
size="xs"
|
||||||
|
data-cy="ticketDeletedIcon"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('Ticket deleted') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
v-if="row?.hasRisk"
|
||||||
name="vn:risk"
|
name="vn:risk"
|
||||||
:color="row.hasHighRisk ? 'negative' : 'primary'"
|
:color="row.hasHighRisk ? 'negative' : 'primary'"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ $t('salesTicketsTable.risk') }}:
|
{{ $t('salesTicketsTable.risk') }}:
|
||||||
{{ toCurrency(row.risk - row.credit) }}
|
{{ toCurrency(row.risk - (row.credit ?? 0)) }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
@ -67,12 +89,7 @@ defineProps({ row: { type: Object, required: true } });
|
||||||
>
|
>
|
||||||
<QTooltip>{{ $t('salesTicketsTable.purchaseRequest') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.purchaseRequest') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon v-if="row?.isTaxDataChecked" name="vn:no036" color="primary" size="xs">
|
||||||
v-if="row?.isTaxDataChecked !== 0"
|
|
||||||
name="vn:no036"
|
|
||||||
color="primary"
|
|
||||||
size="xs"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ $t('salesTicketsTable.noVerifiedData') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.noVerifiedData') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon v-if="row?.isFreezed" name="vn:frozen" color="primary" size="xs">
|
<QIcon v-if="row?.isFreezed" name="vn:frozen" color="primary" size="xs">
|
||||||
|
|
|
@ -87,7 +87,7 @@ const makeInvoice = async () => {
|
||||||
(data) => (
|
(data) => (
|
||||||
(rectificativeTypeOptions = data),
|
(rectificativeTypeOptions = data),
|
||||||
(transferInvoiceParams.cplusRectificationTypeFk = data.filter(
|
(transferInvoiceParams.cplusRectificationTypeFk = data.filter(
|
||||||
(type) => type.description == 'I – Por diferencias'
|
(type) => type.description == 'I – Por diferencias',
|
||||||
)[0].id)
|
)[0].id)
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
@ -100,7 +100,7 @@ const makeInvoice = async () => {
|
||||||
(data) => (
|
(data) => (
|
||||||
(siiTypeInvoiceOutsOptions = data),
|
(siiTypeInvoiceOutsOptions = data),
|
||||||
(transferInvoiceParams.siiTypeInvoiceOutFk = data.filter(
|
(transferInvoiceParams.siiTypeInvoiceOutFk = data.filter(
|
||||||
(type) => type.code == 'R4'
|
(type) => type.code == 'R4',
|
||||||
)[0].id)
|
)[0].id)
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
@ -122,7 +122,6 @@ const makeInvoice = async () => {
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Client')"
|
:label="t('Client')"
|
||||||
:options="clientsOptions"
|
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
|
|
|
@ -6,6 +6,7 @@ import VnSelect from 'components/common/VnSelect.vue';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnInputTime from 'components/common/VnInputTime.vue';
|
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||||
|
import VnCheckbox from 'components/common/VnCheckbox.vue';
|
||||||
import VnColumn from 'components/VnTable/VnColumn.vue';
|
import VnColumn from 'components/VnTable/VnColumn.vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -106,7 +107,7 @@ const components = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
checkbox: {
|
checkbox: {
|
||||||
component: markRaw(QCheckbox),
|
component: markRaw(VnCheckbox),
|
||||||
event: updateEvent,
|
event: updateEvent,
|
||||||
attrs: {
|
attrs: {
|
||||||
class: $props.showTitle ? 'q-py-sm' : 'q-px-md q-py-xs fit',
|
class: $props.showTitle ? 'q-py-sm' : 'q-px-md q-py-xs fit',
|
||||||
|
|
|
@ -55,6 +55,10 @@ const $props = defineProps({
|
||||||
type: [Function, Boolean],
|
type: [Function, Boolean],
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
rowCtrlClick: {
|
||||||
|
type: [Function, Boolean],
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
redirect: {
|
redirect: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: null,
|
||||||
|
@ -136,7 +140,7 @@ const $props = defineProps({
|
||||||
},
|
},
|
||||||
dataCy: {
|
dataCy: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'vn-table',
|
default: 'vnTable',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -591,18 +595,17 @@ function cardClick(_, row) {
|
||||||
|
|
||||||
function removeTextValue(data, getChanges) {
|
function removeTextValue(data, getChanges) {
|
||||||
let changes = data.updates;
|
let changes = data.updates;
|
||||||
if (!changes) return data;
|
if (changes) {
|
||||||
|
for (const change of changes) {
|
||||||
for (const change of changes) {
|
for (const key in change.data) {
|
||||||
for (const key in change.data) {
|
if (key.endsWith('VnTableTextValue')) {
|
||||||
if (key.endsWith('VnTableTextValue')) {
|
delete change.data[key];
|
||||||
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);
|
if ($attrs?.beforeSaveFn) data = $attrs.beforeSaveFn(data, getChanges);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -681,7 +684,7 @@ const rowCtrlClickFunction = computed(() => {
|
||||||
@update:selected="emit('update:selected', $event)"
|
@update:selected="emit('update:selected', $event)"
|
||||||
@selection="(details) => handleSelection(details, rows)"
|
@selection="(details) => handleSelection(details, rows)"
|
||||||
:hide-selected-banner="true"
|
:hide-selected-banner="true"
|
||||||
:data-cy="$props.dataCy ?? 'vnTable'"
|
:data-cy
|
||||||
>
|
>
|
||||||
<template #top-left v-if="!$props.withoutHeader">
|
<template #top-left v-if="!$props.withoutHeader">
|
||||||
<slot name="top-left"> </slot>
|
<slot name="top-left"> </slot>
|
||||||
|
@ -772,12 +775,13 @@ const rowCtrlClickFunction = computed(() => {
|
||||||
:data-col-field="col?.name"
|
:data-col-field="col?.name"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="no-padding no-margin peter"
|
class="no-padding no-margin"
|
||||||
style="
|
style="
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
"
|
"
|
||||||
|
:data-cy="`vnTableCell_${col.name}`"
|
||||||
>
|
>
|
||||||
<slot
|
<slot
|
||||||
:name="`column-${col.name}`"
|
:name="`column-${col.name}`"
|
||||||
|
@ -916,12 +920,24 @@ const rowCtrlClickFunction = computed(() => {
|
||||||
:row-index="index"
|
:row-index="index"
|
||||||
>
|
>
|
||||||
<VnColumn
|
<VnColumn
|
||||||
:column="col"
|
:column="{
|
||||||
|
...col,
|
||||||
|
disable:
|
||||||
|
col?.component ===
|
||||||
|
'checkbox'
|
||||||
|
? true
|
||||||
|
: false,
|
||||||
|
}"
|
||||||
:row="row"
|
:row="row"
|
||||||
:is-editable="false"
|
:is-editable="false"
|
||||||
v-model="row[col.name]"
|
v-model="row[col.name]"
|
||||||
component-prop="columnField"
|
component-prop="columnField"
|
||||||
:show-label="true"
|
:show-label="
|
||||||
|
col?.component ===
|
||||||
|
'checkbox'
|
||||||
|
? false
|
||||||
|
: true
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
</span>
|
</span>
|
||||||
|
@ -962,6 +978,8 @@ const rowCtrlClickFunction = computed(() => {
|
||||||
v-for="col of cols.filter((cols) => cols.visible ?? true)"
|
v-for="col of cols.filter((cols) => cols.visible ?? true)"
|
||||||
:key="col?.id"
|
:key="col?.id"
|
||||||
:class="getColAlign(col)"
|
:class="getColAlign(col)"
|
||||||
|
:style="col?.width ? `max-width: ${col?.width}` : ''"
|
||||||
|
style="font-size: small"
|
||||||
>
|
>
|
||||||
<slot
|
<slot
|
||||||
:name="`column-footer-${col.name}`"
|
:name="`column-footer-${col.name}`"
|
||||||
|
@ -1024,38 +1042,43 @@ const rowCtrlClickFunction = computed(() => {
|
||||||
@on-data-saved="(_, res) => createForm.onDataSaved(res)"
|
@on-data-saved="(_, res) => createForm.onDataSaved(res)"
|
||||||
>
|
>
|
||||||
<template #form-inputs="{ data }">
|
<template #form-inputs="{ data }">
|
||||||
<div :style="createComplement?.containerStyle">
|
<slot name="alter-create" :data="data">
|
||||||
<div
|
<div :style="createComplement?.containerStyle">
|
||||||
:style="createComplement?.previousStyle"
|
<div
|
||||||
v-if="!quasar.screen.xs"
|
: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"
|
|
||||||
>
|
>
|
||||||
<VnColumn
|
<slot name="previous-create-dialog" :data="data" />
|
||||||
:column="{
|
</div>
|
||||||
...column,
|
<div
|
||||||
...{ disable: column?.createDisable ?? false },
|
class="grid-create"
|
||||||
}"
|
:style="createComplement?.columnGridStyle"
|
||||||
:row="{}"
|
>
|
||||||
default="input"
|
<slot
|
||||||
v-model="data[column.name]"
|
v-for="column of splittedColumns.create"
|
||||||
:show-label="true"
|
:key="column.name"
|
||||||
component-prop="columnCreate"
|
:name="`column-create-${column.name}`"
|
||||||
:data-cy="`${column.name}-create-popup`"
|
:data="data"
|
||||||
/>
|
:column-name="column.name"
|
||||||
</slot>
|
:label="column.label"
|
||||||
<slot name="more-create-dialog" :data="data" />
|
>
|
||||||
|
<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>
|
||||||
</div>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
</FormModelPopup>
|
</FormModelPopup>
|
||||||
</QDialog>
|
</QDialog>
|
||||||
|
@ -1132,9 +1155,13 @@ es:
|
||||||
|
|
||||||
.grid-create {
|
.grid-create {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
|
grid-template-columns: 1fr 1fr;
|
||||||
|
max-width: 100%;
|
||||||
grid-gap: 20px;
|
grid-gap: 20px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
.col-span-2 {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-one {
|
.flex-one {
|
||||||
|
|
|
@ -30,8 +30,8 @@ describe('CrudModel', () => {
|
||||||
saveFn: '',
|
saveFn: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
wrapper=wrapper.wrapper;
|
wrapper = wrapper.wrapper;
|
||||||
vm=wrapper.vm;
|
vm = wrapper.vm;
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -143,14 +143,14 @@ describe('CrudModel', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if object is empty', async () => {
|
it('should return true if object is empty', async () => {
|
||||||
dummyObj ={};
|
dummyObj = {};
|
||||||
result = vm.isEmpty(dummyObj);
|
result = vm.isEmpty(dummyObj);
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false if object is not empty', async () => {
|
it('should return false if object is not empty', async () => {
|
||||||
dummyObj = {a:1, b:2, c:3};
|
dummyObj = { a: 1, b: 2, c: 3 };
|
||||||
result = vm.isEmpty(dummyObj);
|
result = vm.isEmpty(dummyObj);
|
||||||
|
|
||||||
expect(result).toBe(false);
|
expect(result).toBe(false);
|
||||||
|
@ -158,29 +158,31 @@ describe('CrudModel', () => {
|
||||||
|
|
||||||
it('should return true if array is empty', async () => {
|
it('should return true if array is empty', async () => {
|
||||||
dummyArray = [];
|
dummyArray = [];
|
||||||
result = vm.isEmpty(dummyArray);
|
result = vm.isEmpty(dummyArray);
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false if array is not empty', async () => {
|
it('should return false if array is not empty', async () => {
|
||||||
dummyArray = [1,2,3];
|
dummyArray = [1, 2, 3];
|
||||||
result = vm.isEmpty(dummyArray);
|
result = vm.isEmpty(dummyArray);
|
||||||
|
|
||||||
expect(result).toBe(false);
|
expect(result).toBe(false);
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('resetData()', () => {
|
describe('resetData()', () => {
|
||||||
it('should add $index to elements in data[] and sets originalData and formData with data', async () => {
|
it('should add $index to elements in data[] and sets originalData and formData with data', async () => {
|
||||||
data = [{
|
data = [
|
||||||
name: 'Tony',
|
{
|
||||||
lastName: 'Stark',
|
name: 'Tony',
|
||||||
age: 42,
|
lastName: 'Stark',
|
||||||
}];
|
age: 42,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
vm.resetData(data);
|
vm.resetData(data);
|
||||||
|
|
||||||
expect(vm.originalData).toEqual(data);
|
expect(vm.originalData).toEqual(data);
|
||||||
expect(vm.originalData[0].$index).toEqual(0);
|
expect(vm.originalData[0].$index).toEqual(0);
|
||||||
expect(vm.formData).toEqual(data);
|
expect(vm.formData).toEqual(data);
|
||||||
|
@ -200,7 +202,7 @@ describe('CrudModel', () => {
|
||||||
lastName: 'Stark',
|
lastName: 'Stark',
|
||||||
age: 42,
|
age: 42,
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.resetData(data);
|
vm.resetData(data);
|
||||||
|
|
||||||
expect(vm.originalData).toEqual(data);
|
expect(vm.originalData).toEqual(data);
|
||||||
|
@ -210,17 +212,19 @@ describe('CrudModel', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('saveChanges()', () => {
|
describe('saveChanges()', () => {
|
||||||
data = [{
|
data = [
|
||||||
name: 'Tony',
|
{
|
||||||
lastName: 'Stark',
|
name: 'Tony',
|
||||||
age: 42,
|
lastName: 'Stark',
|
||||||
}];
|
age: 42,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
it('should call saveFn if exists', async () => {
|
it('should call saveFn if exists', async () => {
|
||||||
await wrapper.setProps({ saveFn: vi.fn() });
|
await wrapper.setProps({ saveFn: vi.fn() });
|
||||||
|
|
||||||
vm.saveChanges(data);
|
vm.saveChanges(data);
|
||||||
|
|
||||||
expect(vm.saveFn).toHaveBeenCalledOnce();
|
expect(vm.saveFn).toHaveBeenCalledOnce();
|
||||||
expect(vm.isLoading).toBe(false);
|
expect(vm.isLoading).toBe(false);
|
||||||
expect(vm.hasChanges).toBe(false);
|
expect(vm.hasChanges).toBe(false);
|
||||||
|
@ -229,13 +233,15 @@ describe('CrudModel', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should use default url if there's not saveFn", async () => {
|
it("should use default url if there's not saveFn", async () => {
|
||||||
const postMock =vi.spyOn(axios, 'post');
|
const postMock = vi.spyOn(axios, 'post');
|
||||||
|
|
||||||
vm.formData = [{
|
vm.formData = [
|
||||||
name: 'Bruce',
|
{
|
||||||
lastName: 'Wayne',
|
name: 'Bruce',
|
||||||
age: 45,
|
lastName: 'Wayne',
|
||||||
}]
|
age: 45,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
await vm.saveChanges(data);
|
await vm.saveChanges(data);
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,7 @@ vi.mock('src/router/modules', () => ({
|
||||||
meta: {
|
meta: {
|
||||||
title: 'customers',
|
title: 'customers',
|
||||||
icon: 'vn:client',
|
icon: 'vn:client',
|
||||||
},
|
menu: ['CustomerList', 'CustomerCreate'],
|
||||||
menus: {
|
|
||||||
main: ['CustomerList', 'CustomerCreate'],
|
|
||||||
card: ['CustomerBasicData'],
|
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
@ -50,14 +47,6 @@ vi.mock('src/router/modules', () => ({
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'create',
|
|
||||||
name: 'CustomerCreate',
|
|
||||||
meta: {
|
|
||||||
title: 'createCustomer',
|
|
||||||
icon: 'vn:addperson',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -98,7 +87,7 @@ vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
|
||||||
icon: 'vn:client',
|
icon: 'vn:client',
|
||||||
moduleName: 'Customer',
|
moduleName: 'Customer',
|
||||||
keyBinding: 'c',
|
keyBinding: 'c',
|
||||||
menu: 'customer',
|
menu: ['customer'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -260,15 +249,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', () => {
|
it('should get routes for main source', () => {
|
||||||
vm.props.source = 'main';
|
vm.props.source = 'main';
|
||||||
vm.getRoutes();
|
vm.getRoutes();
|
||||||
|
@ -351,8 +331,9 @@ describe('addChildren', () => {
|
||||||
|
|
||||||
it('should handle routes with no meta menu', () => {
|
it('should handle routes with no meta menu', () => {
|
||||||
const route = {
|
const route = {
|
||||||
meta: {},
|
meta: {
|
||||||
menus: {},
|
menu: [],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const parent = [];
|
const parent = [];
|
||||||
|
|
|
@ -56,7 +56,12 @@ async function confirm() {
|
||||||
{{ t('The notification will be sent to the following address') }}
|
{{ t('The notification will be sent to the following address') }}
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="q-pt-none">
|
<QCardSection class="q-pt-none">
|
||||||
<VnInput v-model="address" is-outlined autofocus />
|
<VnInput
|
||||||
|
v-model="address"
|
||||||
|
is-outlined
|
||||||
|
autofocus
|
||||||
|
data-cy="SendEmailNotifiactionDialogInput"
|
||||||
|
/>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardActions align="right">
|
<QCardActions align="right">
|
||||||
<QBtn :label="t('globals.cancel')" color="primary" flat v-close-popup />
|
<QBtn :label="t('globals.cancel')" color="primary" flat v-close-popup />
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { nextTick, ref, watch } from 'vue';
|
import { nextTick, ref } from 'vue';
|
||||||
import { QInput } from 'quasar';
|
import VnInput from './VnInput.vue';
|
||||||
|
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
insertable: {
|
insertable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -14,70 +11,25 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
|
const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
|
||||||
|
const model = defineModel({ prop: 'modelValue' });
|
||||||
|
const inputRef = ref(false);
|
||||||
|
|
||||||
let internalValue = ref($props.modelValue);
|
function setCursorPosition(pos) {
|
||||||
|
const input = inputRef.value.vnInputRef.$el.querySelector('input');
|
||||||
watch(
|
input.focus();
|
||||||
() => $props.modelValue,
|
input.setSelectionRange(pos, pos);
|
||||||
(newVal) => {
|
|
||||||
internalValue.value = newVal;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => internalValue.value,
|
|
||||||
(newVal) => {
|
|
||||||
emit('update:modelValue', newVal);
|
|
||||||
accountShortToStandard();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleKeydown = (e) => {
|
|
||||||
if (e.key === 'Backspace') return;
|
|
||||||
if (e.key === '.') {
|
|
||||||
accountShortToStandard();
|
|
||||||
// TODO: Fix this setTimeout, with nextTick doesn't work
|
|
||||||
setTimeout(() => {
|
|
||||||
setCursorPosition(0, e.target);
|
|
||||||
}, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($props.insertable && e.key.match(/[0-9]/)) {
|
|
||||||
handleInsertMode(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function setCursorPosition(pos, el = vnInputRef.value) {
|
|
||||||
el.focus();
|
|
||||||
el.setSelectionRange(pos, pos);
|
|
||||||
}
|
}
|
||||||
const vnInputRef = ref(false);
|
|
||||||
const handleInsertMode = (e) => {
|
async function handleUpdateModel(val) {
|
||||||
e.preventDefault();
|
model.value = val?.at(-1) === '.' ? useAccountShortToStandard(val) : val;
|
||||||
const input = e.target;
|
await nextTick(() => setCursorPosition(0));
|
||||||
const cursorPos = input.selectionStart;
|
|
||||||
const { maxlength } = vnInputRef.value;
|
|
||||||
let currentValue = internalValue.value;
|
|
||||||
if (!currentValue) currentValue = e.key;
|
|
||||||
const newValue = e.key;
|
|
||||||
if (newValue && !isNaN(newValue) && cursorPos < maxlength) {
|
|
||||||
internalValue.value =
|
|
||||||
currentValue.substring(0, cursorPos) +
|
|
||||||
newValue +
|
|
||||||
currentValue.substring(cursorPos + 1);
|
|
||||||
}
|
|
||||||
nextTick(() => {
|
|
||||||
input.setSelectionRange(cursorPos + 1, cursorPos + 1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
function accountShortToStandard() {
|
|
||||||
internalValue.value = internalValue.value?.replace(
|
|
||||||
'.',
|
|
||||||
'0'.repeat(11 - internalValue.value.length)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QInput @keydown="handleKeydown" ref="vnInputRef" v-model="internalValue" />
|
<VnInput
|
||||||
|
v-model="model"
|
||||||
|
ref="inputRef"
|
||||||
|
:insertable
|
||||||
|
@update:model-value="handleUpdateModel"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,50 +1,56 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeMount, computed } from 'vue';
|
import { onBeforeMount } from 'vue';
|
||||||
import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router';
|
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import useCardSize from 'src/composables/useCardSize';
|
import useCardSize from 'src/composables/useCardSize';
|
||||||
import VnSubToolbar from '../ui/VnSubToolbar.vue';
|
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 props = defineProps({
|
const props = defineProps({
|
||||||
dataKey: { type: String, required: true },
|
dataKey: { type: String, required: true },
|
||||||
url: { type: String, default: undefined },
|
url: { type: String, default: undefined },
|
||||||
|
idInWhere: { type: Boolean, default: false },
|
||||||
filter: { type: Object, default: () => {} },
|
filter: { type: Object, default: () => {} },
|
||||||
descriptor: { type: Object, required: true },
|
descriptor: { type: Object, required: true },
|
||||||
filterPanel: { type: Object, default: undefined },
|
filterPanel: { type: Object, default: undefined },
|
||||||
idInWhere: { type: Boolean, default: false },
|
|
||||||
searchDataKey: { type: String, default: undefined },
|
searchDataKey: { type: String, default: undefined },
|
||||||
searchbarProps: { type: Object, default: undefined },
|
searchbarProps: { type: Object, default: undefined },
|
||||||
redirectOnError: { type: Boolean, default: false },
|
redirectOnError: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchRightDataKey = computed(() => {
|
|
||||||
if (!props.searchDataKey) return route.name;
|
|
||||||
return props.searchDataKey;
|
|
||||||
});
|
|
||||||
|
|
||||||
const arrayData = useArrayData(props.dataKey, {
|
const arrayData = useArrayData(props.dataKey, {
|
||||||
url: props.url,
|
url: props.url,
|
||||||
userFilter: props.filter,
|
userFilter: props.filter,
|
||||||
oneRecord: true,
|
oneRecord: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onBeforeRouteLeave(() => {
|
||||||
|
stateStore.cardDescriptorChangeValue(null);
|
||||||
|
});
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
|
stateStore.cardDescriptorChangeValue(props.descriptor);
|
||||||
|
|
||||||
|
const route = router.currentRoute.value;
|
||||||
try {
|
try {
|
||||||
await fetch(route.params.id);
|
await fetch(route.params.id);
|
||||||
} catch {
|
} catch {
|
||||||
const { matched: matches } = router.currentRoute.value;
|
const { matched: matches } = route;
|
||||||
const { path } = matches.at(-1);
|
const { path } = matches.at(-1);
|
||||||
router.push({ path: path.replace(/:id.*/, '') });
|
router.push({ path: path.replace(/:id.*/, '') });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeRouteUpdate(async (to, from) => {
|
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;
|
const id = to.params.id;
|
||||||
if (id !== from.params.id) await fetch(id, true);
|
if (id !== from.params.id) await fetch(id, true);
|
||||||
});
|
});
|
||||||
|
@ -56,34 +62,13 @@ async function fetch(id, append = false) {
|
||||||
else arrayData.store.url = props.url.replace(regex, `/${id}`);
|
else arrayData.store.url = props.url.replace(regex, `/${id}`);
|
||||||
await arrayData.fetch({ append, updateRouter: false });
|
await arrayData.fetch({ append, updateRouter: false });
|
||||||
}
|
}
|
||||||
|
function hasRouteParam(params, valueToCheck = ':addressId') {
|
||||||
|
return Object.values(params).includes(valueToCheck);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QDrawer
|
<VnSubToolbar />
|
||||||
v-model="stateStore.leftDrawer"
|
<div :class="[useCardSize(), $attrs.class]">
|
||||||
show-if-above
|
<RouterView :key="$route.path" />
|
||||||
:width="256"
|
</div>
|
||||||
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>
|
</template>
|
||||||
|
|
|
@ -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>
|
|
|
@ -27,7 +27,11 @@ const checkboxModel = computed({
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<QCheckbox v-bind="$attrs" v-model="checkboxModel" />
|
<QCheckbox
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-model="checkboxModel"
|
||||||
|
:data-cy="$attrs['data-cy'] ?? `vnCheckbox${$attrs['label'] ?? ''}`"
|
||||||
|
/>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="info"
|
v-if="info"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
|
|
@ -177,6 +177,7 @@ function addDefaultData(data) {
|
||||||
name="vn:attach"
|
name="vn:attach"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
@click="inputFileRef.pickFiles()"
|
@click="inputFileRef.pickFiles()"
|
||||||
|
data-cy="attachFile"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('globals.selectFile') }}</QTooltip>
|
<QTooltip>{{ t('globals.selectFile') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
|
|
|
@ -389,10 +389,7 @@ defineExpose({
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</QTable>
|
</QTable>
|
||||||
<div
|
<div v-else class="info-row q-pa-md text-center">
|
||||||
v-else
|
|
||||||
class="info-row q-pa-md text-center"
|
|
||||||
>
|
|
||||||
<h5>
|
<h5>
|
||||||
{{ t('No data to display') }}
|
{{ t('No data to display') }}
|
||||||
</h5>
|
</h5>
|
||||||
|
@ -416,6 +413,7 @@ defineExpose({
|
||||||
v-shortcut
|
v-shortcut
|
||||||
@click="showFormDialog()"
|
@click="showFormDialog()"
|
||||||
class="fill-icon"
|
class="fill-icon"
|
||||||
|
data-cy="addButton"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('Upload file') }}
|
{{ t('Upload file') }}
|
||||||
|
|
|
@ -83,7 +83,7 @@ const mixinRules = [
|
||||||
requiredFieldRule,
|
requiredFieldRule,
|
||||||
...($attrs.rules ?? []),
|
...($attrs.rules ?? []),
|
||||||
(val) => {
|
(val) => {
|
||||||
const { maxlength } = vnInputRef.value;
|
const maxlength = $props.maxlength;
|
||||||
if (maxlength && +val.length > maxlength)
|
if (maxlength && +val.length > maxlength)
|
||||||
return t(`maxLength`, { value: maxlength });
|
return t(`maxLength`, { value: maxlength });
|
||||||
const { min, max } = vnInputRef.value.$attrs;
|
const { min, max } = vnInputRef.value.$attrs;
|
||||||
|
@ -108,7 +108,7 @@ const handleInsertMode = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const input = e.target;
|
const input = e.target;
|
||||||
const cursorPos = input.selectionStart;
|
const cursorPos = input.selectionStart;
|
||||||
const { maxlength } = vnInputRef.value;
|
const maxlength = $props.maxlength;
|
||||||
let currentValue = value.value;
|
let currentValue = value.value;
|
||||||
if (!currentValue) currentValue = e.key;
|
if (!currentValue) currentValue = e.key;
|
||||||
const newValue = e.key;
|
const newValue = e.key;
|
||||||
|
@ -143,7 +143,7 @@ const handleUppercase = () => {
|
||||||
:rules="mixinRules"
|
:rules="mixinRules"
|
||||||
:lazy-rules="true"
|
:lazy-rules="true"
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
|
:data-cy="($attrs['data-cy'] ?? $attrs.label) + '_input'"
|
||||||
>
|
>
|
||||||
<template #prepend v-if="$slots.prepend">
|
<template #prepend v-if="$slots.prepend">
|
||||||
<slot name="prepend" />
|
<slot name="prepend" />
|
||||||
|
|
|
@ -107,7 +107,7 @@ const manageDate = (date) => {
|
||||||
@click="isPopupOpen = !isPopupOpen"
|
@click="isPopupOpen = !isPopupOpen"
|
||||||
@keydown="isPopupOpen = false"
|
@keydown="isPopupOpen = false"
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
:data-cy="$attrs.dataCy ?? $attrs.label + '_inputDate'"
|
:data-cy="($attrs['data-cy'] ?? $attrs.label) + '_inputDate'"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { useColor } from 'src/composables/useColor';
|
||||||
import { useCapitalize } from 'src/composables/useCapitalize';
|
import { useCapitalize } from 'src/composables/useCapitalize';
|
||||||
import { useValidator } from 'src/composables/useValidator';
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
import VnAvatar from '../ui/VnAvatar.vue';
|
import VnAvatar from '../ui/VnAvatar.vue';
|
||||||
import VnJsonValue from '../common/VnJsonValue.vue';
|
import VnLogValue from './VnLogValue.vue';
|
||||||
import FetchData from '../FetchData.vue';
|
import FetchData from '../FetchData.vue';
|
||||||
import VnSelect from './VnSelect.vue';
|
import VnSelect from './VnSelect.vue';
|
||||||
import VnUserLink from '../ui/VnUserLink.vue';
|
import VnUserLink from '../ui/VnUserLink.vue';
|
||||||
|
@ -560,10 +560,11 @@ watch(
|
||||||
value.nameI18n
|
value.nameI18n
|
||||||
}}:
|
}}:
|
||||||
</span>
|
</span>
|
||||||
<VnJsonValue
|
<VnLogValue
|
||||||
:value="
|
:value="
|
||||||
value.val.val
|
value.val.val
|
||||||
"
|
"
|
||||||
|
:name="value.name"
|
||||||
/>
|
/>
|
||||||
</QItem>
|
</QItem>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
|
@ -614,7 +615,11 @@ watch(
|
||||||
>
|
>
|
||||||
{{ prop.nameI18n }}:
|
{{ prop.nameI18n }}:
|
||||||
</span>
|
</span>
|
||||||
<VnJsonValue :value="prop.val.val" />
|
<VnLogValue
|
||||||
|
:value="prop.val.val"
|
||||||
|
:name="prop.name"
|
||||||
|
/>
|
||||||
|
<VnIconLink />
|
||||||
<span
|
<span
|
||||||
v-if="
|
v-if="
|
||||||
propIndex <
|
propIndex <
|
||||||
|
@ -642,8 +647,9 @@ watch(
|
||||||
{{ prop.nameI18n }}:
|
{{ prop.nameI18n }}:
|
||||||
</span>
|
</span>
|
||||||
<span v-if="log.action == 'update'">
|
<span v-if="log.action == 'update'">
|
||||||
<VnJsonValue
|
<VnLogValue
|
||||||
:value="prop.old.val"
|
:value="prop.old.val"
|
||||||
|
:name="prop.name"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="prop.old.id"
|
v-if="prop.old.id"
|
||||||
|
@ -652,8 +658,9 @@ watch(
|
||||||
#{{ prop.old.id }}
|
#{{ prop.old.id }}
|
||||||
</span>
|
</span>
|
||||||
→
|
→
|
||||||
<VnJsonValue
|
<VnLogValue
|
||||||
:value="prop.val.val"
|
:value="prop.val.val"
|
||||||
|
:name="prop.name"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="prop.val.id"
|
v-if="prop.val.id"
|
||||||
|
@ -663,8 +670,9 @@ watch(
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-else="prop.old.val">
|
<span v-else="prop.old.val">
|
||||||
<VnJsonValue
|
<VnLogValue
|
||||||
:value="prop.val.val"
|
:value="prop.val.val"
|
||||||
|
:name="prop.name"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="prop.old.id"
|
v-if="prop.old.id"
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script setup>
|
||||||
|
import { useDescriptorStore } from 'src/stores/useDescriptorStore';
|
||||||
|
import VnJsonValue from './VnJsonValue.vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
const descriptorStore = useDescriptorStore();
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
name: { type: [String], default: undefined },
|
||||||
|
});
|
||||||
|
|
||||||
|
const descriptor = computed(() => descriptorStore.has($props.name));
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VnJsonValue v-bind="$attrs" />
|
||||||
|
<QIcon
|
||||||
|
name="launch"
|
||||||
|
class="link"
|
||||||
|
v-if="$attrs.value && descriptor"
|
||||||
|
:data-cy="'iconLaunch-' + $props.name"
|
||||||
|
/>
|
||||||
|
<component :is="descriptor" :id="$attrs.value" v-if="$attrs.value && descriptor" />
|
||||||
|
</template>
|
|
@ -302,6 +302,8 @@ defineExpose({ opts: myOptions, vnSelectRef });
|
||||||
|
|
||||||
function handleKeyDown(event) {
|
function handleKeyDown(event) {
|
||||||
if (event.key === 'Tab' && !event.shiftKey) {
|
if (event.key === 'Tab' && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
const inputValue = vnSelectRef.value?.inputValue;
|
const inputValue = vnSelectRef.value?.inputValue;
|
||||||
|
|
||||||
if (inputValue) {
|
if (inputValue) {
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
||||||
|
});
|
|
@ -5,7 +5,7 @@ import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useClipboard } from 'src/composables/useClipboard';
|
import { useClipboard } from 'src/composables/useClipboard';
|
||||||
import VnMoreOptions from './VnMoreOptions.vue';
|
import VnMoreOptions from './VnMoreOptions.vue';
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ const $props = defineProps({
|
||||||
|
|
||||||
const state = useState();
|
const state = useState();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { copyText } = useClipboard();
|
const { copyText } = useClipboard();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
|
@ -50,6 +51,9 @@ let store;
|
||||||
let entity;
|
let entity;
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const isSameDataKey = computed(() => $props.dataKey === route.meta.moduleName);
|
const isSameDataKey = computed(() => $props.dataKey === route.meta.moduleName);
|
||||||
|
const DESCRIPTOR_PROXY = 'DescriptorProxy';
|
||||||
|
const moduleName = ref();
|
||||||
|
const isSameModuleName = route.matched[1].meta.moduleName !== moduleName.value;
|
||||||
defineExpose({ getData });
|
defineExpose({ getData });
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
|
@ -76,15 +80,18 @@ onBeforeMount(async () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const routeName = computed(() => {
|
function getName() {
|
||||||
const DESCRIPTOR_PROXY = 'DescriptorProxy';
|
|
||||||
|
|
||||||
let name = $props.dataKey;
|
let name = $props.dataKey;
|
||||||
if ($props.dataKey.includes(DESCRIPTOR_PROXY)) {
|
if ($props.dataKey.includes(DESCRIPTOR_PROXY)) {
|
||||||
name = name.split(DESCRIPTOR_PROXY)[0];
|
name = name.split(DESCRIPTOR_PROXY)[0];
|
||||||
}
|
}
|
||||||
return `${name}Summary`;
|
return name;
|
||||||
|
}
|
||||||
|
const routeName = computed(() => {
|
||||||
|
let routeName = getName();
|
||||||
|
return `${routeName}Summary`;
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getData() {
|
async function getData() {
|
||||||
store.url = $props.url;
|
store.url = $props.url;
|
||||||
store.filter = $props.filter ?? {};
|
store.filter = $props.filter ?? {};
|
||||||
|
@ -120,20 +127,35 @@ function copyIdText(id) {
|
||||||
|
|
||||||
const emit = defineEmits(['onFetch']);
|
const emit = defineEmits(['onFetch']);
|
||||||
|
|
||||||
const iconModule = computed(() => route.matched[1].meta.icon);
|
const iconModule = computed(() => {
|
||||||
const toModule = computed(() =>
|
moduleName.value = getName();
|
||||||
route.matched[1].path.split('/').length > 2
|
if (isSameModuleName) {
|
||||||
? route.matched[1].redirect
|
return router.options.routes[1].children.find((r) => r.name === moduleName.value)
|
||||||
: route.matched[1].children[0].redirect,
|
?.meta?.icon;
|
||||||
);
|
} else {
|
||||||
|
return route.matched[1].meta.icon;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const toModule = computed(() => {
|
||||||
|
moduleName.value = getName();
|
||||||
|
if (isSameModuleName) {
|
||||||
|
return router.options.routes[1].children.find((r) => r.name === moduleName.value)
|
||||||
|
?.children[0]?.redirect;
|
||||||
|
} else {
|
||||||
|
return route.matched[1].path.split('/').length > 2
|
||||||
|
? route.matched[1].redirect
|
||||||
|
: route.matched[1].children[0].redirect;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="descriptor">
|
<div class="descriptor" data-cy="cardDescriptor">
|
||||||
<template v-if="entity && !isLoading">
|
<template v-if="entity && !isLoading">
|
||||||
<div class="header bg-primary q-pa-sm justify-between">
|
<div class="header bg-primary q-pa-sm justify-between">
|
||||||
<slot name="header-extra-action"
|
<slot name="header-extra-action">
|
||||||
><QBtn
|
<QBtn
|
||||||
round
|
round
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
|
@ -141,13 +163,13 @@ const toModule = computed(() =>
|
||||||
:icon="iconModule"
|
:icon="iconModule"
|
||||||
color="white"
|
color="white"
|
||||||
class="link"
|
class="link"
|
||||||
:to="$attrs['to-module'] ?? toModule"
|
:to="toModule"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('globals.goToModuleIndex') }}
|
{{ t('globals.goToModuleIndex') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QBtn></slot
|
</QBtn>
|
||||||
>
|
</slot>
|
||||||
<QBtn
|
<QBtn
|
||||||
@click.stop="viewSummary(entity.id, $props.summary, $props.width)"
|
@click.stop="viewSummary(entity.id, $props.summary, $props.width)"
|
||||||
round
|
round
|
||||||
|
@ -158,6 +180,7 @@ const toModule = computed(() =>
|
||||||
color="white"
|
color="white"
|
||||||
class="link"
|
class="link"
|
||||||
v-if="summary"
|
v-if="summary"
|
||||||
|
data-cy="openSummaryBtn"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('components.smartCard.openSummary') }}
|
{{ t('components.smartCard.openSummary') }}
|
||||||
|
@ -172,6 +195,7 @@ const toModule = computed(() =>
|
||||||
icon="launch"
|
icon="launch"
|
||||||
round
|
round
|
||||||
size="md"
|
size="md"
|
||||||
|
data-cy="goToSummaryBtn"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('components.cardDescriptor.summary') }}
|
{{ t('components.cardDescriptor.summary') }}
|
||||||
|
@ -189,18 +213,27 @@ const toModule = computed(() =>
|
||||||
<QList dense>
|
<QList dense>
|
||||||
<QItemLabel header class="ellipsis text-h5" :lines="1">
|
<QItemLabel header class="ellipsis text-h5" :lines="1">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span v-if="$props.title" :title="getValueFromPath(title)">
|
<span
|
||||||
|
v-if="$props.title"
|
||||||
|
:title="getValueFromPath(title)"
|
||||||
|
:data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_title`"
|
||||||
|
>
|
||||||
{{ getValueFromPath(title) ?? $props.title }}
|
{{ getValueFromPath(title) ?? $props.title }}
|
||||||
</span>
|
</span>
|
||||||
<slot v-else name="description" :entity="entity">
|
<slot v-else name="description" :entity="entity">
|
||||||
<span :title="entity.name">
|
<span
|
||||||
{{ entity.name }}
|
:title="entity.name"
|
||||||
</span>
|
:data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_description`"
|
||||||
|
v-text="entity.name"
|
||||||
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemLabel class="subtitle">
|
<QItemLabel
|
||||||
|
class="subtitle"
|
||||||
|
:data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_subtitle`"
|
||||||
|
>
|
||||||
#{{ getValueFromPath(subtitle) ?? entity.id }}
|
#{{ getValueFromPath(subtitle) ?? entity.id }}
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
@ -218,7 +251,10 @@ const toModule = computed(() =>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</QItem>
|
</QItem>
|
||||||
</QList>
|
</QList>
|
||||||
<div class="list-box q-mt-xs">
|
<div
|
||||||
|
class="list-box q-mt-xs"
|
||||||
|
:data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_listbox`"
|
||||||
|
>
|
||||||
<slot name="body" :entity="entity" />
|
<slot name="body" :entity="entity" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -230,7 +266,6 @@ const toModule = computed(() =>
|
||||||
</div>
|
</div>
|
||||||
<slot name="after" />
|
<slot name="after" />
|
||||||
</template>
|
</template>
|
||||||
<!-- Skeleton -->
|
|
||||||
<SkeletonDescriptor v-if="!entity || isLoading" />
|
<SkeletonDescriptor v-if="!entity || isLoading" />
|
||||||
</div>
|
</div>
|
||||||
<QInnerLoading
|
<QInnerLoading
|
||||||
|
|
|
@ -81,6 +81,7 @@ async function fetch() {
|
||||||
name: `${moduleName ?? route.meta.moduleName}Summary`,
|
name: `${moduleName ?? route.meta.moduleName}Summary`,
|
||||||
params: { id: entityId || entity.id },
|
params: { id: entityId || entity.id },
|
||||||
}"
|
}"
|
||||||
|
data-cy="goToSummaryBtn"
|
||||||
>
|
>
|
||||||
<QIcon name="open_in_new" color="white" size="sm" />
|
<QIcon name="open_in_new" color="white" size="sm" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
|
@ -132,7 +132,8 @@ const card = toRef(props, 'item');
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 192px;
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ const $props = defineProps({
|
||||||
default: 'table',
|
default: 'table',
|
||||||
},
|
},
|
||||||
redirect: {
|
redirect: {
|
||||||
type: Boolean,
|
type: [String, Boolean],
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
arrayData: {
|
arrayData: {
|
||||||
|
@ -249,7 +249,7 @@ const getLocale = (label) => {
|
||||||
:key="chip.label"
|
:key="chip.label"
|
||||||
:removable="!unremovableParams?.includes(chip.label)"
|
:removable="!unremovableParams?.includes(chip.label)"
|
||||||
@remove="remove(chip.label)"
|
@remove="remove(chip.label)"
|
||||||
data-cy="vnFilterPanelChip"
|
:data-cy="`vnFilterPanelChip_${chip.label}`"
|
||||||
>
|
>
|
||||||
<slot
|
<slot
|
||||||
name="tags"
|
name="tags"
|
||||||
|
|
|
@ -28,7 +28,7 @@ function copyValueText() {
|
||||||
const val = computed(() => $props.value);
|
const val = computed(() => $props.value);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="vn-label-value">
|
<div class="vn-label-value" :data-cy="`${$attrs['data-cy'] ?? 'vnLv'}${label ?? ''}`">
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
v-if="typeof value === 'boolean'"
|
v-if="typeof value === 'boolean'"
|
||||||
v-model="val"
|
v-model="val"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{{ $t('components.cardDescriptor.moreOptions') }}
|
{{ $t('components.cardDescriptor.moreOptions') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
<QMenu ref="menuRef" data-cy="descriptor-more-opts-menu">
|
<QMenu ref="menuRef" data-cy="descriptor-more-opts-menu">
|
||||||
<QList>
|
<QList data-cy="descriptor-more-opts_list">
|
||||||
<slot name="menu" :menu-ref="$refs.menuRef" />
|
<slot name="menu" :menu-ref="$refs.menuRef" />
|
||||||
</QList>
|
</QList>
|
||||||
</QMenu>
|
</QMenu>
|
||||||
|
|
|
@ -18,20 +18,16 @@ import VnInput from 'components/common/VnInput.vue';
|
||||||
|
|
||||||
const emit = defineEmits(['onFetch']);
|
const emit = defineEmits(['onFetch']);
|
||||||
|
|
||||||
const originalAttrs = useAttrs();
|
const $attrs = useAttrs();
|
||||||
|
|
||||||
const $attrs = computed(() => {
|
|
||||||
const { style, ...rest } = originalAttrs;
|
|
||||||
return rest;
|
|
||||||
});
|
|
||||||
|
|
||||||
const isRequired = computed(() => {
|
const isRequired = computed(() => {
|
||||||
return Object.keys($attrs).includes('required')
|
return Object.keys($attrs).includes('required');
|
||||||
});
|
});
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
url: { type: String, default: null },
|
url: { type: String, default: null },
|
||||||
saveUrl: {type: String, default: null},
|
saveUrl: { type: String, default: null },
|
||||||
|
userFilter: { type: Object, default: () => {} },
|
||||||
filter: { type: Object, default: () => {} },
|
filter: { type: Object, default: () => {} },
|
||||||
body: { type: Object, default: () => {} },
|
body: { type: Object, default: () => {} },
|
||||||
addNote: { type: Boolean, default: false },
|
addNote: { type: Boolean, default: false },
|
||||||
|
@ -65,7 +61,7 @@ async function insert() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmAndUpdate() {
|
function confirmAndUpdate() {
|
||||||
if(!newNote.text && originalText)
|
if (!newNote.text && originalText)
|
||||||
quasar
|
quasar
|
||||||
.dialog({
|
.dialog({
|
||||||
component: VnConfirm,
|
component: VnConfirm,
|
||||||
|
@ -88,11 +84,17 @@ async function update() {
|
||||||
...body,
|
...body,
|
||||||
...{ notes: newNote.text },
|
...{ notes: newNote.text },
|
||||||
};
|
};
|
||||||
await axios.patch(`${$props.saveUrl ?? `${$props.url}/${$props.body.workerFk}`}`, newBody);
|
await axios.patch(
|
||||||
|
`${$props.saveUrl ?? `${$props.url}/${$props.body.workerFk}`}`,
|
||||||
|
newBody,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeRouteLeave((to, from, next) => {
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
if ((newNote.text && !$props.justInput) || (newNote.text !== originalText) && $props.justInput)
|
if (
|
||||||
|
(newNote.text && !$props.justInput) ||
|
||||||
|
(newNote.text !== originalText && $props.justInput)
|
||||||
|
)
|
||||||
quasar.dialog({
|
quasar.dialog({
|
||||||
component: VnConfirm,
|
component: VnConfirm,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
|
@ -104,12 +106,11 @@ onBeforeRouteLeave((to, from, next) => {
|
||||||
else next();
|
else next();
|
||||||
});
|
});
|
||||||
|
|
||||||
function fetchData([ data ]) {
|
function fetchData([data]) {
|
||||||
newNote.text = data?.notes;
|
newNote.text = data?.notes;
|
||||||
originalText = data?.notes;
|
originalText = data?.notes;
|
||||||
emit('onFetch', data);
|
emit('onFetch', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -126,8 +127,8 @@ function fetchData([ data ]) {
|
||||||
@on-fetch="fetchData"
|
@on-fetch="fetchData"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<QCard
|
<QCard
|
||||||
class="q-pa-xs q-mb-lg full-width"
|
class="q-pa-xs q-mb-lg full-width"
|
||||||
:class="{ 'just-input': $props.justInput }"
|
:class="{ 'just-input': $props.justInput }"
|
||||||
v-if="$props.addNote || $props.justInput"
|
v-if="$props.addNote || $props.justInput"
|
||||||
>
|
>
|
||||||
|
@ -179,12 +180,13 @@ function fetchData([ data ]) {
|
||||||
:url="$props.url"
|
:url="$props.url"
|
||||||
order="created DESC"
|
order="created DESC"
|
||||||
:limit="0"
|
:limit="0"
|
||||||
:user-filter="$props.filter"
|
:user-filter="userFilter"
|
||||||
|
:filter="filter"
|
||||||
auto-load
|
auto-load
|
||||||
ref="vnPaginateRef"
|
ref="vnPaginateRef"
|
||||||
class="show"
|
class="show"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
search-url="notes"
|
:search-url="false"
|
||||||
@on-fetch="
|
@on-fetch="
|
||||||
newNote.text = '';
|
newNote.text = '';
|
||||||
newNote.observationTypeFk = null;
|
newNote.observationTypeFk = null;
|
||||||
|
@ -218,7 +220,7 @@ function fetchData([ data ]) {
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
observationTypes.find(
|
observationTypes.find(
|
||||||
(ot) => ot.id === note.observationTypeFk
|
(ot) => ot.id === note.observationTypeFk,
|
||||||
)?.description
|
)?.description
|
||||||
}}
|
}}
|
||||||
</QBadge>
|
</QBadge>
|
||||||
|
|
|
@ -33,6 +33,10 @@ const props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
userFilter: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
filter: {
|
filter: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
|
|
|
@ -9,6 +9,8 @@ export function getColAlign(col) {
|
||||||
case 'number':
|
case 'number':
|
||||||
align = 'right';
|
align = 'right';
|
||||||
break;
|
break;
|
||||||
|
case 'time':
|
||||||
|
case 'date':
|
||||||
case 'checkbox':
|
case 'checkbox':
|
||||||
align = 'center';
|
align = 'center';
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -148,8 +148,7 @@ export function useArrayData(key, userOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function applyFilter({ filter, params }, fetchOptions = {}) {
|
async function applyFilter({ filter, params }, fetchOptions = {}) {
|
||||||
if (filter) store.userFilter = filter;
|
if (filter) store.filter = filter;
|
||||||
store.filter = {};
|
|
||||||
if (params) store.userParams = { ...params };
|
if (params) store.userParams = { ...params };
|
||||||
|
|
||||||
const response = await fetch(fetchOptions);
|
const response = await fetch(fetchOptions);
|
||||||
|
@ -245,7 +244,7 @@ export function useArrayData(key, userOptions) {
|
||||||
async function loadMore() {
|
async function loadMore() {
|
||||||
if (!store.hasMoreData) return;
|
if (!store.hasMoreData) return;
|
||||||
|
|
||||||
store.skip = store.limit * store.page;
|
store.skip = (store?.filter?.limit ?? store.limit) * store.page;
|
||||||
store.page += 1;
|
store.page += 1;
|
||||||
|
|
||||||
await fetch({ append: true });
|
await fetch({ append: true });
|
||||||
|
|
|
@ -15,6 +15,7 @@ body.body--light {
|
||||||
--vn-empty-tag: #acacac;
|
--vn-empty-tag: #acacac;
|
||||||
--vn-black-text-color: black;
|
--vn-black-text-color: black;
|
||||||
--vn-text-color-contrast: white;
|
--vn-text-color-contrast: white;
|
||||||
|
--vn-link-color: #1e90ff;
|
||||||
|
|
||||||
background-color: var(--vn-page-color);
|
background-color: var(--vn-page-color);
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ body.body--dark {
|
||||||
--vn-empty-tag: #2d2d2d;
|
--vn-empty-tag: #2d2d2d;
|
||||||
--vn-black-text-color: black;
|
--vn-black-text-color: black;
|
||||||
--vn-text-color-contrast: black;
|
--vn-text-color-contrast: black;
|
||||||
|
--vn-link-color: #66bfff;
|
||||||
|
|
||||||
background-color: var(--vn-page-color);
|
background-color: var(--vn-page-color);
|
||||||
|
|
||||||
|
@ -49,7 +51,7 @@ a {
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
color: $color-link;
|
color: var(--vn-link-color);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&--white {
|
&--white {
|
||||||
|
@ -58,14 +60,14 @@ a {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-color-link {
|
.tx-color-link {
|
||||||
color: $color-link !important;
|
color: var(--vn-link-color) !important;
|
||||||
}
|
}
|
||||||
.tx-color-font {
|
.tx-color-font {
|
||||||
color: $color-link !important;
|
color: var(--vn-link-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-link {
|
.header-link {
|
||||||
color: $color-link !important;
|
color: var(--vn-link-color) !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-bottom: solid $primary;
|
border-bottom: solid $primary;
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
|
@ -337,5 +339,5 @@ input::-webkit-inner-spin-button {
|
||||||
}
|
}
|
||||||
|
|
||||||
.containerShrinked {
|
.containerShrinked {
|
||||||
width: 80%;
|
width: 70%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ $alert: $negative;
|
||||||
$white: #fff;
|
$white: #fff;
|
||||||
$dark: #3d3d3d;
|
$dark: #3d3d3d;
|
||||||
// custom
|
// custom
|
||||||
$color-link: #66bfff;
|
|
||||||
$color-spacer-light: #a3a3a31f;
|
$color-spacer-light: #a3a3a31f;
|
||||||
$color-spacer: #7979794d;
|
$color-spacer: #7979794d;
|
||||||
$border-thin-light: 1px solid $color-spacer-light;
|
$border-thin-light: 1px solid $color-spacer-light;
|
||||||
|
|
|
@ -99,7 +99,6 @@ globals:
|
||||||
file: File
|
file: File
|
||||||
selectFile: Select a file
|
selectFile: Select a file
|
||||||
copyClipboard: Copy on clipboard
|
copyClipboard: Copy on clipboard
|
||||||
salesPerson: SalesPerson
|
|
||||||
send: Send
|
send: Send
|
||||||
code: Code
|
code: Code
|
||||||
since: Since
|
since: Since
|
||||||
|
@ -158,7 +157,9 @@ globals:
|
||||||
changeState: Change state
|
changeState: Change state
|
||||||
raid: 'Raid {daysInForward} days'
|
raid: 'Raid {daysInForward} days'
|
||||||
isVies: Vies
|
isVies: Vies
|
||||||
|
department: Department
|
||||||
noData: No data available
|
noData: No data available
|
||||||
|
vehicle: Vehicle
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Login
|
logIn: Login
|
||||||
addressEdit: Update address
|
addressEdit: Update address
|
||||||
|
@ -346,7 +347,6 @@ globals:
|
||||||
params:
|
params:
|
||||||
description: Description
|
description: Description
|
||||||
clientFk: Client id
|
clientFk: Client id
|
||||||
salesPersonFk: Sales person
|
|
||||||
warehouseFk: Warehouse
|
warehouseFk: Warehouse
|
||||||
provinceFk: Province
|
provinceFk: Province
|
||||||
stateFk: State
|
stateFk: State
|
||||||
|
@ -369,6 +369,7 @@ globals:
|
||||||
countryFk: Country
|
countryFk: Country
|
||||||
countryCodeFk: Country
|
countryCodeFk: Country
|
||||||
companyFk: Company
|
companyFk: Company
|
||||||
|
nickname: Alias
|
||||||
model: Model
|
model: Model
|
||||||
fuel: Fuel
|
fuel: Fuel
|
||||||
active: Active
|
active: Active
|
||||||
|
@ -530,6 +531,7 @@ ticket:
|
||||||
customerCard: Customer card
|
customerCard: Customer card
|
||||||
ticketList: Ticket List
|
ticketList: Ticket List
|
||||||
newOrder: New Order
|
newOrder: New Order
|
||||||
|
ticketClaimed: Claimed ticket
|
||||||
boxing:
|
boxing:
|
||||||
expedition: Expedition
|
expedition: Expedition
|
||||||
created: Created
|
created: Created
|
||||||
|
@ -602,7 +604,6 @@ worker:
|
||||||
balance: Balance
|
balance: Balance
|
||||||
medical: Medical
|
medical: Medical
|
||||||
list:
|
list:
|
||||||
department: Department
|
|
||||||
schedule: Schedule
|
schedule: Schedule
|
||||||
newWorker: New worker
|
newWorker: New worker
|
||||||
summary:
|
summary:
|
||||||
|
@ -861,7 +862,6 @@ components:
|
||||||
mine: For me
|
mine: For me
|
||||||
hasMinPrice: Minimum price
|
hasMinPrice: Minimum price
|
||||||
# LatestBuysFilter
|
# LatestBuysFilter
|
||||||
salesPersonFk: Buyer
|
|
||||||
supplierFk: Supplier
|
supplierFk: Supplier
|
||||||
from: From
|
from: From
|
||||||
to: To
|
to: To
|
||||||
|
|
|
@ -103,7 +103,6 @@ globals:
|
||||||
file: Fichero
|
file: Fichero
|
||||||
selectFile: Seleccione un fichero
|
selectFile: Seleccione un fichero
|
||||||
copyClipboard: Copiar en portapapeles
|
copyClipboard: Copiar en portapapeles
|
||||||
salesPerson: Comercial
|
|
||||||
send: Enviar
|
send: Enviar
|
||||||
code: Código
|
code: Código
|
||||||
since: Desde
|
since: Desde
|
||||||
|
@ -163,6 +162,8 @@ globals:
|
||||||
raid: 'Redada {daysInForward} días'
|
raid: 'Redada {daysInForward} días'
|
||||||
isVies: Vies
|
isVies: Vies
|
||||||
noData: Datos no disponibles
|
noData: Datos no disponibles
|
||||||
|
department: Departamento
|
||||||
|
vehicle: Vehículo
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Inicio de sesión
|
logIn: Inicio de sesión
|
||||||
addressEdit: Modificar consignatario
|
addressEdit: Modificar consignatario
|
||||||
|
@ -349,7 +350,6 @@ globals:
|
||||||
params:
|
params:
|
||||||
description: Descripción
|
description: Descripción
|
||||||
clientFk: Id cliente
|
clientFk: Id cliente
|
||||||
salesPersonFk: Comercial
|
|
||||||
warehouseFk: Almacén
|
warehouseFk: Almacén
|
||||||
provinceFk: Provincia
|
provinceFk: Provincia
|
||||||
stateFk: Estado
|
stateFk: Estado
|
||||||
|
@ -370,6 +370,7 @@ globals:
|
||||||
countryFk: País
|
countryFk: País
|
||||||
countryCodeFk: País
|
countryCodeFk: País
|
||||||
companyFk: Empresa
|
companyFk: Empresa
|
||||||
|
nickname: Alias
|
||||||
errors:
|
errors:
|
||||||
statusUnauthorized: Acceso denegado
|
statusUnauthorized: Acceso denegado
|
||||||
statusInternalServerError: Ha ocurrido un error interno del servidor
|
statusInternalServerError: Ha ocurrido un error interno del servidor
|
||||||
|
@ -530,13 +531,13 @@ ticket:
|
||||||
state: Estado
|
state: Estado
|
||||||
shipped: Enviado
|
shipped: Enviado
|
||||||
landed: Entregado
|
landed: Entregado
|
||||||
salesPerson: Comercial
|
|
||||||
total: Total
|
total: Total
|
||||||
card:
|
card:
|
||||||
customerId: ID cliente
|
customerId: ID cliente
|
||||||
customerCard: Ficha del cliente
|
customerCard: Ficha del cliente
|
||||||
ticketList: Listado de tickets
|
ticketList: Listado de tickets
|
||||||
newOrder: Nuevo pedido
|
newOrder: Nuevo pedido
|
||||||
|
ticketClaimed: Ticket reclamado
|
||||||
boxing:
|
boxing:
|
||||||
expedition: Expedición
|
expedition: Expedición
|
||||||
created: Creado
|
created: Creado
|
||||||
|
@ -621,8 +622,6 @@ invoiceOut:
|
||||||
errors:
|
errors:
|
||||||
downloadCsvFailed: Error al descargar CSV
|
downloadCsvFailed: Error al descargar CSV
|
||||||
order:
|
order:
|
||||||
field:
|
|
||||||
salesPersonFk: Comercial
|
|
||||||
form:
|
form:
|
||||||
clientFk: Cliente
|
clientFk: Cliente
|
||||||
addressFk: Dirección
|
addressFk: Dirección
|
||||||
|
@ -690,7 +689,6 @@ worker:
|
||||||
formation: Formación
|
formation: Formación
|
||||||
medical: Mutua
|
medical: Mutua
|
||||||
list:
|
list:
|
||||||
department: Departamento
|
|
||||||
schedule: Horario
|
schedule: Horario
|
||||||
newWorker: Nuevo trabajador
|
newWorker: Nuevo trabajador
|
||||||
summary:
|
summary:
|
||||||
|
@ -948,7 +946,6 @@ components:
|
||||||
hasMinPrice: Precio mínimo
|
hasMinPrice: Precio mínimo
|
||||||
wareHouseFk: Almacén
|
wareHouseFk: Almacén
|
||||||
# LatestBuysFilter
|
# LatestBuysFilter
|
||||||
salesPersonFk: Comprador
|
|
||||||
supplierFk: Proveedor
|
supplierFk: Proveedor
|
||||||
visible: Visible
|
visible: Visible
|
||||||
active: Activo
|
active: Activo
|
||||||
|
|
|
@ -149,14 +149,12 @@ const columns = computed(() => [
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
>
|
>
|
||||||
<template #more-create-dialog="{ data }">
|
<template #more-create-dialog="{ data }">
|
||||||
<QCardSection>
|
|
||||||
<VnInputPassword
|
<VnInputPassword
|
||||||
:label="t('Password')"
|
:label="t('Password')"
|
||||||
v-model="data.password"
|
v-model="data.password"
|
||||||
:required="true"
|
:required="true"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
/>
|
/>
|
||||||
</QCardSection>
|
|
||||||
</template>
|
</template>
|
||||||
</VnTable>
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import VnCardBeta from 'components/common/VnCardBeta.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import AliasDescriptor from './AliasDescriptor.vue';
|
import AliasDescriptor from './AliasDescriptor.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VnCardBeta
|
<VnCard
|
||||||
data-key="Alias"
|
data-key="Alias"
|
||||||
url="MailAliases"
|
url="MailAliases"
|
||||||
:descriptor="AliasDescriptor"
|
:descriptor="AliasDescriptor"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import CardSummary from 'components/ui/CardSummary.vue';
|
import CardSummary from 'components/ui/CardSummary.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
|
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -27,13 +28,10 @@ const entityId = computed(() => $props.id || route.params.id);
|
||||||
<template #body="{ entity: alias }">
|
<template #body="{ entity: alias }">
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<QCardSection class="q-pa-none">
|
<QCardSection class="q-pa-none">
|
||||||
<router-link
|
<VnTitle
|
||||||
:to="{ name: 'AliasBasicData', params: { id: entityId } }"
|
:url="`#/account/alias/${entityId}/basic-data`"
|
||||||
class="header header-link"
|
:text="t('globals.summary.basicData')"
|
||||||
>
|
/>
|
||||||
{{ t('globals.summary.basicData') }}
|
|
||||||
<QIcon name="open_in_new" />
|
|
||||||
</router-link>
|
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<VnLv :label="t('role.id')" :value="alias.id" />
|
<VnLv :label="t('role.id')" :value="alias.id" />
|
||||||
<VnLv :label="t('role.description')" :value="alias.description" />
|
<VnLv :label="t('role.description')" :value="alias.description" />
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import VnCardBeta from 'components/common/VnCardBeta.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import AccountDescriptor from './AccountDescriptor.vue';
|
import AccountDescriptor from './AccountDescriptor.vue';
|
||||||
import filter from './AccountFilter.js';
|
import filter from './AccountFilter.js';
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnCardBeta
|
<VnCard
|
||||||
url="VnUsers/preview"
|
url="VnUsers/preview"
|
||||||
:id-in-where="true"
|
:id-in-where="true"
|
||||||
data-key="Account"
|
data-key="Account"
|
||||||
|
|
|
@ -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.id"
|
||||||
|
:summary="AccountSummary"
|
||||||
|
:proxy-render="true"
|
||||||
|
/>
|
||||||
|
</QPopupProxy>
|
||||||
|
</template>
|
|
@ -5,6 +5,7 @@ import CardSummary from 'components/ui/CardSummary.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import filter from './AccountFilter.js';
|
import filter from './AccountFilter.js';
|
||||||
import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
|
import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
|
||||||
|
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||||
|
|
||||||
const $props = defineProps({ id: { type: Number, default: 0 } });
|
const $props = defineProps({ id: { type: Number, default: 0 } });
|
||||||
|
|
||||||
|
@ -26,13 +27,10 @@ const entityId = computed(() => $props.id || route.params.id);
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<QCardSection class="q-pa-none">
|
<QCardSection class="q-pa-none">
|
||||||
<router-link
|
<VnTitle
|
||||||
:to="{ name: 'AccountBasicData', params: { id: entityId } }"
|
:url="`#/account/${entityId}/basic-data`"
|
||||||
class="header header-link"
|
:text="$t('globals.pageTitles.basicData')"
|
||||||
>
|
/>
|
||||||
{{ $t('globals.pageTitles.basicData') }}
|
|
||||||
<QIcon name="open_in_new" />
|
|
||||||
</router-link>
|
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<VnLv :label="$t('account.card.nickname')" :value="entity.name" />
|
<VnLv :label="$t('account.card.nickname')" :value="entity.name" />
|
||||||
<VnLv :label="$t('account.card.role')" :value="entity.role?.name" />
|
<VnLv :label="$t('account.card.role')" :value="entity.role?.name" />
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import VnCardBeta from 'components/common/VnCardBeta.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import RoleDescriptor from './RoleDescriptor.vue';
|
import RoleDescriptor from './RoleDescriptor.vue';
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnCardBeta
|
<VnCard
|
||||||
url="VnRoles"
|
url="VnRoles"
|
||||||
data-key="Role"
|
data-key="Role"
|
||||||
:id-in-where="true"
|
:id-in-where="true"
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import CardSummary from 'components/ui/CardSummary.vue';
|
import CardSummary from 'components/ui/CardSummary.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
|
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -29,13 +30,10 @@ const entityId = computed(() => $props.id || route.params.id);
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<QCardSection class="q-pa-none">
|
<QCardSection class="q-pa-none">
|
||||||
<a
|
<VnTitle
|
||||||
class="header header-link"
|
:url="`#/account/role/${entityId}/basic-data`"
|
||||||
:href="`#/VnUser/${entityId}/basic-data`"
|
:text="$t('globals.pageTitles.basicData')"
|
||||||
>
|
/>
|
||||||
{{ t('globals.pageTitles.basicData') }}
|
|
||||||
<QIcon name="open_in_new" />
|
|
||||||
</a>
|
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<VnLv :label="t('role.id')" :value="entity.id" />
|
<VnLv :label="t('role.id')" :value="entity.id" />
|
||||||
<VnLv :label="t('globals.name')" :value="entity.name" />
|
<VnLv :label="t('globals.name')" :value="entity.name" />
|
||||||
|
|
|
@ -328,7 +328,7 @@ async function post(query, params) {
|
||||||
<QTd>
|
<QTd>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
v-model="row.shelvingFk"
|
v-model="row.shelvingFk"
|
||||||
:options="shelvings"
|
url="Shelvings"
|
||||||
option-label="code"
|
option-label="code"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
style="width: 100px"
|
style="width: 100px"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import VnCardBeta from 'components/common/VnCardBeta.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import ClaimDescriptor from './ClaimDescriptor.vue';
|
import ClaimDescriptor from './ClaimDescriptor.vue';
|
||||||
import filter from './ClaimFilter.js';
|
import filter from './ClaimFilter.js';
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnCardBeta
|
<VnCard
|
||||||
data-key="Claim"
|
data-key="Claim"
|
||||||
url="Claims"
|
url="Claims"
|
||||||
:descriptor="ClaimDescriptor"
|
:descriptor="ClaimDescriptor"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
import { toDateHourMinSec, toPercentage } from 'src/filters';
|
import { toDateHourMinSec, toPercentage } from 'src/filters';
|
||||||
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
|
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
|
||||||
import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
|
import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
|
||||||
|
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
|
||||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||||
|
@ -65,12 +66,12 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv :label="t('claim.created')" :value="toDateHourMinSec(entity.created)" />
|
<VnLv :label="t('claim.created')" :value="toDateHourMinSec(entity.created)" />
|
||||||
<VnLv :label="t('claim.commercial')">
|
<VnLv :label="t('globals.department')">
|
||||||
<template #value>
|
<template #value>
|
||||||
<VnUserLink
|
<span class="link">
|
||||||
:name="entity.client?.salesPersonUser?.name"
|
{{ entity?.client?.department?.name || '-' }}
|
||||||
:worker-id="entity.client?.salesPersonFk"
|
<DepartmentDescriptorProxy :id="entity?.client?.departmentFk" />
|
||||||
/>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv
|
<VnLv
|
||||||
|
|
|
@ -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>
|
|
@ -14,7 +14,7 @@ export default {
|
||||||
relation: 'client',
|
relation: 'client',
|
||||||
scope: {
|
scope: {
|
||||||
include: [
|
include: [
|
||||||
{ relation: 'salesPersonUser' },
|
{ relation: 'department' },
|
||||||
{
|
{
|
||||||
relation: 'claimsRatio',
|
relation: 'claimsRatio',
|
||||||
scope: {
|
scope: {
|
||||||
|
|
|
@ -117,7 +117,7 @@ const selected = ref([]);
|
||||||
const mana = ref(0);
|
const mana = ref(0);
|
||||||
async function fetchMana() {
|
async function fetchMana() {
|
||||||
const ticketId = claim.value.ticketFk;
|
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;
|
mana.value = response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, useAttrs } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import VnNotes from 'src/components/ui/VnNotes.vue';
|
import VnNotes from 'src/components/ui/VnNotes.vue';
|
||||||
|
@ -7,7 +7,6 @@ import VnNotes from 'src/components/ui/VnNotes.vue';
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const state = useState();
|
const state = useState();
|
||||||
const user = state.getUser();
|
const user = state.getUser();
|
||||||
const $attrs = useAttrs();
|
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: { type: [Number, String], default: null },
|
id: { type: [Number, String], default: null },
|
||||||
|
@ -15,24 +14,21 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
const claimId = computed(() => $props.id || route.params.id);
|
const claimId = computed(() => $props.id || route.params.id);
|
||||||
|
|
||||||
const claimFilter = computed(() => {
|
const claimFilter = {
|
||||||
return {
|
fields: ['id', 'created', 'workerFk', 'text'],
|
||||||
where: { claimFk: claimId.value },
|
include: {
|
||||||
fields: ['id', 'created', 'workerFk', 'text'],
|
relation: 'worker',
|
||||||
include: {
|
scope: {
|
||||||
relation: 'worker',
|
fields: ['id', 'firstName', 'lastName'],
|
||||||
scope: {
|
include: {
|
||||||
fields: ['id', 'firstName', 'lastName'],
|
relation: 'user',
|
||||||
include: {
|
scope: {
|
||||||
relation: 'user',
|
fields: ['id', 'nickname', 'name'],
|
||||||
scope: {
|
|
||||||
fields: ['id', 'nickname', 'name'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
});
|
};
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
claimFk: claimId.value,
|
claimFk: claimId.value,
|
||||||
|
@ -43,7 +39,8 @@ const body = {
|
||||||
<VnNotes
|
<VnNotes
|
||||||
url="claimObservations"
|
url="claimObservations"
|
||||||
:add-note="$props.addNote"
|
:add-note="$props.addNote"
|
||||||
:filter="claimFilter"
|
:user-filter="claimFilter"
|
||||||
|
:filter="{ where: { claimFk: claimId } }"
|
||||||
:body="body"
|
:body="body"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
style="overflow-y: auto"
|
style="overflow-y: auto"
|
||||||
|
|
|
@ -210,6 +210,7 @@ function onDrag() {
|
||||||
class="all-pointer-events absolute delete-button zindex"
|
class="all-pointer-events absolute delete-button zindex"
|
||||||
@click.stop="viewDeleteDms(index)"
|
@click.stop="viewDeleteDms(index)"
|
||||||
round
|
round
|
||||||
|
:data-cy="`delete-button-${index+1}`"
|
||||||
/>
|
/>
|
||||||
<QIcon
|
<QIcon
|
||||||
name="play_circle"
|
name="play_circle"
|
||||||
|
@ -227,6 +228,7 @@ function onDrag() {
|
||||||
class="rounded-borders cursor-pointer fit"
|
class="rounded-borders cursor-pointer fit"
|
||||||
@click="openDialog(media.dmsFk)"
|
@click="openDialog(media.dmsFk)"
|
||||||
v-if="!media.isVideo"
|
v-if="!media.isVideo"
|
||||||
|
:data-cy="`file-${index+1}`"
|
||||||
>
|
>
|
||||||
</QImg>
|
</QImg>
|
||||||
<video
|
<video
|
||||||
|
@ -235,6 +237,7 @@ function onDrag() {
|
||||||
muted="muted"
|
muted="muted"
|
||||||
v-if="media.isVideo"
|
v-if="media.isVideo"
|
||||||
@click="openDialog(media.dmsFk)"
|
@click="openDialog(media.dmsFk)"
|
||||||
|
:data-cy="`file-${index+1}`"
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,6 +19,7 @@ import ClaimNotes from 'src/pages/Claim/Card/ClaimNotes.vue';
|
||||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.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 ClaimDescriptorMenu from './ClaimDescriptorMenu.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -252,13 +253,15 @@ function claimUrl(section) {
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv
|
<VnLv
|
||||||
v-if="$route.name != 'ClaimSummary'"
|
v-if="$route.name != 'ClaimSummary'"
|
||||||
:label="t('globals.salesPerson')"
|
:label="t('customer.summary.team')"
|
||||||
>
|
>
|
||||||
<template #value>
|
<template #value>
|
||||||
<VnUserLink
|
<span class="link">
|
||||||
:name="claim.client?.salesPersonUser?.name"
|
{{ claim?.client?.department?.name || '-' }}
|
||||||
:worker-id="claim.client?.salesPersonFk"
|
<DepartmentDescriptorProxy
|
||||||
/>
|
:id="claim?.client?.departmentFk"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.attendedBy')">
|
<VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.attendedBy')">
|
||||||
|
@ -271,7 +274,7 @@ function claimUrl(section) {
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.customer')">
|
<VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.customer')">
|
||||||
<template #value>
|
<template #value>
|
||||||
<span class="link cursor-pointer">
|
<span class="link">
|
||||||
{{ claim.client?.name }}
|
{{ claim.client?.name }}
|
||||||
<CustomerDescriptorProxy :id="claim.clientFk" />
|
<CustomerDescriptorProxy :id="claim.clientFk" />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -80,7 +80,7 @@ const columns = [
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
:column-search="false"
|
:column-search="false"
|
||||||
:disable-option="{ card: true, table: true }"
|
:disable-option="{ card: true, table: true }"
|
||||||
search-url="actions"
|
:search-url="false"
|
||||||
:filter="{ where: { claimFk: $props.id } }"
|
:filter="{ where: { claimFk: $props.id } }"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:limit="0"
|
:limit="0"
|
||||||
|
|
|
@ -44,15 +44,14 @@ const props = defineProps({
|
||||||
is-outlined
|
is-outlined
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Salesperson')"
|
|
||||||
v-model="params.salesPersonFk"
|
|
||||||
url="Workers/activeWithInheritedRole"
|
|
||||||
:filter="{ where: { role: 'salesPerson' } }"
|
|
||||||
:use-like="false"
|
|
||||||
option-filter="firstName"
|
|
||||||
dense
|
|
||||||
outlined
|
outlined
|
||||||
|
dense
|
||||||
rounded
|
rounded
|
||||||
|
:label="t('globals.params.departmentFk')"
|
||||||
|
v-model="params.departmentFk"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name"
|
||||||
|
url="Departments"
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('claim.attendedBy')"
|
:label="t('claim.attendedBy')"
|
||||||
|
@ -126,7 +125,6 @@ en:
|
||||||
search: Contains
|
search: Contains
|
||||||
clientFk: Customer
|
clientFk: Customer
|
||||||
clientName: Customer
|
clientName: Customer
|
||||||
salesPersonFk: Salesperson
|
|
||||||
attenderFk: Attender
|
attenderFk: Attender
|
||||||
claimResponsibleFk: Responsible
|
claimResponsibleFk: Responsible
|
||||||
claimStateFk: State
|
claimStateFk: State
|
||||||
|
@ -139,7 +137,6 @@ es:
|
||||||
search: Contiene
|
search: Contiene
|
||||||
clientFk: Cliente
|
clientFk: Cliente
|
||||||
clientName: Cliente
|
clientName: Cliente
|
||||||
salesPersonFk: Comercial
|
|
||||||
attenderFk: Asistente
|
attenderFk: Asistente
|
||||||
claimResponsibleFk: Responsable
|
claimResponsibleFk: Responsable
|
||||||
claimStateFk: Estado
|
claimStateFk: Estado
|
||||||
|
@ -148,6 +145,5 @@ es:
|
||||||
itemFk: Artículo
|
itemFk: Artículo
|
||||||
zoneFk: Zona
|
zoneFk: Zona
|
||||||
Client Name: Nombre del cliente
|
Client Name: Nombre del cliente
|
||||||
Salesperson: Comercial
|
|
||||||
Item: Artículo
|
Item: Artículo
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
import { toDate } from 'filters/index';
|
import { toDate } from 'filters/index';
|
||||||
import ClaimFilter from './ClaimFilter.vue';
|
import ClaimFilter from './ClaimFilter.vue';
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.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 VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||||
import ClaimSummary from './Card/ClaimSummary.vue';
|
import ClaimSummary from './Card/ClaimSummary.vue';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
|
@ -48,6 +49,20 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
columnClass: 'expand',
|
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',
|
align: 'left',
|
||||||
label: t('claim.attendedBy'),
|
label: t('claim.attendedBy'),
|
||||||
|
@ -152,6 +167,12 @@ const STATE_COLOR = {
|
||||||
<CustomerDescriptorProxy :id="row.clientFk" />
|
<CustomerDescriptorProxy :id="row.clientFk" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template #column-departmentFk="{ row }">
|
||||||
|
<span class="link" @click.stop>
|
||||||
|
{{ row.departmentName || '-' }}
|
||||||
|
<DepartmentDescriptorProxy :id="row?.departmentFk" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
<template #column-attendedBy="{ row }">
|
<template #column-attendedBy="{ row }">
|
||||||
<span @click.stop>
|
<span @click.stop>
|
||||||
<VnUserLink :name="row.workerName" :worker-id="row.workerFk" />
|
<VnUserLink :name="row.workerName" :worker-id="row.workerFk" />
|
||||||
|
|
|
@ -8,7 +8,6 @@ import FormModel from 'components/FormModel.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
|
||||||
import { getDifferences, getUpdatedValues } from 'src/filters';
|
import { getDifferences, getUpdatedValues } from 'src/filters';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -37,7 +36,7 @@ const exprBuilder = (param, value) => {
|
||||||
function onBeforeSave(formData, originalData) {
|
function onBeforeSave(formData, originalData) {
|
||||||
return getUpdatedValues(
|
return getUpdatedValues(
|
||||||
Object.keys(getDifferences(formData, originalData)),
|
Object.keys(getDifferences(formData, originalData)),
|
||||||
formData
|
formData,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -119,16 +118,11 @@ function onBeforeSave(formData, originalData) {
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnSelectWorker
|
<VnSelect
|
||||||
:label="t('customer.summary.salesPerson')"
|
:label="t('globals.department')"
|
||||||
v-model="data.salesPersonFk"
|
v-model="data.departmentFk"
|
||||||
:params="{
|
url="Departments"
|
||||||
departmentCodes: ['VT', 'shopping'],
|
:fields="['id', 'name']"
|
||||||
}"
|
|
||||||
:has-avatar="true"
|
|
||||||
:rules="validate('client.salesPersonFk')"
|
|
||||||
:expr-builder="exprBuilder"
|
|
||||||
emit-value
|
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
v-model="data.contactChannelFk"
|
v-model="data.contactChannelFk"
|
||||||
|
@ -160,7 +154,7 @@ function onBeforeSave(formData, originalData) {
|
||||||
<QIcon name="info" class="cursor-pointer">
|
<QIcon name="info" class="cursor-pointer">
|
||||||
<QTooltip>{{
|
<QTooltip>{{
|
||||||
t(
|
t(
|
||||||
'In case of a company succession, specify the grantor company'
|
'In case of a company succession, specify the grantor company',
|
||||||
)
|
)
|
||||||
}}</QTooltip>
|
}}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import VnCardBeta from 'components/common/VnCardBeta.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import CustomerDescriptor from './CustomerDescriptor.vue';
|
import CustomerDescriptor from './CustomerDescriptor.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VnCardBeta
|
<VnCard
|
||||||
data-key="Customer"
|
data-key="Customer"
|
||||||
:url="`Clients/${$route.params.id}/getCard`"
|
:url="`Clients/${$route.params.id}/getCard`"
|
||||||
:descriptor="CustomerDescriptor"
|
:descriptor="CustomerDescriptor"
|
||||||
|
|
|
@ -3,14 +3,14 @@ import { onMounted, ref, computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
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 useCardDescription from 'src/composables/useCardDescription';
|
||||||
|
|
||||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
|
||||||
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
||||||
|
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
const state = useState();
|
const state = useState();
|
||||||
|
|
||||||
|
@ -84,14 +84,10 @@ const debtWarning = computed(() => {
|
||||||
:value="toCurrency(entity.debt)"
|
:value="toCurrency(entity.debt)"
|
||||||
:info="t('customer.summary.riskInfo')"
|
:info="t('customer.summary.riskInfo')"
|
||||||
/>
|
/>
|
||||||
<VnLv :label="t('customer.summary.salesPerson')">
|
<VnLv :label="t('globals.department')">
|
||||||
<template #value>
|
<template #value>
|
||||||
<VnUserLink
|
<span class="link" v-text="entity.department?.name" />
|
||||||
v-if="entity.salesPersonUser"
|
<DepartmentDescriptorProxy :id="entity.department?.id" />
|
||||||
:name="entity.salesPersonUser.name"
|
|
||||||
:worker-id="entity.salesPersonFk"
|
|
||||||
/>
|
|
||||||
<span v-else>{{ dashIfEmpty(entity.salesPersonUser) }}</span>
|
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv
|
<VnLv
|
||||||
|
@ -118,14 +114,6 @@ const debtWarning = computed(() => {
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('Allowed substitution') }}</QTooltip>
|
<QTooltip>{{ t('Allowed substitution') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
|
||||||
v-if="customer?.isFreezed"
|
|
||||||
name="vn:frozen"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="!entity.account?.active"
|
v-if="!entity.account?.active"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -150,6 +138,14 @@ const debtWarning = computed(() => {
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
|
<QIcon
|
||||||
|
v-if="entity?.isFreezed"
|
||||||
|
name="vn:frozen"
|
||||||
|
size="xs"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
<QBtn
|
<QBtn
|
||||||
v-if="entity.unpaid"
|
v-if="entity.unpaid"
|
||||||
flat
|
flat
|
||||||
|
@ -163,13 +159,13 @@ const debtWarning = computed(() => {
|
||||||
<br />
|
<br />
|
||||||
{{
|
{{
|
||||||
t('unpaidDated', {
|
t('unpaidDated', {
|
||||||
dated: toDate(customer.unpaid?.dated),
|
dated: toDate(entity.unpaid?.dated),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
<br />
|
<br />
|
||||||
{{
|
{{
|
||||||
t('unpaidAmount', {
|
t('unpaidAmount', {
|
||||||
amount: toCurrency(customer.unpaid?.amount),
|
amount: toCurrency(entity.unpaid?.amount),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
|
|
|
@ -86,12 +86,12 @@ const tableColumnComponents = {
|
||||||
},
|
},
|
||||||
file: {
|
file: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
props: () => ({ flat: true }),
|
||||||
event: ({ row }) => downloadFile(row.dmsFk),
|
event: ({ row }) => downloadFile(row.dmsFk),
|
||||||
},
|
},
|
||||||
employee: {
|
employee: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
props: () => ({ flat: true }),
|
||||||
event: () => {},
|
event: () => {},
|
||||||
},
|
},
|
||||||
created: {
|
created: {
|
||||||
|
@ -214,8 +214,17 @@ const toCustomerFileManagementCreate = () => {
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||||
>
|
>
|
||||||
<template v-if="props.col.name !== 'original'">
|
<template v-if="props.col.name !== 'original'">
|
||||||
{{ props.value }}
|
<span
|
||||||
|
:class="{
|
||||||
|
link:
|
||||||
|
props.col.name === 'employee' ||
|
||||||
|
props.col.name === 'file',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ props.value }}
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<WorkerDescriptorProxy
|
<WorkerDescriptorProxy
|
||||||
:id="props.row.dms.workerFk"
|
:id="props.row.dms.workerFk"
|
||||||
v-if="props.col.name === 'employee'"
|
v-if="props.col.name === 'employee'"
|
||||||
|
|
|
@ -16,9 +16,7 @@ const filter = {
|
||||||
{ relation: 'mandateType', scope: { fields: ['id', 'code'] } },
|
{ relation: 'mandateType', scope: { fields: ['id', 'code'] } },
|
||||||
{ relation: 'company', scope: { fields: ['id', 'code'] } },
|
{ relation: 'company', scope: { fields: ['id', 'code'] } },
|
||||||
],
|
],
|
||||||
where: { clientFk: route.params.id },
|
|
||||||
order: ['created DESC'],
|
order: ['created DESC'],
|
||||||
limit: 20,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
|
@ -32,7 +30,7 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
format: ({ company }) => company.code,
|
format: ({ company }) => company?.code,
|
||||||
label: t('globals.company'),
|
label: t('globals.company'),
|
||||||
name: 'company',
|
name: 'company',
|
||||||
},
|
},
|
||||||
|
@ -65,7 +63,8 @@ const columns = computed(() => [
|
||||||
<VnTable
|
<VnTable
|
||||||
data-key="Mandates"
|
data-key="Mandates"
|
||||||
url="Mandates"
|
url="Mandates"
|
||||||
:filter="filter"
|
:user-filter="filter"
|
||||||
|
:filter="{ where: { clientFk: route.params.id } }"
|
||||||
auto-load
|
auto-load
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
class="full-width q-mt-md"
|
class="full-width q-mt-md"
|
||||||
|
|
|
@ -1,28 +1,15 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import VnNotes from 'src/components/ui/VnNotes.vue';
|
import VnNotes from 'src/components/ui/VnNotes.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
const noteFilter = computed(() => {
|
|
||||||
return {
|
|
||||||
order: 'created DESC',
|
|
||||||
where: {
|
|
||||||
clientFk: `${route.params.id}`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VnNotes
|
<VnNotes
|
||||||
url="clientObservations"
|
url="clientObservations"
|
||||||
:add-note="true"
|
:add-note="true"
|
||||||
:filter="noteFilter"
|
:filter="{ where: { clientFk: $route.params.id } }"
|
||||||
:body="{ clientFk: route.params.id }"
|
:body="{ clientFk: $route.params.id }"
|
||||||
style="overflow-y: auto"
|
style="overflow-y: auto"
|
||||||
:select-type="true"
|
:select-type="true"
|
||||||
required
|
required
|
||||||
|
order="created DESC"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
|
||||||
|
|
||||||
import { toCurrency, toPercentage, toDate, dashOrCurrency } from 'src/filters';
|
import { toCurrency, toPercentage, toDate, dashOrCurrency } from 'src/filters';
|
||||||
import CardSummary from 'components/ui/CardSummary.vue';
|
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 VnTitle from 'src/components/common/VnTitle.vue';
|
||||||
import VnRow from 'src/components/ui/VnRow.vue';
|
import VnRow from 'src/components/ui/VnRow.vue';
|
||||||
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
||||||
|
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const grafanaUrl = 'https://grafana.verdnatura.es';
|
const grafanaUrl = 'https://grafana.verdnatura.es';
|
||||||
|
@ -106,16 +107,12 @@ const sumRisk = ({ clientRisks }) => {
|
||||||
{{ t('globals.params.email') }}
|
{{ t('globals.params.email') }}
|
||||||
<VnLinkMail email="entity.email"></VnLinkMail> </template
|
<VnLinkMail email="entity.email"></VnLinkMail> </template
|
||||||
></VnLv>
|
></VnLv>
|
||||||
<VnLv
|
<VnLv :label="t('globals.department')">
|
||||||
:label="t('customer.summary.salesPerson')"
|
|
||||||
:value="entity?.salesPersonUser?.name"
|
|
||||||
>
|
|
||||||
<template #value>
|
<template #value>
|
||||||
<VnUserLink
|
<span class="link" v-text="entity.department?.name" />
|
||||||
:name="entity.salesPersonUser?.name"
|
<DepartmentDescriptorProxy :id="entity?.department?.id" />
|
||||||
:worker-id="entity.salesPersonFk"
|
</template>
|
||||||
/> </template
|
</VnLv>
|
||||||
></VnLv>
|
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.contactChannel')"
|
:label="t('customer.summary.contactChannel')"
|
||||||
:value="entity?.contactChannel?.name"
|
:value="entity?.contactChannel?.name"
|
||||||
|
|
|
@ -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>
|
|
|
@ -3,7 +3,6 @@ import { useI18n } from 'vue-i18n';
|
||||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
defineProps({
|
defineProps({
|
||||||
|
@ -65,22 +64,15 @@ const exprBuilder = (param, value) => {
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem class="q-mb-sm">
|
<QItem class="q-mb-sm">
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnSelectWorker
|
<VnSelect
|
||||||
: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
|
|
||||||
dense
|
|
||||||
outlined
|
outlined
|
||||||
|
dense
|
||||||
rounded
|
rounded
|
||||||
:input-debounce="0"
|
:label="t('globals.params.departmentFk')"
|
||||||
|
v-model="params.departmentFk"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name"
|
||||||
|
url="Departments"
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
@ -164,7 +156,6 @@ en:
|
||||||
params:
|
params:
|
||||||
search: Contains
|
search: Contains
|
||||||
fi: FI
|
fi: FI
|
||||||
salesPersonFk: Salesperson
|
|
||||||
provinceFk: Province
|
provinceFk: Province
|
||||||
isActive: Is active
|
isActive: Is active
|
||||||
city: City
|
city: City
|
||||||
|
@ -191,7 +182,6 @@ es:
|
||||||
sageTaxTypeFk: Tipo de impuesto Sage
|
sageTaxTypeFk: Tipo de impuesto Sage
|
||||||
sageTransactionTypeFk: Tipo de impuesto Sage
|
sageTransactionTypeFk: Tipo de impuesto Sage
|
||||||
payMethodFk: Forma de pago
|
payMethodFk: Forma de pago
|
||||||
salesPersonFk: Comercial
|
|
||||||
provinceFk: Provincia
|
provinceFk: Provincia
|
||||||
city: Ciudad
|
city: Ciudad
|
||||||
phone: Teléfono
|
phone: Teléfono
|
||||||
|
@ -201,7 +191,6 @@ es:
|
||||||
name: Nombre
|
name: Nombre
|
||||||
postcode: CP
|
postcode: CP
|
||||||
FI: NIF
|
FI: NIF
|
||||||
Salesperson: Comercial
|
|
||||||
Province: Provincia
|
Province: Provincia
|
||||||
City: Ciudad
|
City: Ciudad
|
||||||
Phone: Teléfono
|
Phone: Teléfono
|
||||||
|
|
|
@ -10,7 +10,6 @@ import CustomerFilter from './CustomerFilter.vue';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import VnLocation from 'src/components/common/VnLocation.vue';
|
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||||
import VnLinkPhone from 'src/components/ui/VnLinkPhone.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';
|
import VnSection from 'src/components/common/VnSection.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -73,30 +72,17 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'salesPersonFk',
|
name: 'departmentFk',
|
||||||
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
|
label: t('customer.summary.team'),
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'Workers/activeWithInheritedRole',
|
url: 'Departments',
|
||||||
fields: ['id', 'name', 'firstName'],
|
|
||||||
where: { role: 'salesPerson' },
|
|
||||||
optionFilter: 'firstName',
|
|
||||||
},
|
},
|
||||||
columnFilter: {
|
create: true,
|
||||||
component: 'select',
|
|
||||||
attrs: {
|
|
||||||
url: 'Workers/activeWithInheritedRole',
|
|
||||||
fields: ['id', 'name', 'firstName'],
|
|
||||||
where: { role: 'salesPerson' },
|
|
||||||
optionLabel: 'firstName',
|
|
||||||
optionValue: 'id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
create: false,
|
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
},
|
},
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson),
|
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -155,6 +141,9 @@ const columns = computed(() => [
|
||||||
inWhere: true,
|
inWhere: true,
|
||||||
},
|
},
|
||||||
columnClass: 'expand',
|
columnClass: 'expand',
|
||||||
|
attrs: {
|
||||||
|
uppercase: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -446,36 +435,6 @@ function handleLocation(data, location) {
|
||||||
redirect="customer"
|
redirect="customer"
|
||||||
>
|
>
|
||||||
<template #more-create-dialog="{ data }">
|
<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
|
<VnLocation
|
||||||
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
|
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
|
||||||
v-model="data.location"
|
v-model="data.location"
|
||||||
|
|
|
@ -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',
|
align: 'left',
|
||||||
name: 'departmentFk',
|
name: 'departmentFk',
|
||||||
|
@ -153,6 +131,11 @@ const columns = computed(() => [
|
||||||
label: t('Has recovery'),
|
label: t('Has recovery'),
|
||||||
name: 'hasRecovery',
|
name: 'hasRecovery',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'isWorker',
|
||||||
|
label: t('customer.params.isWorker'),
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const viewAddObservation = (rowsSelected) => {
|
const viewAddObservation = (rowsSelected) => {
|
||||||
|
@ -167,7 +150,6 @@ const viewAddObservation = (rowsSelected) => {
|
||||||
|
|
||||||
function exprBuilder(param, value) {
|
function exprBuilder(param, value) {
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case 'salesPersonFk':
|
|
||||||
case 'creditInsurance':
|
case 'creditInsurance':
|
||||||
case 'countryFk':
|
case 'countryFk':
|
||||||
return { [`c.${param}`]: value };
|
return { [`c.${param}`]: value };
|
||||||
|
@ -176,7 +158,7 @@ function exprBuilder(param, value) {
|
||||||
case 'workerFk':
|
case 'workerFk':
|
||||||
return { [`co.${param}`]: value };
|
return { [`co.${param}`]: value };
|
||||||
case 'departmentFk':
|
case 'departmentFk':
|
||||||
return { [`wd.${param}`]: value };
|
return { [`c.${param}`]: value };
|
||||||
case 'amount':
|
case 'amount':
|
||||||
case 'clientFk':
|
case 'clientFk':
|
||||||
return { [`d.${param}`]: value };
|
return { [`d.${param}`]: value };
|
||||||
|
@ -241,12 +223,6 @@ function exprBuilder(param, value) {
|
||||||
<template #column-observation="{ row }">
|
<template #column-observation="{ row }">
|
||||||
<VnInput type="textarea" v-model="row.observation" readonly dense rows="2" />
|
<VnInput type="textarea" v-model="row.observation" readonly dense rows="2" />
|
||||||
</template>
|
</template>
|
||||||
<template #column-salesPersonFk="{ row }">
|
|
||||||
<span class="link" @click.stop>
|
|
||||||
{{ row.salesPersonName }}
|
|
||||||
<WorkerDescriptorProxy :id="row.salesPersonFk" />
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template #column-departmentFk="{ row }">
|
<template #column-departmentFk="{ row }">
|
||||||
<span class="link" @click.stop>
|
<span class="link" @click.stop>
|
||||||
{{ row.departmentName }}
|
{{ row.departmentName }}
|
||||||
|
@ -265,8 +241,6 @@ function exprBuilder(param, value) {
|
||||||
es:
|
es:
|
||||||
Add observation: Añadir observación
|
Add observation: Añadir observación
|
||||||
Client: Cliente
|
Client: Cliente
|
||||||
Is worker: Es trabajador
|
|
||||||
Salesperson: Comercial
|
|
||||||
Department: Departamento
|
Department: Departamento
|
||||||
Country: País
|
Country: País
|
||||||
P. Method: F. Pago
|
P. Method: F. Pago
|
||||||
|
@ -281,5 +255,5 @@ es:
|
||||||
Credit I.: Crédito A.
|
Credit I.: Crédito A.
|
||||||
Credit insurance: Crédito asegurado
|
Credit insurance: Crédito asegurado
|
||||||
From: Desde
|
From: Desde
|
||||||
Has recovery: Tiene recobro
|
Has recovery: Recobro
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -15,19 +15,12 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const salespersons = ref();
|
|
||||||
const countries = ref();
|
const countries = ref();
|
||||||
const authors = ref();
|
const authors = ref();
|
||||||
const departments = ref();
|
const departments = ref();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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) => (countries = data)" auto-load url="Countries" />
|
||||||
<FetchData
|
<FetchData
|
||||||
@on-fetch="(data) => (authors = data)"
|
@on-fetch="(data) => (authors = data)"
|
||||||
|
@ -62,29 +55,6 @@ const departments = ref();
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
/>
|
/>
|
||||||
</QItem>
|
</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">
|
<QItem class="q-mb-sm">
|
||||||
<QItemSection v-if="departments">
|
<QItemSection v-if="departments">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
@ -219,7 +189,6 @@ const departments = ref();
|
||||||
en:
|
en:
|
||||||
params:
|
params:
|
||||||
clientFk: Client
|
clientFk: Client
|
||||||
salesPersonFk: Salesperson
|
|
||||||
countryFk: Country
|
countryFk: Country
|
||||||
paymentMethod: P. Method
|
paymentMethod: P. Method
|
||||||
balance: Balance D.
|
balance: Balance D.
|
||||||
|
@ -230,7 +199,6 @@ en:
|
||||||
es:
|
es:
|
||||||
params:
|
params:
|
||||||
clientFk: Cliente
|
clientFk: Cliente
|
||||||
salesPersonFk: Comercial
|
|
||||||
countryFk: País
|
countryFk: País
|
||||||
paymentMethod: F. Pago
|
paymentMethod: F. Pago
|
||||||
balance: Saldo V.
|
balance: Saldo V.
|
||||||
|
@ -239,7 +207,6 @@ es:
|
||||||
credit: Crédito A.
|
credit: Crédito A.
|
||||||
defaulterSinced: Desde
|
defaulterSinced: Desde
|
||||||
Client: Cliente
|
Client: Cliente
|
||||||
Salesperson: Comercial
|
|
||||||
Departments: Departamentos
|
Departments: Departamentos
|
||||||
Country: País
|
Country: País
|
||||||
P. Method: F. Pago
|
P. Method: F. Pago
|
||||||
|
|
|
@ -69,17 +69,16 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
|
name: 'departmentFk',
|
||||||
name: 'salesPersonFk',
|
label: t('customer.summary.team'),
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'Workers/activeWithInheritedRole',
|
url: 'Departments',
|
||||||
fields: ['id', 'name'],
|
|
||||||
where: { role: 'salesPerson' },
|
|
||||||
optionFilter: 'firstName',
|
|
||||||
useLike: false,
|
|
||||||
},
|
},
|
||||||
visible: false,
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
</script>
|
</script>
|
||||||
|
@ -96,7 +95,7 @@ const columns = computed(() => [
|
||||||
</VnSubToolbar>
|
</VnSubToolbar>
|
||||||
<VnTable
|
<VnTable
|
||||||
:data-key="dataKey"
|
:data-key="dataKey"
|
||||||
url="Clients"
|
url="Clients/filter"
|
||||||
:table="{
|
:table="{
|
||||||
'row-key': 'id',
|
'row-key': 'id',
|
||||||
selection: 'multiple',
|
selection: 'multiple',
|
||||||
|
@ -127,7 +126,6 @@ const columns = computed(() => [
|
||||||
es:
|
es:
|
||||||
Identifier: Identificador
|
Identifier: Identificador
|
||||||
Social name: Razón social
|
Social name: Razón social
|
||||||
Salesperson: Comercial
|
|
||||||
Phone: Teléfono
|
Phone: Teléfono
|
||||||
City: Población
|
City: Población
|
||||||
Email: Email
|
Email: Email
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useRoute } from 'vue-router';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { getClientRisk } from '../composables/getClientRisk';
|
import { getClientRisk } from '../composables/getClientRisk';
|
||||||
import { useDialogPluginComponent } from 'quasar';
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
import { usePrintService } from 'composables/usePrintService';
|
import { usePrintService } from 'composables/usePrintService';
|
||||||
import useNotify from 'src/composables/useNotify.js';
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
@ -74,26 +74,24 @@ onBeforeMount(() => {
|
||||||
urlCreate.value = `Clients/${route.params.id}/createReceipt`;
|
urlCreate.value = `Clients/${route.params.id}/createReceipt`;
|
||||||
});
|
});
|
||||||
|
|
||||||
function setPaymentType(accounting) {
|
function setPaymentType(data, accounting) {
|
||||||
|
data.bankFk = accounting.id;
|
||||||
if (!accounting) return;
|
if (!accounting) return;
|
||||||
accountingType.value = accounting.accountingType;
|
accountingType.value = accounting.accountingType;
|
||||||
initialData.description = [];
|
data.description = [];
|
||||||
initialData.payed = Date.vnNew();
|
data.payed = Date.vnNew();
|
||||||
isCash.value = accountingType.value.code == 'cash';
|
isCash.value = accountingType.value.code == 'cash';
|
||||||
viewReceipt.value = isCash.value;
|
viewReceipt.value = isCash.value;
|
||||||
if (accountingType.value.daysInFuture)
|
if (accountingType.value.daysInFuture)
|
||||||
initialData.payed.setDate(
|
data.payed.setDate(data.payed.getDate() + accountingType.value.daysInFuture);
|
||||||
initialData.payed.getDate() + accountingType.value.daysInFuture,
|
|
||||||
);
|
|
||||||
maxAmount.value = accountingType.value && accountingType.value.maxAmount;
|
maxAmount.value = accountingType.value && accountingType.value.maxAmount;
|
||||||
if (accountingType.value.code == 'compensation')
|
if (accountingType.value.code == 'compensation') return (data.description = '');
|
||||||
return (initialData.description = '');
|
|
||||||
|
|
||||||
let descriptions = [];
|
let descriptions = [];
|
||||||
if (accountingType.value.receiptDescription)
|
if (accountingType.value.receiptDescription)
|
||||||
descriptions.push(accountingType.value.receiptDescription);
|
descriptions.push(accountingType.value.receiptDescription);
|
||||||
if (initialData.description) descriptions.push(initialData.description);
|
if (data.description) descriptions.push(data.description);
|
||||||
initialData.description = descriptions.join(', ');
|
data.description = descriptions.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculateFromAmount = (event) => {
|
const calculateFromAmount = (event) => {
|
||||||
|
@ -113,7 +111,6 @@ function onBeforeSave(data) {
|
||||||
if (isCash.value && shouldSendEmail.value && !data.email)
|
if (isCash.value && shouldSendEmail.value && !data.email)
|
||||||
return notify(t('There is no assigned email for this client'), 'negative');
|
return notify(t('There is no assigned email for this client'), 'negative');
|
||||||
|
|
||||||
data.bankFk = data.bankFk?.id;
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,42 +178,19 @@ async function getAmountPaid() {
|
||||||
auto-load
|
auto-load
|
||||||
url="Clients/findOne"
|
url="Clients/findOne"
|
||||||
/>
|
/>
|
||||||
<FormModel
|
<FormModelPopup
|
||||||
ref="formModelRef"
|
ref="formModelRef"
|
||||||
:form-initial-data="initialData"
|
:form-initial-data="initialData"
|
||||||
:observe-form-changes="false"
|
|
||||||
:url-create="urlCreate"
|
:url-create="urlCreate"
|
||||||
:mapper="onBeforeSave"
|
:mapper="onBeforeSave"
|
||||||
@on-data-saved="onDataSaved"
|
@on-data-saved="onDataSaved"
|
||||||
prevent-submit
|
:prevent-submit="true"
|
||||||
>
|
>
|
||||||
<template #form="{ data, validate }">
|
<template #form-inputs="{ data, validate }">
|
||||||
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
|
||||||
<QIcon name="close" size="sm" />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<h5 class="q-mt-none">{{ t('New payment') }}</h5>
|
<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>
|
<VnRow>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
autofocus
|
||||||
:label="t('Bank')"
|
:label="t('Bank')"
|
||||||
v-model="data.bankFk"
|
v-model="data.bankFk"
|
||||||
url="Accountings"
|
url="Accountings"
|
||||||
|
@ -225,9 +199,10 @@ async function getAmountPaid() {
|
||||||
sort-by="id"
|
sort-by="id"
|
||||||
:limit="0"
|
:limit="0"
|
||||||
@update:model-value="
|
@update:model-value="
|
||||||
(value, options) => setPaymentType(value, options)
|
(value, options) => setPaymentType(data, value, options)
|
||||||
"
|
"
|
||||||
:emit-value="false"
|
:emit-value="false"
|
||||||
|
data-cy="paymentBank"
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
|
@ -245,8 +220,28 @@ async function getAmountPaid() {
|
||||||
@update:model-value="calculateFromAmount($event)"
|
@update:model-value="calculateFromAmount($event)"
|
||||||
clearable
|
clearable
|
||||||
v-model.number="data.amountPaid"
|
v-model.number="data.amountPaid"
|
||||||
|
data-cy="paymentAmount"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
<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="data.bankFk?.accountingType?.code == 'compensation'">
|
<div v-if="data.bankFk?.accountingType?.code == 'compensation'">
|
||||||
<div class="text-h6">
|
<div class="text-h6">
|
||||||
{{ t('Compensation') }}
|
{{ t('Compensation') }}
|
||||||
|
@ -287,27 +282,8 @@ async function getAmountPaid() {
|
||||||
<QCheckbox v-model="shouldSendEmail" :label="t('Send email')" />
|
<QCheckbox v-model="shouldSendEmail" :label="t('Send email')" />
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</div>
|
</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>
|
</template>
|
||||||
</FormModel>
|
</FormModelPopup>
|
||||||
</QDialog>
|
</QDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,23 @@ describe('getAddresses', () => {
|
||||||
expect(axios.get).toHaveBeenCalledWith(`Clients/${clientId}/addresses`, {
|
expect(axios.get).toHaveBeenCalledWith(`Clients/${clientId}/addresses`, {
|
||||||
params: {
|
params: {
|
||||||
filter: JSON.stringify({
|
filter: JSON.stringify({
|
||||||
fields: ['nickname', 'street', 'city', 'id'],
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'client',
|
||||||
|
scope: {
|
||||||
|
fields: ['defaultAddressFk'],
|
||||||
|
include: {
|
||||||
|
relation: 'defaultAddress',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'agencyModeFk'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
fields: ['nickname', 'street', 'city', 'id', 'isActive', 'clientFk'],
|
||||||
where: { isActive: true },
|
where: { isActive: true },
|
||||||
order: 'nickname ASC',
|
order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -30,4 +44,4 @@ describe('getAddresses', () => {
|
||||||
|
|
||||||
expect(axios.get).not.toHaveBeenCalled();
|
expect(axios.get).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,15 +1,29 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export async function getAddresses(clientId, _filter = {}) {
|
export async function getAddresses(clientId, _filter = {}) {
|
||||||
if (!clientId) return;
|
if (!clientId) return;
|
||||||
const filter = {
|
const filter = {
|
||||||
..._filter,
|
..._filter,
|
||||||
fields: ['nickname', 'street', 'city', 'id'],
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'client',
|
||||||
|
scope: {
|
||||||
|
fields: ['defaultAddressFk'],
|
||||||
|
include: {
|
||||||
|
relation: 'defaultAddress',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'agencyModeFk'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
fields: ['nickname', 'street', 'city', 'id', 'isActive', 'clientFk'],
|
||||||
where: { isActive: true },
|
where: { isActive: true },
|
||||||
order: 'nickname ASC',
|
order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'],
|
||||||
};
|
};
|
||||||
const params = { filter: JSON.stringify(filter) };
|
const params = { filter: JSON.stringify(filter) };
|
||||||
return await axios.get(`Clients/${clientId}/addresses`, {
|
return await axios.get(`Clients/${clientId}/addresses`, {
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ customer:
|
||||||
name: Name
|
name: Name
|
||||||
contact: Contact
|
contact: Contact
|
||||||
mobile: Mobile
|
mobile: Mobile
|
||||||
salesPerson: Sales person
|
team: Team
|
||||||
contactChannel: Contact channel
|
contactChannel: Contact channel
|
||||||
socialName: Social name
|
socialName: Social name
|
||||||
fiscalId: Fiscal ID
|
fiscalId: Fiscal ID
|
||||||
|
@ -78,7 +78,6 @@ customer:
|
||||||
id: Identifier
|
id: Identifier
|
||||||
socialName: Social name
|
socialName: Social name
|
||||||
fi: Tax number
|
fi: Tax number
|
||||||
salesPersonFk: Salesperson
|
|
||||||
creditInsurance: Credit insurance
|
creditInsurance: Credit insurance
|
||||||
phone: Phone
|
phone: Phone
|
||||||
street: Street
|
street: Street
|
||||||
|
|
|
@ -20,7 +20,7 @@ customer:
|
||||||
name: Nombre
|
name: Nombre
|
||||||
contact: Contacto
|
contact: Contacto
|
||||||
mobile: Móvil
|
mobile: Móvil
|
||||||
salesPerson: Comercial
|
team: Equipo
|
||||||
contactChannel: Canal de contacto
|
contactChannel: Canal de contacto
|
||||||
socialName: Razón social
|
socialName: Razón social
|
||||||
fiscalId: NIF/CIF
|
fiscalId: NIF/CIF
|
||||||
|
@ -78,7 +78,6 @@ customer:
|
||||||
id: Identificador
|
id: Identificador
|
||||||
socialName: Razón social
|
socialName: Razón social
|
||||||
fi: NIF / CIF
|
fi: NIF / CIF
|
||||||
salesPersonFk: Comercial
|
|
||||||
creditInsurance: Crédito asegurado
|
creditInsurance: Crédito asegurado
|
||||||
phone: Teléfono
|
phone: Teléfono
|
||||||
street: Dirección fiscal
|
street: Dirección fiscal
|
||||||
|
|
|
@ -13,6 +13,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||||
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
|
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
|
||||||
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
|
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
|
||||||
|
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -53,7 +54,7 @@ onMounted(() => {
|
||||||
:clear-store-on-unmount="false"
|
:clear-store-on-unmount="false"
|
||||||
>
|
>
|
||||||
<template #form="{ data }">
|
<template #form="{ data }">
|
||||||
<VnRow>
|
<VnRow class="q-py-sm">
|
||||||
<VnSelectTravelExtended
|
<VnSelectTravelExtended
|
||||||
:data="data"
|
:data="data"
|
||||||
v-model="data.travelFk"
|
v-model="data.travelFk"
|
||||||
|
@ -65,7 +66,7 @@ onMounted(() => {
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow class="q-py-sm">
|
||||||
<VnInput v-model="data.reference" :label="t('globals.reference')" />
|
<VnInput v-model="data.reference" :label="t('globals.reference')" />
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
v-model="data.invoiceAmount"
|
v-model="data.invoiceAmount"
|
||||||
|
@ -73,7 +74,7 @@ onMounted(() => {
|
||||||
:positive="false"
|
:positive="false"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow class="q-py-sm">
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.invoiceNumber"
|
v-model="data.invoiceNumber"
|
||||||
:label="t('entry.summary.invoiceNumber')"
|
:label="t('entry.summary.invoiceNumber')"
|
||||||
|
@ -84,12 +85,13 @@ onMounted(() => {
|
||||||
:options="companiesOptions"
|
:options="companiesOptions"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="code"
|
option-label="code"
|
||||||
|
sort-by="code"
|
||||||
map-options
|
map-options
|
||||||
hide-selected
|
hide-selected
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow class="q-py-sm">
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
:label="t('entry.summary.commission')"
|
:label="t('entry.summary.commission')"
|
||||||
v-model="data.commission"
|
v-model="data.commission"
|
||||||
|
@ -102,9 +104,10 @@ onMounted(() => {
|
||||||
:options="currenciesOptions"
|
:options="currenciesOptions"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="code"
|
option-label="code"
|
||||||
|
sort-by="code"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow class="q-py-sm">
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
v-model="data.initialTemperature"
|
v-model="data.initialTemperature"
|
||||||
name="initialTemperature"
|
name="initialTemperature"
|
||||||
|
@ -121,8 +124,16 @@ onMounted(() => {
|
||||||
:decimal-places="2"
|
:decimal-places="2"
|
||||||
:positive="false"
|
:positive="false"
|
||||||
/>
|
/>
|
||||||
|
<VnSelect
|
||||||
|
v-model="data.typeFk"
|
||||||
|
url="entryTypes"
|
||||||
|
:fields="['code', 'description']"
|
||||||
|
option-value="code"
|
||||||
|
optionLabel="description"
|
||||||
|
sortBy="description"
|
||||||
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow class="q-py-sm">
|
||||||
<QInput
|
<QInput
|
||||||
:label="t('entry.basicData.observation')"
|
:label="t('entry.basicData.observation')"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
|
@ -132,14 +143,20 @@ onMounted(() => {
|
||||||
fill-input
|
fill-input
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow class="q-py-sm">
|
||||||
<QCheckbox v-model="data.isOrdered" :label="t('entry.summary.ordered')" />
|
<VnCheckbox
|
||||||
<QCheckbox v-model="data.isConfirmed" :label="t('globals.confirmed')" />
|
v-model="data.isOrdered"
|
||||||
<QCheckbox
|
:label="t('entry.list.tableVisibleColumns.isOrdered')"
|
||||||
v-model="data.isExcludedFromAvailable"
|
|
||||||
:label="t('entry.summary.excludedFromAvailable')"
|
|
||||||
/>
|
/>
|
||||||
<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()"
|
:disable="!isAdministrative()"
|
||||||
v-model="data.isBooked"
|
v-model="data.isBooked"
|
||||||
:label="t('entry.basicData.booked')"
|
:label="t('entry.basicData.booked')"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref, computed } from 'vue';
|
||||||
|
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ import ItemDescriptor from 'src/pages/Item/Card/ItemDescriptor.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
|
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
|
||||||
import { checkEntryLock } from 'src/composables/checkEntryLock';
|
import { checkEntryLock } from 'src/composables/checkEntryLock';
|
||||||
|
import VnRow from 'src/components/ui/VnRow.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
@ -57,31 +59,6 @@ const columns = [
|
||||||
createOrder: 12,
|
createOrder: 12,
|
||||||
width: '25px',
|
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',
|
name: 'id',
|
||||||
isId: true,
|
isId: true,
|
||||||
|
@ -111,16 +88,10 @@ const columns = [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'left',
|
||||||
label: t('Article'),
|
label: t('Article'),
|
||||||
|
component: 'input',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
component: 'select',
|
|
||||||
attrs: {
|
|
||||||
url: 'Items',
|
|
||||||
fields: ['id', 'name'],
|
|
||||||
optionLabel: 'name',
|
|
||||||
optionValue: 'id',
|
|
||||||
},
|
|
||||||
width: '85px',
|
width: '85px',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
},
|
},
|
||||||
|
@ -212,7 +183,6 @@ const columns = [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
|
||||||
labelAbbreviation: 'GM',
|
labelAbbreviation: 'GM',
|
||||||
label: t('Grouping selector'),
|
label: t('Grouping selector'),
|
||||||
toolTip: t('Grouping selector'),
|
toolTip: t('Grouping selector'),
|
||||||
|
@ -240,7 +210,6 @@ const columns = [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
|
||||||
labelAbbreviation: 'G',
|
labelAbbreviation: 'G',
|
||||||
label: 'Grouping',
|
label: 'Grouping',
|
||||||
toolTip: 'Grouping',
|
toolTip: 'Grouping',
|
||||||
|
@ -294,7 +263,7 @@ const columns = [
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Amount'),
|
label: t('Amount'),
|
||||||
name: 'amount',
|
name: 'amount',
|
||||||
width: '45px',
|
width: '75px',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
attrs: {
|
attrs: {
|
||||||
positive: false,
|
positive: false,
|
||||||
|
@ -310,7 +279,9 @@ const columns = [
|
||||||
toolTip: t('Package'),
|
toolTip: t('Package'),
|
||||||
name: 'price2',
|
name: 'price2',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
createDisable: true,
|
createAttrs: {
|
||||||
|
disable: true,
|
||||||
|
},
|
||||||
width: '35px',
|
width: '35px',
|
||||||
create: true,
|
create: true,
|
||||||
format: (row) => parseFloat(row['price2']).toFixed(2),
|
format: (row) => parseFloat(row['price2']).toFixed(2),
|
||||||
|
@ -320,7 +291,9 @@ const columns = [
|
||||||
label: t('Box'),
|
label: t('Box'),
|
||||||
name: 'price3',
|
name: 'price3',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
createDisable: true,
|
createAttrs: {
|
||||||
|
disable: true,
|
||||||
|
},
|
||||||
cellEvent: {
|
cellEvent: {
|
||||||
'update:modelValue': async (value, oldValue, row) => {
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
row['price2'] = row['price2'] * (value / oldValue);
|
row['price2'] = row['price2'] * (value / oldValue);
|
||||||
|
@ -340,13 +313,6 @@ const columns = [
|
||||||
toggleIndeterminate: false,
|
toggleIndeterminate: false,
|
||||||
},
|
},
|
||||||
component: 'checkbox',
|
component: 'checkbox',
|
||||||
cellEvent: {
|
|
||||||
'update:modelValue': async (value, oldValue, row) => {
|
|
||||||
await axios.patch(`Items/${row['itemFk']}`, {
|
|
||||||
hasMinPrice: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
width: '25px',
|
width: '25px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -356,13 +322,6 @@ const columns = [
|
||||||
toolTip: t('Minimum price'),
|
toolTip: t('Minimum price'),
|
||||||
name: 'minPrice',
|
name: 'minPrice',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
cellEvent: {
|
|
||||||
'update:modelValue': async (value, oldValue, row) => {
|
|
||||||
await axios.patch(`Items/${row['itemFk']}`, {
|
|
||||||
minPrice: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
width: '35px',
|
width: '35px',
|
||||||
style: (row) => {
|
style: (row) => {
|
||||||
if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
|
if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
|
||||||
|
@ -425,6 +384,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) {
|
function getQuantityStyle(row) {
|
||||||
if (row?.quantity !== row?.stickers * row?.packing)
|
if (row?.quantity !== row?.stickers * row?.packing)
|
||||||
|
@ -610,6 +586,7 @@ onMounted(() => {
|
||||||
:url="`Entries/${entityId}/getBuyList`"
|
:url="`Entries/${entityId}/getBuyList`"
|
||||||
search-url="EntryBuys"
|
search-url="EntryBuys"
|
||||||
save-url="Buys/crud"
|
save-url="Buys/crud"
|
||||||
|
:filter="filter"
|
||||||
:disable-option="{ card: true }"
|
:disable-option="{ card: true }"
|
||||||
v-model:selected="selectedRows"
|
v-model:selected="selectedRows"
|
||||||
@on-fetch="() => footerFetchDataRef.fetch()"
|
@on-fetch="() => footerFetchDataRef.fetch()"
|
||||||
|
@ -655,7 +632,7 @@ onMounted(() => {
|
||||||
:is-editable="editableMode"
|
:is-editable="editableMode"
|
||||||
:without-header="!editableMode"
|
:without-header="!editableMode"
|
||||||
:with-filters="editableMode"
|
:with-filters="editableMode"
|
||||||
:right-search="editableMode"
|
:right-search="false"
|
||||||
:row-click="false"
|
:row-click="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:beforeSaveFn="beforeSave"
|
:beforeSaveFn="beforeSave"
|
||||||
|
@ -666,6 +643,46 @@ onMounted(() => {
|
||||||
data-cy="entry-buys"
|
data-cy="entry-buys"
|
||||||
overlay
|
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"
|
||||||
|
/>
|
||||||
|
<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 }">
|
<template #column-hex="{ row }">
|
||||||
<VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />
|
<VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -696,7 +713,7 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #column-footer-weight>
|
<template #column-footer-weight>
|
||||||
{{ footer?.weight }}
|
<span class="q-pr-xs">{{ footer?.weight }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #column-footer-quantity>
|
<template #column-footer-quantity>
|
||||||
<span :style="getQuantityStyle(footer)" data-cy="footer-quantity">
|
<span :style="getQuantityStyle(footer)" data-cy="footer-quantity">
|
||||||
|
@ -704,9 +721,8 @@ onMounted(() => {
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #column-footer-amount>
|
<template #column-footer-amount>
|
||||||
<span :style="getAmountStyle(footer)" data-cy="footer-amount">
|
<span data-cy="footer-amount">{{ footer?.amount }} / </span>
|
||||||
{{ footer?.amount }}
|
<span style="color: var(--q-positive)">{{ footer?.checkedAmount }}</span>
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
<template #column-create-itemFk="{ data }">
|
<template #column-create-itemFk="{ data }">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
@ -767,6 +783,8 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
|
Buyer: Comprador
|
||||||
|
Family: Familia
|
||||||
Article: Artículo
|
Article: Artículo
|
||||||
Siz.: Med.
|
Siz.: Med.
|
||||||
Size: Medida
|
Size: Medida
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import VnCardBeta from 'components/common/VnCardBeta.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import EntryDescriptor from './EntryDescriptor.vue';
|
import EntryDescriptor from './EntryDescriptor.vue';
|
||||||
import filter from './EntryFilter.js';
|
import filter from './EntryFilter.js';
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnCardBeta
|
<VnCard
|
||||||
data-key="Entry"
|
data-key="Entry"
|
||||||
url="Entries"
|
url="Entries"
|
||||||
:descriptor="EntryDescriptor"
|
:descriptor="EntryDescriptor"
|
||||||
|
|
|
@ -146,9 +146,8 @@ async function deleteEntry() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
ref="entryDescriptorRef"
|
|
||||||
:url="`Entries/${entityId}`"
|
:url="`Entries/${entityId}`"
|
||||||
:userFilter="entryFilter"
|
:filter="entryFilter"
|
||||||
title="supplier.nickname"
|
title="supplier.nickname"
|
||||||
data-key="Entry"
|
data-key="Entry"
|
||||||
width="lg-width"
|
width="lg-width"
|
||||||
|
|
|
@ -2,153 +2,82 @@
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
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';
|
|
||||||
|
|
||||||
const { params } = useRoute();
|
const { params } = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const selectedRows = ref([]);
|
||||||
const entryObservationsRef = ref(null);
|
const entryObservationsRef = ref(null);
|
||||||
const entryObservationsOptions = ref([]);
|
const entityId = ref(params.id);
|
||||||
const selected = ref([]);
|
|
||||||
|
|
||||||
const sortEntryObservationOptions = (data) => {
|
|
||||||
entryObservationsOptions.value = [...data].sort((a, b) =>
|
|
||||||
a.description.localeCompare(b.description),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
name: 'observationType',
|
name: 'id',
|
||||||
label: t('entry.notes.observationType'),
|
isId: true,
|
||||||
field: (row) => row.observationTypeFk,
|
visible: false,
|
||||||
sortable: true,
|
isEditable: false,
|
||||||
options: entryObservationsOptions.value,
|
columnFilter: false,
|
||||||
required: true,
|
|
||||||
model: 'observationTypeFk',
|
|
||||||
optionValue: 'id',
|
|
||||||
optionLabel: 'description',
|
|
||||||
tabIndex: 1,
|
|
||||||
align: 'left',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
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',
|
name: 'description',
|
||||||
label: t('globals.description'),
|
label: t('globals.description'),
|
||||||
field: (row) => row.description,
|
component: 'input',
|
||||||
tabIndex: 2,
|
columnFilter: false,
|
||||||
align: 'left',
|
attrs: { autogrow: true },
|
||||||
|
create: true,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const filter = computed(() => ({
|
||||||
|
fields: ['id', 'entryFk', 'observationTypeFk', 'description'],
|
||||||
|
include: ['observationType'],
|
||||||
|
where: { entryFk: entityId },
|
||||||
|
}));
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<VnTable
|
||||||
url="ObservationTypes"
|
ref="entryObservationsRef"
|
||||||
@on-fetch="(data) => sortEntryObservationOptions(data)"
|
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
|
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>
|
</template>
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Add note: Añadir nota
|
Create note: Crear nota
|
||||||
Remove note: Quitar nota
|
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -92,13 +92,13 @@ onMounted(async () => {
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<VnCheckbox
|
<VnCheckbox
|
||||||
:label="t('entry.summary.ordered')"
|
:label="t('entry.list.tableVisibleColumns.isOrdered')"
|
||||||
v-model="entry.isOrdered"
|
v-model="entry.isOrdered"
|
||||||
:disable="true"
|
:disable="true"
|
||||||
size="xs"
|
size="xs"
|
||||||
/>
|
/>
|
||||||
<VnCheckbox
|
<VnCheckbox
|
||||||
:label="t('globals.confirmed')"
|
:label="t('entry.list.tableVisibleColumns.isConfirmed')"
|
||||||
v-model="entry.isConfirmed"
|
v-model="entry.isConfirmed"
|
||||||
:disable="true"
|
:disable="true"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
@ -110,7 +110,11 @@ onMounted(async () => {
|
||||||
size="xs"
|
size="xs"
|
||||||
/>
|
/>
|
||||||
<VnCheckbox
|
<VnCheckbox
|
||||||
:label="t('entry.summary.excludedFromAvailable')"
|
:label="
|
||||||
|
t(
|
||||||
|
'entry.list.tableVisibleColumns.isExcludedFromAvailable',
|
||||||
|
)
|
||||||
|
"
|
||||||
v-model="entry.isExcludedFromAvailable"
|
v-model="entry.isExcludedFromAvailable"
|
||||||
:disable="true"
|
:disable="true"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
|
|
@ -85,7 +85,7 @@ const entryFilterPanel = ref();
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
:label="t('entry.list.tableVisibleColumns.isConfirmed')"
|
label="LE"
|
||||||
v-model="params.isConfirmed"
|
v-model="params.isConfirmed"
|
||||||
toggle-indeterminate
|
toggle-indeterminate
|
||||||
>
|
>
|
||||||
|
@ -102,6 +102,7 @@ const entryFilterPanel = ref();
|
||||||
v-model="params.landed"
|
v-model="params.landed"
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
is-outlined
|
is-outlined
|
||||||
|
data-cy="landed"
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
@ -121,13 +122,6 @@ const entryFilterPanel = ref();
|
||||||
rounded
|
rounded
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
<QItemSection>
|
|
||||||
<VnInput
|
|
||||||
v-model="params.invoiceNumber"
|
|
||||||
:label="t('params.invoiceNumber')"
|
|
||||||
is-outlined
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
|
@ -145,6 +139,7 @@ const entryFilterPanel = ref();
|
||||||
v-model="params.agencyModeId"
|
v-model="params.agencyModeId"
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
url="AgencyModes"
|
url="AgencyModes"
|
||||||
|
sort-by="name ASC"
|
||||||
:fields="['id', 'name']"
|
:fields="['id', 'name']"
|
||||||
hide-selected
|
hide-selected
|
||||||
dense
|
dense
|
||||||
|
@ -170,6 +165,7 @@ const entryFilterPanel = ref();
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
url="Warehouses"
|
url="Warehouses"
|
||||||
:fields="['id', 'name']"
|
:fields="['id', 'name']"
|
||||||
|
sort-by="name ASC"
|
||||||
hide-selected
|
hide-selected
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
|
@ -185,6 +181,7 @@ const entryFilterPanel = ref();
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
url="Warehouses"
|
url="Warehouses"
|
||||||
:fields="['id', 'name']"
|
:fields="['id', 'name']"
|
||||||
|
sort-by="name ASC"
|
||||||
hide-selected
|
hide-selected
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
|
@ -232,15 +229,6 @@ const entryFilterPanel = ref();
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
|
||||||
<QItemSection>
|
|
||||||
<VnInput
|
|
||||||
v-model="params.evaNotes"
|
|
||||||
:label="t('params.evaNotes')"
|
|
||||||
is-outlined
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
</template>
|
</template>
|
||||||
</VnFilterPanel>
|
</VnFilterPanel>
|
||||||
</template>
|
</template>
|
||||||
|
@ -266,7 +254,7 @@ en:
|
||||||
hasToShowDeletedEntries: Show deleted entries
|
hasToShowDeletedEntries: Show deleted entries
|
||||||
es:
|
es:
|
||||||
params:
|
params:
|
||||||
isExcludedFromAvailable: Inventario
|
isExcludedFromAvailable: Excluida
|
||||||
isOrdered: Pedida
|
isOrdered: Pedida
|
||||||
isConfirmed: Confirmado
|
isConfirmed: Confirmado
|
||||||
isReceived: Recibida
|
isReceived: Recibida
|
||||||
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -107,9 +107,8 @@ const columns = computed(() => [
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'suppliers',
|
url: 'suppliers',
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name'],
|
||||||
where: { order: 'name DESC' },
|
sortBy: 'name ASC',
|
||||||
},
|
},
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName),
|
|
||||||
width: '110px',
|
width: '110px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -145,6 +144,7 @@ const columns = computed(() => [
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'agencyModes',
|
url: 'agencyModes',
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name'],
|
||||||
|
sortBy: 'name ASC',
|
||||||
},
|
},
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
|
@ -158,7 +158,6 @@ const columns = computed(() => [
|
||||||
component: 'input',
|
component: 'input',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
|
||||||
label: t('entry.list.tableVisibleColumns.warehouseOutFk'),
|
label: t('entry.list.tableVisibleColumns.warehouseOutFk'),
|
||||||
name: 'warehouseOutFk',
|
name: 'warehouseOutFk',
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
|
@ -166,6 +165,7 @@ const columns = computed(() => [
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'warehouses',
|
url: 'warehouses',
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name'],
|
||||||
|
sortBy: 'name ASC',
|
||||||
},
|
},
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
|
@ -174,7 +174,6 @@ const columns = computed(() => [
|
||||||
width: '65px',
|
width: '65px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
|
||||||
label: t('entry.list.tableVisibleColumns.warehouseInFk'),
|
label: t('entry.list.tableVisibleColumns.warehouseInFk'),
|
||||||
name: 'warehouseInFk',
|
name: 'warehouseInFk',
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
|
@ -182,6 +181,7 @@ const columns = computed(() => [
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'warehouses',
|
url: 'warehouses',
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name'],
|
||||||
|
sortBy: 'name ASC',
|
||||||
},
|
},
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
|
@ -190,7 +190,6 @@ const columns = computed(() => [
|
||||||
width: '65px',
|
width: '65px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
|
||||||
labelAbbreviation: t('Type'),
|
labelAbbreviation: t('Type'),
|
||||||
label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
||||||
toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
||||||
|
@ -201,6 +200,7 @@ const columns = computed(() => [
|
||||||
fields: ['code', 'description'],
|
fields: ['code', 'description'],
|
||||||
optionValue: 'code',
|
optionValue: 'code',
|
||||||
optionLabel: 'description',
|
optionLabel: 'description',
|
||||||
|
sortBy: 'description',
|
||||||
},
|
},
|
||||||
width: '65px',
|
width: '65px',
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription),
|
format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription),
|
||||||
|
@ -283,7 +283,11 @@ onBeforeMount(async () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VnSection :data-key="dataKey" prefix="entry">
|
<VnSection
|
||||||
|
:data-key="dataKey"
|
||||||
|
prefix="entry"
|
||||||
|
:array-data-props="{ url: 'Entries/filter' }"
|
||||||
|
>
|
||||||
<template #advanced-menu>
|
<template #advanced-menu>
|
||||||
<EntryFilter :data-key="dataKey" />
|
<EntryFilter :data-key="dataKey" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useQuasar, date } from 'quasar';
|
||||||
import { useQuasar } from 'quasar';
|
|
||||||
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnRow from 'components/ui/VnRow.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 VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.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 { t } = useI18n();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const state = useState();
|
const filterDate = ref(useFilterParams('StockBoughts').params);
|
||||||
const user = state.getUser();
|
|
||||||
const footer = ref({ bought: 0, reserve: 0 });
|
const footer = ref({ bought: 0, reserve: 0 });
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
|
@ -46,7 +45,7 @@ const columns = computed(() => [
|
||||||
optionValue: 'id',
|
optionValue: 'id',
|
||||||
},
|
},
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
width: '50px',
|
width: '60%',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -56,20 +55,20 @@ const columns = computed(() => [
|
||||||
create: true,
|
create: true,
|
||||||
component: 'number',
|
component: 'number',
|
||||||
summation: true,
|
summation: true,
|
||||||
width: '50px',
|
|
||||||
format: ({ reserve }, dashIfEmpty) => dashIfEmpty(round(reserve)),
|
format: ({ reserve }, dashIfEmpty) => dashIfEmpty(round(reserve)),
|
||||||
|
width: '20%',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'right',
|
||||||
label: t('entryStockBought.bought'),
|
label: t('entryStockBought.bought'),
|
||||||
name: 'bought',
|
name: 'bought',
|
||||||
summation: true,
|
summation: true,
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
style: ({ reserve, bought }) => boughtStyle(bought, reserve),
|
style: ({ reserve, bought }) => boughtStyle(bought, reserve),
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
|
width: '20%',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
|
||||||
label: t('entryStockBought.date'),
|
label: t('entryStockBought.date'),
|
||||||
name: 'dated',
|
name: 'dated',
|
||||||
component: 'date',
|
component: 'date',
|
||||||
|
@ -77,7 +76,7 @@ const columns = computed(() => [
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'center',
|
||||||
name: 'tableActions',
|
name: 'tableActions',
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -90,7 +89,7 @@ const columns = computed(() => [
|
||||||
component: EntryStockBoughtDetail,
|
component: EntryStockBoughtDetail,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
workerFk: row.workerFk,
|
workerFk: row.workerFk,
|
||||||
dated: userParams.value.dated,
|
dated: filterDate.value.dated,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -98,39 +97,29 @@ const columns = computed(() => [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const fetchDataRef = ref();
|
const fetchDataRef = ref();
|
||||||
const travelDialogRef = ref(false);
|
const travelDialogRef = ref(false);
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const travel = ref(null);
|
const travel = ref(null);
|
||||||
const userParams = ref({
|
const filter = computed(() => ({
|
||||||
dated: Date.vnNew().toJSON(),
|
fields: ['id', 'm3', 'ref', 'warehouseInFk'],
|
||||||
});
|
|
||||||
|
|
||||||
const filter = ref({
|
|
||||||
fields: ['id', 'm3', 'warehouseInFk'],
|
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
relation: 'warehouseIn',
|
relation: 'warehouseIn',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['code'],
|
fields: ['code', 'name'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
where: {
|
where: {
|
||||||
shipped: (userParams.value.dated
|
shipped: date.adjustDate(filterDate.value.dated, {
|
||||||
? new Date(userParams.value.dated)
|
hour: 0,
|
||||||
: Date.vnNew()
|
minute: 0,
|
||||||
).setHours(0, 0, 0, 0),
|
second: 0,
|
||||||
|
}),
|
||||||
m3: { neq: null },
|
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() {
|
function openDialog() {
|
||||||
travelDialogRef.value = true;
|
travelDialogRef.value = true;
|
||||||
|
@ -151,6 +140,31 @@ function round(value) {
|
||||||
function boughtStyle(bought, reserve) {
|
function boughtStyle(bought, reserve) {
|
||||||
return reserve < bought ? { color: 'var(--q-negative)' } : '';
|
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);
|
||||||
|
const filteredChanges = changes.filter((change) => change?.isReal !== false);
|
||||||
|
data.creates = filteredChanges;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnSubToolbar>
|
<VnSubToolbar>
|
||||||
|
@ -158,18 +172,17 @@ function boughtStyle(bought, reserve) {
|
||||||
<FetchData
|
<FetchData
|
||||||
ref="fetchDataRef"
|
ref="fetchDataRef"
|
||||||
url="Travels"
|
url="Travels"
|
||||||
auto-load
|
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
@on-fetch="
|
@on-fetch="
|
||||||
(data) => {
|
(data) => {
|
||||||
travel = data.find(
|
travel = data.find(
|
||||||
(data) => data.warehouseIn?.code.toLowerCase() === 'vnh',
|
(data) => data.warehouseIn?.code?.toLowerCase() === 'vnh',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<VnRow class="travel">
|
<VnRow class="travel">
|
||||||
<div v-if="travel">
|
<div v-show="travel">
|
||||||
<span style="color: var(--vn-label-color)">
|
<span style="color: var(--vn-label-color)">
|
||||||
{{ t('entryStockBought.purchaseSpaces') }}:
|
{{ t('entryStockBought.purchaseSpaces') }}:
|
||||||
</span>
|
</span>
|
||||||
|
@ -180,7 +193,7 @@ function boughtStyle(bought, reserve) {
|
||||||
v-if="travel?.m3"
|
v-if="travel?.m3"
|
||||||
style="max-width: 20%"
|
style="max-width: 20%"
|
||||||
flat
|
flat
|
||||||
icon="edit"
|
icon="search"
|
||||||
@click="openDialog()"
|
@click="openDialog()"
|
||||||
:title="t('entryStockBought.editTravel')"
|
:title="t('entryStockBought.editTravel')"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -195,57 +208,42 @@ function boughtStyle(bought, reserve) {
|
||||||
:url-update="`Travels/${travel?.id}`"
|
:url-update="`Travels/${travel?.id}`"
|
||||||
model="travel"
|
model="travel"
|
||||||
:title="t('Travel m3')"
|
:title="t('Travel m3')"
|
||||||
:form-initial-data="{ id: travel?.id, m3: travel?.m3 }"
|
:form-initial-data="travel"
|
||||||
@on-data-saved="fetchDataRef.fetch()"
|
@on-data-saved="fetchDataRef.fetch()"
|
||||||
>
|
>
|
||||||
<template #form-inputs="{ data }">
|
<template #form-inputs="{ data }">
|
||||||
<VnInput
|
<span class="link">
|
||||||
v-model="data.id"
|
{{ data.ref }}
|
||||||
:label="t('id')"
|
<TravelDescriptorProxy :id="data.id" />
|
||||||
type="number"
|
</span>
|
||||||
disable
|
|
||||||
readonly
|
|
||||||
/>
|
|
||||||
<VnInput v-model="data.m3" :label="t('m3')" type="number" />
|
<VnInput v-model="data.m3" :label="t('m3')" type="number" />
|
||||||
</template>
|
</template>
|
||||||
</FormModelPopup>
|
</FormModelPopup>
|
||||||
</QDialog>
|
</QDialog>
|
||||||
<RightMenu>
|
|
||||||
<template #right-panel>
|
|
||||||
<EntryStockBoughtFilter
|
|
||||||
data-key="StockBoughts"
|
|
||||||
@set-user-params="setUserParams"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</RightMenu>
|
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<div class="column items-center">
|
<div class="column items-center">
|
||||||
<VnTable
|
<VnTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
data-key="StockBoughts"
|
data-key="StockBoughts"
|
||||||
url="StockBoughts/getStockBought"
|
url="StockBoughts/getStockBought"
|
||||||
|
:beforeSaveFn="beforeSave"
|
||||||
save-url="StockBoughts/crud"
|
save-url="StockBoughts/crud"
|
||||||
search-url="StockBoughts"
|
search-url="StockBoughts"
|
||||||
order="reserve DESC"
|
order="bought DESC"
|
||||||
:right-search="false"
|
|
||||||
:is-editable="true"
|
:is-editable="true"
|
||||||
@on-fetch="(data) => setFooter(data)"
|
@on-fetch="
|
||||||
:create="{
|
async (data) => {
|
||||||
urlCreate: 'StockBoughts',
|
setFooter(data);
|
||||||
title: t('entryStockBought.reserveSomeSpace'),
|
await fetchDataRef.fetch();
|
||||||
onDataSaved: () => tableRef.reload(),
|
}
|
||||||
formInitialData: {
|
"
|
||||||
workerFk: user.id,
|
|
||||||
dated: Date.vnNow(),
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:user-params="userParams"
|
|
||||||
:footer="true"
|
:footer="true"
|
||||||
table-height="80vh"
|
table-height="80vh"
|
||||||
auto-load
|
|
||||||
:column-search="false"
|
:column-search="false"
|
||||||
:without-header="true"
|
:without-header="true"
|
||||||
|
:user-params="{ dated: Date.vnNew() }"
|
||||||
|
auto-load
|
||||||
>
|
>
|
||||||
<template #column-workerFk="{ row }">
|
<template #column-workerFk="{ row }">
|
||||||
<span class="link" @click.stop>
|
<span class="link" @click.stop>
|
||||||
|
@ -278,9 +276,6 @@ function boughtStyle(bought, reserve) {
|
||||||
.column {
|
.column {
|
||||||
min-width: 35%;
|
min-width: 35%;
|
||||||
margin-top: 5%;
|
margin-top: 5%;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
.text-negative {
|
.text-negative {
|
||||||
color: $negative !important;
|
color: $negative !important;
|
||||||
|
|
|
@ -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>
|
|
|
@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||||
import { toDate } from 'src/filters/index';
|
import { toDate } from 'src/filters/index';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import EntryBuysTableDialog from './EntryBuysTableDialog.vue';
|
import EntrySupplierlDetail from './EntrySupplierlDetail.vue';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -18,18 +18,28 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'id',
|
name: 'id',
|
||||||
label: t('myEntries.id'),
|
label: t('entrySupplier.id'),
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
|
isId: true,
|
||||||
|
chip: {
|
||||||
|
condition: () => true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'supplierName',
|
||||||
|
label: t('entrySupplier.supplierName'),
|
||||||
|
cardVisible: true,
|
||||||
isTitle: true,
|
isTitle: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
visible: false,
|
visible: false,
|
||||||
align: 'right',
|
align: 'right',
|
||||||
label: t('myEntries.shipped'),
|
label: t('entrySupplier.shipped'),
|
||||||
name: 'shipped',
|
name: 'shipped',
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
name: 'fromShipped',
|
name: 'fromShipped',
|
||||||
label: t('myEntries.fromShipped'),
|
label: t('entrySupplier.fromShipped'),
|
||||||
component: 'date',
|
component: 'date',
|
||||||
},
|
},
|
||||||
format: ({ shipped }) => toDate(shipped),
|
format: ({ shipped }) => toDate(shipped),
|
||||||
|
@ -37,26 +47,26 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
visible: false,
|
visible: false,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('myEntries.shipped'),
|
label: t('entrySupplier.shipped'),
|
||||||
name: 'shipped',
|
name: 'shipped',
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
name: 'toShipped',
|
name: 'toShipped',
|
||||||
label: t('myEntries.toShipped'),
|
label: t('entrySupplier.toShipped'),
|
||||||
component: 'date',
|
component: 'date',
|
||||||
},
|
},
|
||||||
format: ({ shipped }) => toDate(shipped),
|
format: ({ shipped }) => toDate(shipped),
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'left',
|
||||||
label: t('myEntries.shipped'),
|
label: t('entrySupplier.shipped'),
|
||||||
name: 'shipped',
|
name: 'shipped',
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
format: ({ shipped }) => toDate(shipped),
|
format: ({ shipped }) => toDate(shipped),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'left',
|
||||||
label: t('myEntries.landed'),
|
label: t('entrySupplier.landed'),
|
||||||
name: 'landed',
|
name: 'landed',
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
format: ({ landed }) => toDate(landed),
|
format: ({ landed }) => toDate(landed),
|
||||||
|
@ -64,15 +74,13 @@ const columns = computed(() => [
|
||||||
|
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'right',
|
||||||
label: t('myEntries.wareHouseIn'),
|
label: t('entrySupplier.wareHouseIn'),
|
||||||
name: 'warehouseInFk',
|
name: 'warehouseInFk',
|
||||||
format: (row) => {
|
format: ({ warehouseInName }) => warehouseInName,
|
||||||
row.warehouseInName;
|
|
||||||
},
|
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
name: 'warehouseInFk',
|
name: 'warehouseInFk',
|
||||||
label: t('myEntries.warehouseInFk'),
|
label: t('entrySupplier.warehouseInFk'),
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'warehouses',
|
url: 'warehouses',
|
||||||
|
@ -86,13 +94,13 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('myEntries.daysOnward'),
|
label: t('entrySupplier.daysOnward'),
|
||||||
name: 'daysOnward',
|
name: 'daysOnward',
|
||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('myEntries.daysAgo'),
|
label: t('entrySupplier.daysAgo'),
|
||||||
name: 'daysAgo',
|
name: 'daysAgo',
|
||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
|
@ -101,8 +109,8 @@ const columns = computed(() => [
|
||||||
name: 'tableActions',
|
name: 'tableActions',
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
title: t('myEntries.printLabels'),
|
title: t('entrySupplier.printLabels'),
|
||||||
icon: 'move_item',
|
icon: 'search',
|
||||||
isPrimary: true,
|
isPrimary: true,
|
||||||
action: (row) => printBuys(row.id),
|
action: (row) => printBuys(row.id),
|
||||||
},
|
},
|
||||||
|
@ -112,7 +120,7 @@ const columns = computed(() => [
|
||||||
|
|
||||||
const printBuys = (rowId) => {
|
const printBuys = (rowId) => {
|
||||||
quasar.dialog({
|
quasar.dialog({
|
||||||
component: EntryBuysTableDialog,
|
component: EntrySupplierlDetail,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
id: rowId,
|
id: rowId,
|
||||||
},
|
},
|
||||||
|
@ -121,19 +129,18 @@ const printBuys = (rowId) => {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnSearchbar
|
<VnSearchbar
|
||||||
data-key="myEntriesList"
|
data-key="entrySupplierList"
|
||||||
url="Entries/filter"
|
url="Entries/filter"
|
||||||
:label="t('myEntries.search')"
|
:label="t('entrySupplier.search')"
|
||||||
:info="t('myEntries.searchInfo')"
|
:info="t('entrySupplier.searchInfo')"
|
||||||
/>
|
/>
|
||||||
<VnTable
|
<VnTable
|
||||||
data-key="myEntriesList"
|
data-key="entrySupplierList"
|
||||||
url="Entries/filter"
|
url="Entries/filter"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:user-params="params"
|
:user-params="params"
|
||||||
default-mode="card"
|
default-mode="card"
|
||||||
order="shipped DESC"
|
order="shipped DESC"
|
||||||
auto-load
|
auto-load
|
||||||
chip-locale="myEntries"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
|
@ -30,7 +30,7 @@ const entriesTableColumns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'itemFk',
|
name: 'itemFk',
|
||||||
field: 'itemFk',
|
field: 'itemFk',
|
||||||
label: t('entry.latestBuys.tableVisibleColumns.itemFk'),
|
label: t('entrySupplier.itemId'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -65,7 +65,15 @@ const entriesTableColumns = computed(() => [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function downloadCSV(rows) {
|
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 csvRows = rows.map((row) => {
|
||||||
const buy = row;
|
const buy = row;
|
||||||
|
@ -119,17 +127,18 @@ function downloadCSV(rows) {
|
||||||
>
|
>
|
||||||
<template #top-left>
|
<template #top-left>
|
||||||
<QBtn
|
<QBtn
|
||||||
:label="t('myEntries.downloadCsv')"
|
:label="t('entrySupplier.downloadCsv')"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="csv"
|
icon="csv"
|
||||||
@click="downloadCSV(rows)"
|
@click="downloadCSV(rows)"
|
||||||
unelevated
|
unelevated
|
||||||
|
data-cy="downloadCsvBtn"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #top-right>
|
<template #top-right>
|
||||||
<QBtn
|
<QBtn
|
||||||
class="q-mr-lg"
|
class="q-mr-lg"
|
||||||
:label="t('myEntries.printLabels')"
|
:label="t('entrySupplier.printLabels')"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="print"
|
icon="print"
|
||||||
@click="
|
@click="
|
||||||
|
@ -148,13 +157,18 @@ function downloadCSV(rows) {
|
||||||
v-if="props.row.stickers > 0"
|
v-if="props.row.stickers > 0"
|
||||||
@click="
|
@click="
|
||||||
openReport(
|
openReport(
|
||||||
`Entries/${props.row.id}/buy-label-supplier`
|
`Entries/${props.row.id}/buy-label-supplier`,
|
||||||
|
{},
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
unelevated
|
unelevated
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
data-cy="seeLabelBtn"
|
||||||
>
|
>
|
||||||
<QTooltip>{{
|
<QTooltip>{{
|
||||||
t('myEntries.viewLabel')
|
t('entrySupplier.viewLabel')
|
||||||
}}</QTooltip>
|
}}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</QTr>
|
</QTr>
|
|
@ -38,7 +38,7 @@ const recalc = async () => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="q-pa-lg row justify-center">
|
<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>
|
<QCardSection>
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
class="q-mb-lg"
|
class="q-mb-lg"
|
||||||
|
@ -46,6 +46,7 @@ const recalc = async () => {
|
||||||
:label="$t('globals.from')"
|
:label="$t('globals.from')"
|
||||||
rounded
|
rounded
|
||||||
dense
|
dense
|
||||||
|
data-cy="dateFrom"
|
||||||
/>
|
/>
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
class="q-mb-lg"
|
class="q-mb-lg"
|
||||||
|
@ -55,6 +56,7 @@ const recalc = async () => {
|
||||||
:disable="!dateFrom"
|
:disable="!dateFrom"
|
||||||
rounded
|
rounded
|
||||||
dense
|
dense
|
||||||
|
data-cy="dateTo"
|
||||||
/>
|
/>
|
||||||
<QBtn
|
<QBtn
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -63,6 +65,7 @@ const recalc = async () => {
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
:disable="isLoading || !(dateFrom && dateTo)"
|
:disable="isLoading || !(dateFrom && dateTo)"
|
||||||
@click="recalc()"
|
@click="recalc()"
|
||||||
|
data-cy="recalc"
|
||||||
/>
|
/>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
</QCard>
|
</QCard>
|
||||||
|
|
|
@ -6,7 +6,7 @@ entry:
|
||||||
list:
|
list:
|
||||||
newEntry: New entry
|
newEntry: New entry
|
||||||
tableVisibleColumns:
|
tableVisibleColumns:
|
||||||
isExcludedFromAvailable: Exclude from inventory
|
isExcludedFromAvailable: Excluded from available
|
||||||
isOrdered: Ordered
|
isOrdered: Ordered
|
||||||
isConfirmed: Ready to label
|
isConfirmed: Ready to label
|
||||||
isReceived: Received
|
isReceived: Received
|
||||||
|
@ -33,7 +33,7 @@ entry:
|
||||||
invoiceAmount: Invoice amount
|
invoiceAmount: Invoice amount
|
||||||
ordered: Ordered
|
ordered: Ordered
|
||||||
booked: Booked
|
booked: Booked
|
||||||
excludedFromAvailable: Inventory
|
excludedFromAvailable: Excluded
|
||||||
travelReference: Reference
|
travelReference: Reference
|
||||||
travelAgency: Agency
|
travelAgency: Agency
|
||||||
travelShipped: Shipped
|
travelShipped: Shipped
|
||||||
|
@ -55,7 +55,7 @@ entry:
|
||||||
commission: Commission
|
commission: Commission
|
||||||
observation: Observation
|
observation: Observation
|
||||||
booked: Booked
|
booked: Booked
|
||||||
excludedFromAvailable: Inventory
|
excludedFromAvailable: Excluded
|
||||||
initialTemperature: Ini °C
|
initialTemperature: Ini °C
|
||||||
finalTemperature: Fin °C
|
finalTemperature: Fin °C
|
||||||
buys:
|
buys:
|
||||||
|
@ -65,27 +65,10 @@ entry:
|
||||||
printedStickers: Printed stickers
|
printedStickers: Printed stickers
|
||||||
notes:
|
notes:
|
||||||
observationType: Observation type
|
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:
|
params:
|
||||||
isExcludedFromAvailable: Exclude from inventory
|
entryFk: Entry
|
||||||
|
observationTypeFk: Observation type
|
||||||
|
isExcludedFromAvailable: Excluded from available
|
||||||
isOrdered: Ordered
|
isOrdered: Ordered
|
||||||
isConfirmed: Ready to label
|
isConfirmed: Ready to label
|
||||||
isReceived: Received
|
isReceived: Received
|
||||||
|
@ -127,13 +110,17 @@ entry:
|
||||||
company_name: Company name
|
company_name: Company name
|
||||||
itemTypeFk: Item type
|
itemTypeFk: Item type
|
||||||
workerFk: Worker id
|
workerFk: Worker id
|
||||||
|
daysAgo: Days ago
|
||||||
|
toShipped: T. shipped
|
||||||
|
fromShipped: F. shipped
|
||||||
|
supplierName: Supplier
|
||||||
search: Search entries
|
search: Search entries
|
||||||
searchInfo: You can search by entry reference
|
searchInfo: You can search by entry reference
|
||||||
descriptorMenu:
|
descriptorMenu:
|
||||||
showEntryReport: Show entry report
|
showEntryReport: Show entry report
|
||||||
entryFilter:
|
entryFilter:
|
||||||
params:
|
params:
|
||||||
isExcludedFromAvailable: Exclude from inventory
|
isExcludedFromAvailable: Excluded from available
|
||||||
invoiceNumber: Invoice number
|
invoiceNumber: Invoice number
|
||||||
travelFk: Travel
|
travelFk: Travel
|
||||||
companyFk: Company
|
companyFk: Company
|
||||||
|
@ -155,7 +142,7 @@ entryFilter:
|
||||||
warehouseOutFk: Origin
|
warehouseOutFk: Origin
|
||||||
warehouseInFk: Destiny
|
warehouseInFk: Destiny
|
||||||
entryTypeCode: Entry type
|
entryTypeCode: Entry type
|
||||||
myEntries:
|
entrySupplier:
|
||||||
id: ID
|
id: ID
|
||||||
landed: Landed
|
landed: Landed
|
||||||
shipped: Shipped
|
shipped: Shipped
|
||||||
|
@ -170,6 +157,8 @@ myEntries:
|
||||||
downloadCsv: Download CSV
|
downloadCsv: Download CSV
|
||||||
search: Search entries
|
search: Search entries
|
||||||
searchInfo: You can search by entry reference
|
searchInfo: You can search by entry reference
|
||||||
|
supplierName: Supplier
|
||||||
|
itemId: Item id
|
||||||
entryStockBought:
|
entryStockBought:
|
||||||
travel: Travel
|
travel: Travel
|
||||||
editTravel: Edit travel
|
editTravel: Edit travel
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue