Merge branch 'dev' into 7793_sortByWeight
This commit is contained in:
commit
3f1195712a
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
3095
CHANGELOG.md
3095
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env groovy
|
#!/usr/bin/env groovy
|
||||||
|
|
||||||
def PROTECTED_BRANCH
|
def PROTECTED_BRANCH
|
||||||
|
def IS_LATEST
|
||||||
|
|
||||||
def BRANCH_ENV = [
|
def BRANCH_ENV = [
|
||||||
test: 'test',
|
test: 'test',
|
||||||
|
@ -10,16 +11,18 @@ def BRANCH_ENV = [
|
||||||
|
|
||||||
node {
|
node {
|
||||||
stage('Setup') {
|
stage('Setup') {
|
||||||
env.FRONT_REPLICAS = 1
|
|
||||||
env.NODE_ENV = BRANCH_ENV[env.BRANCH_NAME] ?: 'dev'
|
env.NODE_ENV = BRANCH_ENV[env.BRANCH_NAME] ?: 'dev'
|
||||||
|
|
||||||
PROTECTED_BRANCH = [
|
PROTECTED_BRANCH = [
|
||||||
'dev',
|
'dev',
|
||||||
'test',
|
'test',
|
||||||
'master',
|
'master',
|
||||||
|
'main',
|
||||||
'beta'
|
'beta'
|
||||||
].contains(env.BRANCH_NAME)
|
].contains(env.BRANCH_NAME)
|
||||||
|
|
||||||
|
IS_LATEST = ['master', 'main'].contains(env.BRANCH_NAME)
|
||||||
|
|
||||||
// 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}"
|
||||||
|
@ -58,6 +61,19 @@ pipeline {
|
||||||
PROJECT_NAME = 'lilium'
|
PROJECT_NAME = 'lilium'
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Version') {
|
||||||
|
when {
|
||||||
|
expression { PROTECTED_BRANCH }
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
def packageJson = readJSON file: 'package.json'
|
||||||
|
def version = "${packageJson.version}-build${env.BUILD_ID}"
|
||||||
|
writeFile(file: 'VERSION.txt', text: version)
|
||||||
|
echo "VERSION: ${version}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Install') {
|
stage('Install') {
|
||||||
environment {
|
environment {
|
||||||
NODE_ENV = ""
|
NODE_ENV = ""
|
||||||
|
@ -71,17 +87,48 @@ pipeline {
|
||||||
expression { !PROTECTED_BRANCH }
|
expression { !PROTECTED_BRANCH }
|
||||||
}
|
}
|
||||||
environment {
|
environment {
|
||||||
NODE_ENV = ""
|
NODE_ENV = ''
|
||||||
|
CI = 'true'
|
||||||
|
TZ = 'Europe/Madrid'
|
||||||
}
|
}
|
||||||
steps {
|
parallel {
|
||||||
sh 'pnpm run test:unit:ci'
|
stage('Unit') {
|
||||||
}
|
steps {
|
||||||
post {
|
sh 'pnpm run test:unit:ci'
|
||||||
always {
|
}
|
||||||
junit(
|
post {
|
||||||
testResults: 'junitresults.xml',
|
always {
|
||||||
allowEmptyResults: true
|
junit(
|
||||||
)
|
testResults: 'junit/vitest.xml',
|
||||||
|
allowEmptyResults: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('E2E') {
|
||||||
|
environment {
|
||||||
|
CREDENTIALS = credentials('docker-registry')
|
||||||
|
COMPOSE_PROJECT = "${PROJECT_NAME}-${env.BUILD_ID}"
|
||||||
|
COMPOSE_PARAMS = "-p ${env.COMPOSE_PROJECT} -f test/cypress/docker-compose.yml --project-directory ."
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
def image = docker.build('lilium-dev', '-f docs/Dockerfile.dev docs')
|
||||||
|
sh "docker-compose ${env.COMPOSE_PARAMS} up -d"
|
||||||
|
image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ") {
|
||||||
|
sh 'cypress run --browser chromium'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
sh "docker-compose ${env.COMPOSE_PARAMS} down"
|
||||||
|
junit(
|
||||||
|
testResults: 'junit/e2e.xml',
|
||||||
|
allowEmptyResults: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,25 +138,30 @@ pipeline {
|
||||||
}
|
}
|
||||||
environment {
|
environment {
|
||||||
CREDENTIALS = credentials('docker-registry')
|
CREDENTIALS = credentials('docker-registry')
|
||||||
|
VERSION = readFile 'VERSION.txt'
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
sh 'quasar build'
|
|
||||||
script {
|
script {
|
||||||
def packageJson = readJSON file: 'package.json'
|
sh 'quasar build'
|
||||||
env.VERSION = "${packageJson.version}-build${env.BUILD_ID}"
|
|
||||||
|
def baseImage = "salix-frontend:${env.VERSION}"
|
||||||
|
def image = docker.build(baseImage, ".")
|
||||||
|
docker.withRegistry("https://${env.REGISTRY}", 'docker-registry') {
|
||||||
|
image.push()
|
||||||
|
image.push(env.BRANCH_NAME)
|
||||||
|
if (IS_LATEST) image.push('latest')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dockerBuild()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Deploy') {
|
stage('Deploy') {
|
||||||
when {
|
when {
|
||||||
expression { PROTECTED_BRANCH }
|
expression { PROTECTED_BRANCH }
|
||||||
}
|
}
|
||||||
|
environment {
|
||||||
|
VERSION = readFile 'VERSION.txt'
|
||||||
|
}
|
||||||
steps {
|
steps {
|
||||||
script {
|
|
||||||
def packageJson = readJSON file: 'package.json'
|
|
||||||
env.VERSION = "${packageJson.version}-build${env.BUILD_ID}"
|
|
||||||
}
|
|
||||||
withKubeConfig([
|
withKubeConfig([
|
||||||
serverUrl: "$KUBERNETES_API",
|
serverUrl: "$KUBERNETES_API",
|
||||||
credentialsId: 'kubernetes',
|
credentialsId: 'kubernetes',
|
||||||
|
|
|
@ -3,10 +3,39 @@ import { defineConfig } from 'cypress';
|
||||||
// https://docs.cypress.io/app/references/configuration
|
// https://docs.cypress.io/app/references/configuration
|
||||||
// https://www.npmjs.com/package/cypress-mochawesome-reporter
|
// https://www.npmjs.com/package/cypress-mochawesome-reporter
|
||||||
|
|
||||||
|
let urlHost,
|
||||||
|
reporter,
|
||||||
|
reporterOptions;
|
||||||
|
|
||||||
|
if (process.env.CI) {
|
||||||
|
urlHost = 'front';
|
||||||
|
reporter = 'junit';
|
||||||
|
reporterOptions = {
|
||||||
|
mochaFile: 'junit/e2e.xml',
|
||||||
|
toConsole: false,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
urlHost = 'localhost';
|
||||||
|
reporter = 'cypress-mochawesome-reporter';
|
||||||
|
reporterOptions = {
|
||||||
|
charts: true,
|
||||||
|
reportPageTitle: 'Cypress Inline Reporter',
|
||||||
|
reportFilename: '[status]_[datetime]-report',
|
||||||
|
embeddedScreenshots: true,
|
||||||
|
reportDir: 'test/cypress/reports',
|
||||||
|
inlineAssets: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
e2e: {
|
e2e: {
|
||||||
baseUrl: 'http://localhost:9000/',
|
baseUrl: `http://${urlHost}:9000`,
|
||||||
experimentalStudio: true,
|
experimentalStudio: false, // Desactivado para evitar tiempos de espera innecesarios
|
||||||
|
defaultCommandTimeout: 10000,
|
||||||
|
trashAssetsBeforeRuns: false,
|
||||||
|
requestTimeout: 10000,
|
||||||
|
responseTimeout: 30000,
|
||||||
|
pageLoadTimeout: 60000,
|
||||||
fixturesFolder: 'test/cypress/fixtures',
|
fixturesFolder: 'test/cypress/fixtures',
|
||||||
screenshotsFolder: 'test/cypress/screenshots',
|
screenshotsFolder: 'test/cypress/screenshots',
|
||||||
supportFile: 'test/cypress/support/index.js',
|
supportFile: 'test/cypress/support/index.js',
|
||||||
|
@ -14,29 +43,35 @@ export default defineConfig({
|
||||||
downloadsFolder: 'test/cypress/downloads',
|
downloadsFolder: 'test/cypress/downloads',
|
||||||
video: false,
|
video: false,
|
||||||
specPattern: 'test/cypress/integration/**/*.spec.js',
|
specPattern: 'test/cypress/integration/**/*.spec.js',
|
||||||
experimentalRunAllSpecs: false,
|
experimentalRunAllSpecs: true,
|
||||||
watchForFileChanges: false,
|
watchForFileChanges: true,
|
||||||
reporter: 'cypress-mochawesome-reporter',
|
reporter,
|
||||||
reporterOptions: {
|
reporterOptions,
|
||||||
charts: true,
|
|
||||||
reportPageTitle: 'Cypress Inline Reporter',
|
|
||||||
reportFilename: '[status]_[datetime]-report',
|
|
||||||
embeddedScreenshots: true,
|
|
||||||
reportDir: 'test/cypress/reports',
|
|
||||||
inlineAssets: true,
|
|
||||||
},
|
|
||||||
component: {
|
component: {
|
||||||
componentFolder: 'src',
|
componentFolder: 'src',
|
||||||
testFiles: '**/*.spec.js',
|
testFiles: '**/*.spec.js',
|
||||||
supportFile: 'test/cypress/support/unit.js',
|
supportFile: 'test/cypress/support/unit.js',
|
||||||
},
|
},/*
|
||||||
setupNodeEvents: async (on, config) => {
|
setupNodeEvents: async (on, config) => {
|
||||||
const plugin = await import('cypress-mochawesome-reporter/plugin');
|
const plugin = await import('cypress-mochawesome-reporter/plugin');
|
||||||
plugin.default(on);
|
plugin.default(on);
|
||||||
|
const fs = await import('fs');
|
||||||
|
on('task', {
|
||||||
|
deleteFile(filePath) {
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
fs.unlinkSync(filePath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},*/
|
||||||
viewportWidth: 1280,
|
viewportWidth: 1280,
|
||||||
viewportHeight: 720,
|
viewportHeight: 720,
|
||||||
},
|
},
|
||||||
|
experimentalMemoryManagement: true,
|
||||||
|
defaultCommandTimeout: 10000,
|
||||||
|
numTestsKeptInMemory: 2,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
version: '3.7'
|
|
||||||
services:
|
|
||||||
main:
|
|
||||||
image: registry.verdnatura.es/salix-frontend:${VERSION:?}
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: ./Dockerfile
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
FROM debian:12.9-slim
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
gnupg2 \
|
||||||
|
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||||
|
&& apt-get install -y --no-install-recommends nodejs \
|
||||||
|
&& npm install -g corepack@0.31.0 \
|
||||||
|
&& corepack enable pnpm \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get -y --no-install-recommends install \
|
||||||
|
apt-utils \
|
||||||
|
chromium \
|
||||||
|
libasound2 \
|
||||||
|
libgbm-dev \
|
||||||
|
libgtk-3-0 \
|
||||||
|
libgtk2.0-0 \
|
||||||
|
libnotify-dev \
|
||||||
|
libnss3 \
|
||||||
|
libxss1 \
|
||||||
|
libxtst6 \
|
||||||
|
xauth \
|
||||||
|
xvfb \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN groupadd -r -g 1000 app \
|
||||||
|
&& useradd -r -u 1000 -g app -m -d /home/app app
|
||||||
|
USER app
|
||||||
|
|
||||||
|
ENV SHELL=bash
|
||||||
|
ENV PNPM_HOME="/home/app/.local/share/pnpm"
|
||||||
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
|
|
||||||
|
RUN pnpm setup \
|
||||||
|
&& pnpm install --global cypress@13.6.6 \
|
||||||
|
&& cypress install
|
||||||
|
|
||||||
|
WORKDIR /app
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "25.08.0",
|
"version": "25.10.0",
|
||||||
"description": "Salix frontend",
|
"description": "Salix frontend",
|
||||||
"productName": "Salix",
|
"productName": "Salix",
|
||||||
"author": "Verdnatura",
|
"author": "Verdnatura",
|
||||||
|
@ -71,4 +71,4 @@
|
||||||
"vite": "^6.0.11",
|
"vite": "^6.0.11",
|
||||||
"vitest": "^0.31.1"
|
"vitest": "^0.31.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: '/api',
|
path: '/api',
|
||||||
rule: { target: 'http://0.0.0.0:3000' },
|
rule: { target: 'http://127.0.0.1:3000' },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
import { configure } from 'quasar/wrappers';
|
import { configure } from 'quasar/wrappers';
|
||||||
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
const target = `http://${process.env.CI ? 'back' : 'localhost'}:3000`;
|
||||||
|
|
||||||
export default configure(function (/* ctx */) {
|
export default configure(function (/* ctx */) {
|
||||||
return {
|
return {
|
||||||
|
@ -108,13 +109,17 @@ export default configure(function (/* ctx */) {
|
||||||
},
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://0.0.0.0:3000',
|
target: target,
|
||||||
logLevel: 'debug',
|
logLevel: 'debug',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
open: false,
|
open: false,
|
||||||
|
allowedHosts: [
|
||||||
|
'front', // Agrega este nombre de host
|
||||||
|
'localhost', // Opcional, para pruebas locales
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
||||||
|
|
|
@ -9,19 +9,19 @@ export default {
|
||||||
if (!form) return;
|
if (!form) return;
|
||||||
try {
|
try {
|
||||||
const inputsFormCard = form.querySelectorAll(
|
const inputsFormCard = form.querySelectorAll(
|
||||||
`input:not([disabled]):not([type="checkbox"])`
|
`input:not([disabled]):not([type="checkbox"])`,
|
||||||
);
|
);
|
||||||
if (inputsFormCard.length) {
|
if (inputsFormCard.length) {
|
||||||
focusFirstInput(inputsFormCard[0]);
|
focusFirstInput(inputsFormCard[0]);
|
||||||
}
|
}
|
||||||
const textareas = document.querySelectorAll(
|
const textareas = document.querySelectorAll(
|
||||||
'textarea:not([disabled]), [contenteditable]:not([disabled])'
|
'textarea:not([disabled]), [contenteditable]:not([disabled])',
|
||||||
);
|
);
|
||||||
if (textareas.length) {
|
if (textareas.length) {
|
||||||
focusFirstInput(textareas[textareas.length - 1]);
|
focusFirstInput(textareas[textareas.length - 1]);
|
||||||
}
|
}
|
||||||
const inputs = document.querySelectorAll(
|
const inputs = document.querySelectorAll(
|
||||||
'form#formModel input:not([disabled]):not([type="checkbox"])'
|
'form#formModel input:not([disabled]):not([type="checkbox"])',
|
||||||
);
|
);
|
||||||
const input = inputs[0];
|
const input = inputs[0];
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
|
@ -30,22 +30,5 @@ export default {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
form.addEventListener('keyup', function (evt) {
|
|
||||||
if (evt.key === 'Enter' && !that.$attrs['prevent-submit']) {
|
|
||||||
const input = evt.target;
|
|
||||||
if (input.type == 'textarea' && evt.shiftKey) {
|
|
||||||
evt.preventDefault();
|
|
||||||
let { selectionStart, selectionEnd } = input;
|
|
||||||
input.value =
|
|
||||||
input.value.substring(0, selectionStart) +
|
|
||||||
'\n' +
|
|
||||||
input.value.substring(selectionEnd);
|
|
||||||
selectionStart = selectionEnd = selectionStart + 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
evt.preventDefault();
|
|
||||||
that.onSubmit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import VnSelectProvince from 'src/components/VnSelectProvince.vue';
|
import VnSelectProvince from 'src/components/VnSelectProvince.vue';
|
||||||
|
@ -21,14 +20,11 @@ const postcodeFormData = reactive({
|
||||||
provinceFk: null,
|
provinceFk: null,
|
||||||
townFk: null,
|
townFk: null,
|
||||||
});
|
});
|
||||||
const townsFetchDataRef = ref(false);
|
|
||||||
const townFilter = ref({});
|
const townFilter = ref({});
|
||||||
|
|
||||||
const countriesRef = ref(false);
|
const countriesRef = ref(false);
|
||||||
const provincesOptions = ref([]);
|
const provincesOptions = ref([]);
|
||||||
const townsOptions = ref([]);
|
|
||||||
const town = ref({});
|
const town = ref({});
|
||||||
const countryFilter = ref({});
|
|
||||||
|
|
||||||
function onDataSaved(formData) {
|
function onDataSaved(formData) {
|
||||||
const newPostcode = {
|
const newPostcode = {
|
||||||
|
@ -51,7 +47,6 @@ async function setCountry(countryFk, data) {
|
||||||
data.townFk = null;
|
data.townFk = null;
|
||||||
data.provinceFk = null;
|
data.provinceFk = null;
|
||||||
data.countryFk = countryFk;
|
data.countryFk = countryFk;
|
||||||
await fetchTowns();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Province
|
// Province
|
||||||
|
@ -60,22 +55,11 @@ async function setProvince(id, data) {
|
||||||
const newProvince = provincesOptions.value.find((province) => province.id == id);
|
const newProvince = provincesOptions.value.find((province) => province.id == id);
|
||||||
if (newProvince) data.countryFk = newProvince.countryFk;
|
if (newProvince) data.countryFk = newProvince.countryFk;
|
||||||
postcodeFormData.provinceFk = id;
|
postcodeFormData.provinceFk = id;
|
||||||
await fetchTowns();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onProvinceCreated(data) {
|
async function onProvinceCreated(data) {
|
||||||
postcodeFormData.provinceFk = data.id;
|
postcodeFormData.provinceFk = data.id;
|
||||||
}
|
}
|
||||||
function provinceByCountry(countryFk = postcodeFormData.countryFk) {
|
|
||||||
return provincesOptions.value
|
|
||||||
.filter((province) => province.countryFk === countryFk)
|
|
||||||
.map(({ id }) => id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Town
|
|
||||||
async function handleTowns(data) {
|
|
||||||
townsOptions.value = data;
|
|
||||||
}
|
|
||||||
function setTown(newTown, data) {
|
function setTown(newTown, data) {
|
||||||
town.value = newTown;
|
town.value = newTown;
|
||||||
data.provinceFk = newTown?.provinceFk ?? newTown;
|
data.provinceFk = newTown?.provinceFk ?? newTown;
|
||||||
|
@ -88,18 +72,6 @@ async function onCityCreated(newTown, formData) {
|
||||||
formData.townFk = newTown;
|
formData.townFk = newTown;
|
||||||
setTown(newTown, formData);
|
setTown(newTown, formData);
|
||||||
}
|
}
|
||||||
async function fetchTowns(countryFk = postcodeFormData.countryFk) {
|
|
||||||
if (!countryFk) return;
|
|
||||||
const provinces = postcodeFormData.provinceFk
|
|
||||||
? [postcodeFormData.provinceFk]
|
|
||||||
: provinceByCountry();
|
|
||||||
townFilter.value.where = {
|
|
||||||
provinceFk: {
|
|
||||||
inq: provinces,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
await townsFetchDataRef.value?.fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function filterTowns(name) {
|
async function filterTowns(name) {
|
||||||
if (name !== '') {
|
if (name !== '') {
|
||||||
|
@ -108,22 +80,11 @@ async function filterTowns(name) {
|
||||||
like: `%${name}%`,
|
like: `%${name}%`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await townsFetchDataRef.value?.fetch();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
ref="townsFetchDataRef"
|
|
||||||
:sort-by="['name ASC']"
|
|
||||||
:limit="30"
|
|
||||||
:filter="townFilter"
|
|
||||||
@on-fetch="handleTowns"
|
|
||||||
auto-load
|
|
||||||
url="Towns/location"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormModelPopup
|
<FormModelPopup
|
||||||
url-create="postcodes"
|
url-create="postcodes"
|
||||||
model="postcode"
|
model="postcode"
|
||||||
|
@ -149,14 +110,13 @@ async function filterTowns(name) {
|
||||||
@filter="filterTowns"
|
@filter="filterTowns"
|
||||||
:tooltip="t('Create city')"
|
:tooltip="t('Create city')"
|
||||||
v-model="data.townFk"
|
v-model="data.townFk"
|
||||||
:options="townsOptions"
|
url="Towns/location"
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
:rules="validate('postcode.city')"
|
:rules="validate('postcode.city')"
|
||||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||||
:emit-value="false"
|
:emit-value="false"
|
||||||
required
|
required
|
||||||
data-cy="locationTown"
|
data-cy="locationTown"
|
||||||
|
sort-by="name ASC"
|
||||||
>
|
>
|
||||||
<template #option="{ itemProps, opt }">
|
<template #option="{ itemProps, opt }">
|
||||||
<QItem v-bind="itemProps">
|
<QItem v-bind="itemProps">
|
||||||
|
@ -197,16 +157,12 @@ async function filterTowns(name) {
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
ref="countriesRef"
|
ref="countriesRef"
|
||||||
:limit="30"
|
|
||||||
:filter="countryFilter"
|
|
||||||
:sort-by="['name ASC']"
|
:sort-by="['name ASC']"
|
||||||
auto-load
|
auto-load
|
||||||
url="Countries"
|
url="Countries"
|
||||||
required
|
required
|
||||||
:label="t('Country')"
|
:label="t('Country')"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
v-model="data.countryFk"
|
v-model="data.countryFk"
|
||||||
:rules="validate('postcode.countryFk')"
|
:rules="validate('postcode.countryFk')"
|
||||||
@update:model-value="(value) => setCountry(value, data)"
|
@update:model-value="(value) => setCountry(value, data)"
|
||||||
|
|
|
@ -62,12 +62,9 @@ const where = computed(() => {
|
||||||
auto-load
|
auto-load
|
||||||
:where="where"
|
:where="where"
|
||||||
url="Autonomies/location"
|
url="Autonomies/location"
|
||||||
:sort-by="['name ASC']"
|
sort-by="name ASC"
|
||||||
:limit="30"
|
|
||||||
:label="t('Autonomy')"
|
:label="t('Autonomy')"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
v-model="data.autonomyFk"
|
v-model="data.autonomyFk"
|
||||||
:rules="validate('province.autonomyFk')"
|
:rules="validate('province.autonomyFk')"
|
||||||
>
|
>
|
||||||
|
|
|
@ -42,7 +42,6 @@ const itemFilter = {
|
||||||
const itemFilterParams = reactive({});
|
const itemFilterParams = reactive({});
|
||||||
const closeButton = ref(null);
|
const closeButton = ref(null);
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const producersOptions = ref([]);
|
|
||||||
const ItemTypesOptions = ref([]);
|
const ItemTypesOptions = ref([]);
|
||||||
const InksOptions = ref([]);
|
const InksOptions = ref([]);
|
||||||
const tableRows = ref([]);
|
const tableRows = ref([]);
|
||||||
|
@ -121,23 +120,17 @@ const selectItem = ({ id }) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
url="Producers"
|
|
||||||
@on-fetch="(data) => (producersOptions = data)"
|
|
||||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
<FetchData
|
||||||
url="ItemTypes"
|
url="ItemTypes"
|
||||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||||
order="name"
|
order="name ASC"
|
||||||
@on-fetch="(data) => (ItemTypesOptions = data)"
|
@on-fetch="(data) => (ItemTypesOptions = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Inks"
|
url="Inks"
|
||||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||||
order="name"
|
order="name ASC"
|
||||||
@on-fetch="(data) => (InksOptions = data)"
|
@on-fetch="(data) => (InksOptions = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
|
@ -152,11 +145,11 @@ const selectItem = ({ id }) => {
|
||||||
<VnInput :label="t('entry.buys.size')" v-model="itemFilterParams.size" />
|
<VnInput :label="t('entry.buys.size')" v-model="itemFilterParams.size" />
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('globals.producer')"
|
:label="t('globals.producer')"
|
||||||
:options="producersOptions"
|
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
v-model="itemFilterParams.producerFk"
|
v-model="itemFilterParams.producerFk"
|
||||||
|
url="Producers"
|
||||||
|
:fields="['id', 'name']"
|
||||||
|
sort-by="name ASC"
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('globals.type')"
|
:label="t('globals.type')"
|
||||||
|
|
|
@ -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', limit: 30 }"
|
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { onMounted, onUnmounted, computed, ref, watch, nextTick } from 'vue';
|
import { onMounted, onUnmounted, computed, ref, watch, nextTick, useAttrs } from 'vue';
|
||||||
import { onBeforeRouteLeave, useRouter, useRoute } from 'vue-router';
|
import { onBeforeRouteLeave, useRouter, useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
@ -12,6 +12,7 @@ import SkeletonForm from 'components/ui/SkeletonForm.vue';
|
||||||
import VnConfirm from './ui/VnConfirm.vue';
|
import VnConfirm from './ui/VnConfirm.vue';
|
||||||
import { tMobile } from 'src/composables/tMobile';
|
import { tMobile } from 'src/composables/tMobile';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
import { getDifferences, getUpdatedValues } from 'src/filters';
|
||||||
|
|
||||||
const { push } = useRouter();
|
const { push } = useRouter();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
@ -22,6 +23,7 @@ const { validate } = useValidator();
|
||||||
const { notify } = useNotify();
|
const { notify } = useNotify();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const myForm = ref(null);
|
const myForm = ref(null);
|
||||||
|
const attrs = useAttrs();
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
url: {
|
url: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -106,14 +108,14 @@ const isLoading = ref(false);
|
||||||
const isResetting = ref(false);
|
const isResetting = ref(false);
|
||||||
const hasChanges = ref(!$props.observeFormChanges);
|
const hasChanges = ref(!$props.observeFormChanges);
|
||||||
const originalData = computed(() => state.get(modelValue));
|
const originalData = computed(() => state.get(modelValue));
|
||||||
const formData = ref({});
|
const formData = ref();
|
||||||
const defaultButtons = computed(() => ({
|
const defaultButtons = computed(() => ({
|
||||||
save: {
|
save: {
|
||||||
dataCy: 'saveDefaultBtn',
|
dataCy: 'saveDefaultBtn',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
icon: 'save',
|
icon: 'save',
|
||||||
label: 'globals.save',
|
label: 'globals.save',
|
||||||
click: () => myForm.value.submit(),
|
click: async () => await save(),
|
||||||
type: 'submit',
|
type: 'submit',
|
||||||
},
|
},
|
||||||
reset: {
|
reset: {
|
||||||
|
@ -134,7 +136,8 @@ onMounted(async () => {
|
||||||
|
|
||||||
if (!$props.formInitialData) {
|
if (!$props.formInitialData) {
|
||||||
if ($props.autoLoad && $props.url) await fetch();
|
if ($props.autoLoad && $props.url) await fetch();
|
||||||
else if (arrayData.store.data) updateAndEmit('onFetch', arrayData.store.data);
|
else if (arrayData.store.data)
|
||||||
|
updateAndEmit('onFetch', { val: arrayData.store.data });
|
||||||
}
|
}
|
||||||
if ($props.observeFormChanges) {
|
if ($props.observeFormChanges) {
|
||||||
watch(
|
watch(
|
||||||
|
@ -154,7 +157,7 @@ onMounted(async () => {
|
||||||
if (!$props.url)
|
if (!$props.url)
|
||||||
watch(
|
watch(
|
||||||
() => arrayData.store.data,
|
() => arrayData.store.data,
|
||||||
(val) => updateAndEmit('onFetch', val),
|
(val) => updateAndEmit('onFetch', { val }),
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -200,7 +203,7 @@ async function fetch() {
|
||||||
});
|
});
|
||||||
if (Array.isArray(data)) data = data[0] ?? {};
|
if (Array.isArray(data)) data = data[0] ?? {};
|
||||||
|
|
||||||
updateAndEmit('onFetch', data);
|
updateAndEmit('onFetch', { val: data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
state.set(modelValue, {});
|
state.set(modelValue, {});
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -227,7 +230,11 @@ async function save() {
|
||||||
|
|
||||||
if ($props.urlCreate) notify('globals.dataCreated', 'positive');
|
if ($props.urlCreate) notify('globals.dataCreated', 'positive');
|
||||||
|
|
||||||
updateAndEmit('onDataSaved', formData.value, response?.data);
|
updateAndEmit('onDataSaved', {
|
||||||
|
val: formData.value,
|
||||||
|
res: response?.data,
|
||||||
|
old: originalData.value,
|
||||||
|
});
|
||||||
if ($props.reload) await arrayData.fetch({});
|
if ($props.reload) await arrayData.fetch({});
|
||||||
hasChanges.value = false;
|
hasChanges.value = false;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -242,7 +249,7 @@ async function saveAndGo() {
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
formData.value = JSON.parse(JSON.stringify(originalData.value));
|
formData.value = JSON.parse(JSON.stringify(originalData.value));
|
||||||
updateAndEmit('onFetch', originalData.value);
|
updateAndEmit('onFetch', { val: originalData.value });
|
||||||
if ($props.observeFormChanges) {
|
if ($props.observeFormChanges) {
|
||||||
hasChanges.value = false;
|
hasChanges.value = false;
|
||||||
isResetting.value = true;
|
isResetting.value = true;
|
||||||
|
@ -264,11 +271,11 @@ function filter(value, update, filterOptions) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAndEmit(evt, val, res) {
|
function updateAndEmit(evt, { val, res, old } = { val: null, res: null, old: null }) {
|
||||||
state.set(modelValue, val);
|
state.set(modelValue, val);
|
||||||
if (!$props.url) arrayData.store.data = val;
|
if (!$props.url) arrayData.store.data = val;
|
||||||
|
|
||||||
emit(evt, state.get(modelValue), res);
|
emit(evt, state.get(modelValue), res, old);
|
||||||
}
|
}
|
||||||
|
|
||||||
function trimData(data) {
|
function trimData(data) {
|
||||||
|
@ -278,6 +285,27 @@ function trimData(data) {
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
function onBeforeSave(formData, originalData) {
|
||||||
|
return getUpdatedValues(
|
||||||
|
Object.keys(getDifferences(formData, originalData)),
|
||||||
|
formData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async function onKeyup(evt) {
|
||||||
|
if (evt.key === 'Enter' && !('prevent-submit' in attrs)) {
|
||||||
|
const input = evt.target;
|
||||||
|
if (input.type == 'textarea' && evt.shiftKey) {
|
||||||
|
let { selectionStart, selectionEnd } = input;
|
||||||
|
input.value =
|
||||||
|
input.value.substring(0, selectionStart) +
|
||||||
|
'\n' +
|
||||||
|
input.value.substring(selectionEnd);
|
||||||
|
selectionStart = selectionEnd = selectionStart + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
save,
|
save,
|
||||||
|
@ -293,12 +321,13 @@ defineExpose({
|
||||||
<QForm
|
<QForm
|
||||||
ref="myForm"
|
ref="myForm"
|
||||||
v-if="formData"
|
v-if="formData"
|
||||||
@submit="save"
|
@submit.prevent
|
||||||
|
@keyup.prevent="onKeyup"
|
||||||
@reset="reset"
|
@reset="reset"
|
||||||
class="q-pa-md"
|
class="q-pa-md"
|
||||||
:style="maxWidth ? 'max-width: ' + maxWidth : ''"
|
:style="maxWidth ? 'max-width: ' + maxWidth : ''"
|
||||||
id="formModel"
|
id="formModel"
|
||||||
:prevent-submit="$attrs['prevent-submit']"
|
:mapper="onBeforeSave"
|
||||||
>
|
>
|
||||||
<QCard>
|
<QCard>
|
||||||
<slot
|
<slot
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
|
@ -27,10 +27,15 @@ const formModelRef = ref(null);
|
||||||
const closeButton = ref(null);
|
const closeButton = ref(null);
|
||||||
const isSaveAndContinue = ref(false);
|
const isSaveAndContinue = ref(false);
|
||||||
const onDataSaved = (formData, requestResponse) => {
|
const onDataSaved = (formData, requestResponse) => {
|
||||||
if (closeButton.value && isSaveAndContinue) closeButton.value.click();
|
if (closeButton.value && !isSaveAndContinue.value) closeButton.value.click();
|
||||||
emit('onDataSaved', formData, requestResponse);
|
emit('onDataSaved', formData, requestResponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onClick = async (saveAndContinue) => {
|
||||||
|
isSaveAndContinue.value = saveAndContinue;
|
||||||
|
await formModelRef.value.save();
|
||||||
|
};
|
||||||
|
|
||||||
const isLoading = computed(() => formModelRef.value?.isLoading);
|
const isLoading = computed(() => formModelRef.value?.isLoading);
|
||||||
const reset = computed(() => formModelRef.value?.reset);
|
const reset = computed(() => formModelRef.value?.reset);
|
||||||
|
|
||||||
|
@ -58,19 +63,6 @@ defineExpose({
|
||||||
<p>{{ subtitle }}</p>
|
<p>{{ subtitle }}</p>
|
||||||
<slot name="form-inputs" :data="data" :validate="validate" />
|
<slot name="form-inputs" :data="data" :validate="validate" />
|
||||||
<div class="q-mt-lg row justify-end">
|
<div class="q-mt-lg row justify-end">
|
||||||
<QBtn
|
|
||||||
v-if="showSaveAndContinueBtn"
|
|
||||||
:label="t('globals.isSaveAndContinue')"
|
|
||||||
:title="t('globals.isSaveAndContinue')"
|
|
||||||
type="submit"
|
|
||||||
color="primary"
|
|
||||||
class="q-ml-sm"
|
|
||||||
:disabled="isLoading"
|
|
||||||
:loading="isLoading"
|
|
||||||
data-cy="FormModelPopup_isSaveAndContinue"
|
|
||||||
z-max
|
|
||||||
@click="() => (isSaveAndContinue = true)"
|
|
||||||
/>
|
|
||||||
<QBtn
|
<QBtn
|
||||||
:label="t('globals.cancel')"
|
:label="t('globals.cancel')"
|
||||||
:title="t('globals.cancel')"
|
:title="t('globals.cancel')"
|
||||||
|
@ -83,23 +75,33 @@ defineExpose({
|
||||||
v-close-popup
|
v-close-popup
|
||||||
z-max
|
z-max
|
||||||
@click="
|
@click="
|
||||||
() => {
|
isSaveAndContinue = false;
|
||||||
isSaveAndContinue = false;
|
emit('onDataCanceled');
|
||||||
emit('onDataCanceled');
|
|
||||||
}
|
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
:flat="showSaveAndContinueBtn"
|
||||||
:label="t('globals.save')"
|
:label="t('globals.save')"
|
||||||
:title="t('globals.save')"
|
:title="t('globals.save')"
|
||||||
type="submit"
|
@click="onClick(false)"
|
||||||
color="primary"
|
color="primary"
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
data-cy="FormModelPopup_save"
|
data-cy="FormModelPopup_save"
|
||||||
z-max
|
z-max
|
||||||
@click="() => (isSaveAndContinue = false)"
|
/>
|
||||||
|
<QBtn
|
||||||
|
v-if="showSaveAndContinueBtn"
|
||||||
|
:label="t('globals.isSaveAndContinue')"
|
||||||
|
:title="t('globals.isSaveAndContinue')"
|
||||||
|
color="primary"
|
||||||
|
class="q-ml-sm"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:loading="isLoading"
|
||||||
|
data-cy="FormModelPopup_isSaveAndContinue"
|
||||||
|
z-max
|
||||||
|
@click="onClick(true)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -121,23 +121,25 @@ const removeTag = (index, params, search) => {
|
||||||
applyTags(params, search);
|
applyTags(params, search);
|
||||||
};
|
};
|
||||||
const setCategoryList = (data) => {
|
const setCategoryList = (data) => {
|
||||||
categoryList.value = (data || [])
|
categoryList.value = (data || []).map((category) => ({
|
||||||
.filter((category) => category.display)
|
...category,
|
||||||
.map((category) => ({
|
icon: `vn:${(category.icon || '').split('-')[1]}`,
|
||||||
...category,
|
}));
|
||||||
icon: `vn:${(category.icon || '').split('-')[1]}`,
|
|
||||||
}));
|
|
||||||
fetchItemTypes();
|
fetchItemTypes();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData url="ItemCategories" limit="30" auto-load @on-fetch="setCategoryList" />
|
<FetchData
|
||||||
|
url="ItemCategories"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="setCategoryList"
|
||||||
|
:where="{ display: { neq: 0 } }"
|
||||||
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Tags"
|
url="Tags"
|
||||||
:filter="{ fields: ['id', 'name', 'isFree'] }"
|
:filter="{ fields: ['id', 'name', 'isFree'] }"
|
||||||
auto-load
|
auto-load
|
||||||
limit="30"
|
|
||||||
@on-fetch="(data) => (tagOptions = data)"
|
@on-fetch="(data) => (tagOptions = data)"
|
||||||
/>
|
/>
|
||||||
<VnFilterPanel
|
<VnFilterPanel
|
||||||
|
@ -195,8 +197,6 @@ const setCategoryList = (data) => {
|
||||||
:label="t('components.itemsFilterPanel.typeFk')"
|
:label="t('components.itemsFilterPanel.typeFk')"
|
||||||
v-model="params.typeFk"
|
v-model="params.typeFk"
|
||||||
:options="itemTypesOptions"
|
:options="itemTypesOptions"
|
||||||
option-value="id"
|
|
||||||
option-label="name"
|
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
@ -234,7 +234,6 @@ const setCategoryList = (data) => {
|
||||||
:label="t('globals.tag')"
|
:label="t('globals.tag')"
|
||||||
v-model="value.selectedTag"
|
v-model="value.selectedTag"
|
||||||
:options="tagOptions"
|
:options="tagOptions"
|
||||||
option-label="name"
|
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
|
|
@ -85,7 +85,15 @@ const refresh = () => window.location.reload();
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
<PinnedModules ref="pinnedModulesRef" />
|
<PinnedModules ref="pinnedModulesRef" />
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QBtn class="q-pa-none" rounded dense flat no-wrap id="user">
|
<QBtn
|
||||||
|
class="q-pa-none"
|
||||||
|
rounded
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
no-wrap
|
||||||
|
id="user"
|
||||||
|
data-cy="userPanel_btn"
|
||||||
|
>
|
||||||
<VnAvatar
|
<VnAvatar
|
||||||
:worker-id="user.id"
|
:worker-id="user.id"
|
||||||
:title="user.name"
|
:title="user.name"
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { toCurrency } from 'src/filters';
|
||||||
|
|
||||||
defineProps({ row: { type: Object, required: true } });
|
defineProps({ row: { type: Object, required: true } });
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<span class="q-gutter-x-xs">
|
<span class="q-gutter-x-xs">
|
||||||
|
<router-link
|
||||||
|
v-if="row.claim?.claimFk"
|
||||||
|
:to="{ name: 'ClaimBasicData', params: { id: row.claim?.claimFk } }"
|
||||||
|
class="link"
|
||||||
|
>
|
||||||
|
<QIcon name="vn:claims" size="xs">
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('ticketSale.claim') }}:
|
||||||
|
{{ row.claim?.claimFk }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</router-link>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row?.risk"
|
v-if="row?.risk"
|
||||||
name="vn:risk"
|
name="vn:risk"
|
||||||
|
@ -10,7 +24,8 @@ defineProps({ row: { type: Object, required: true } });
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ $t('salesTicketsTable.risk') }}: {{ row.risk - row.credit }}
|
{{ $t('salesTicketsTable.risk') }}:
|
||||||
|
{{ toCurrency(row.risk - row.credit) }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
@ -53,7 +68,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 === 0"
|
v-if="row?.isTaxDataChecked !== 0"
|
||||||
name="vn:no036"
|
name="vn:no036"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { markRaw, computed } from 'vue';
|
import { markRaw, computed } from 'vue';
|
||||||
import { QIcon, QCheckbox, QToggle } from 'quasar';
|
import { QIcon, QToggle } from 'quasar';
|
||||||
import { dashIfEmpty } from 'src/filters';
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
|
|
|
@ -152,7 +152,7 @@ const onTabPressed = async () => {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div v-if="showFilter" class="full-width flex-center" style="overflow: hidden">
|
<div v-if="showFilter" class="full-width" style="overflow: hidden">
|
||||||
<VnColumn
|
<VnColumn
|
||||||
:column="$props.column"
|
:column="$props.column"
|
||||||
default="input"
|
default="input"
|
||||||
|
|
|
@ -23,6 +23,10 @@ const $props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
align: {
|
||||||
|
type: String,
|
||||||
|
default: 'end',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const hover = ref();
|
const hover = ref();
|
||||||
const arrayData = useArrayData($props.dataKey, { searchUrl: $props.searchUrl });
|
const arrayData = useArrayData($props.dataKey, { searchUrl: $props.searchUrl });
|
||||||
|
@ -46,16 +50,27 @@ async function orderBy(name, direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ orderBy });
|
defineExpose({ orderBy });
|
||||||
|
|
||||||
|
function textAlignToFlex(textAlign) {
|
||||||
|
return `justify-content: ${
|
||||||
|
{
|
||||||
|
'text-center': 'center',
|
||||||
|
'text-left': 'start',
|
||||||
|
'text-right': 'end',
|
||||||
|
}[textAlign] || 'start'
|
||||||
|
};`;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
@mouseenter="hover = true"
|
@mouseenter="hover = true"
|
||||||
@mouseleave="hover = false"
|
@mouseleave="hover = false"
|
||||||
@click="orderBy(name, model?.direction)"
|
@click="orderBy(name, model?.direction)"
|
||||||
class="row items-center no-wrap cursor-pointer title"
|
class="items-center no-wrap cursor-pointer title"
|
||||||
|
:style="textAlignToFlex(align)"
|
||||||
>
|
>
|
||||||
<span :title="label">{{ label }}</span>
|
<span :title="label">{{ label }}</span>
|
||||||
<sup v-if="name && model?.index">
|
<div v-if="name && model?.index">
|
||||||
<QChip
|
<QChip
|
||||||
:label="!vertical ? model?.index : ''"
|
:label="!vertical ? model?.index : ''"
|
||||||
:icon="
|
:icon="
|
||||||
|
@ -92,20 +107,16 @@ defineExpose({ orderBy });
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</QChip>
|
</QChip>
|
||||||
</sup>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.title {
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: var(--vn-label-color);
|
color: var(--vn-label-color);
|
||||||
}
|
white-space: nowrap;
|
||||||
sup {
|
|
||||||
vertical-align: super; /* Valor predeterminado */
|
|
||||||
/* También puedes usar otros valores como "baseline", "top", "text-top", etc. */
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,14 +10,15 @@ import {
|
||||||
render,
|
render,
|
||||||
inject,
|
inject,
|
||||||
useAttrs,
|
useAttrs,
|
||||||
|
nextTick,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar, date } from 'quasar';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import { useFilterParams } from 'src/composables/useFilterParams';
|
import { useFilterParams } from 'src/composables/useFilterParams';
|
||||||
import { dashIfEmpty } from 'src/filters';
|
import { dashIfEmpty, toDate } from 'src/filters';
|
||||||
|
|
||||||
import CrudModel from 'src/components/CrudModel.vue';
|
import CrudModel from 'src/components/CrudModel.vue';
|
||||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
|
@ -164,7 +165,6 @@ const app = inject('app');
|
||||||
const editingRow = ref(null);
|
const editingRow = ref(null);
|
||||||
const editingField = ref(null);
|
const editingField = ref(null);
|
||||||
const isTableMode = computed(() => mode.value == TABLE_MODE);
|
const isTableMode = computed(() => mode.value == TABLE_MODE);
|
||||||
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
|
|
||||||
const selectRegex = /select/;
|
const selectRegex = /select/;
|
||||||
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
|
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
|
||||||
const tableModes = [
|
const tableModes = [
|
||||||
|
@ -340,11 +340,12 @@ const clickHandler = async (event) => {
|
||||||
|
|
||||||
const isDateElement = event.target.closest('.q-date');
|
const isDateElement = event.target.closest('.q-date');
|
||||||
const isTimeElement = event.target.closest('.q-time');
|
const isTimeElement = event.target.closest('.q-time');
|
||||||
|
const isQselectDropDown = event.target.closest('.q-select__dropdown-icon');
|
||||||
|
|
||||||
if (isDateElement || isTimeElement) return;
|
if (isDateElement || isTimeElement || isQselectDropDown) return;
|
||||||
|
|
||||||
if (clickedElement === null) {
|
if (clickedElement === null) {
|
||||||
destroyInput(editingRow.value, editingField.value);
|
await destroyInput(editingRow.value, editingField.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rowIndex = clickedElement.getAttribute('data-row-index');
|
const rowIndex = clickedElement.getAttribute('data-row-index');
|
||||||
|
@ -352,19 +353,19 @@ const clickHandler = async (event) => {
|
||||||
const column = $props.columns.find((col) => col.name === colField);
|
const column = $props.columns.find((col) => col.name === colField);
|
||||||
|
|
||||||
if (editingRow.value !== null && editingField.value !== null) {
|
if (editingRow.value !== null && editingField.value !== null) {
|
||||||
if (editingRow.value === rowIndex && editingField.value === colField) {
|
if (editingRow.value == rowIndex && editingField.value == colField) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyInput(editingRow.value, editingField.value);
|
await destroyInput(editingRow.value, editingField.value);
|
||||||
}
|
}
|
||||||
if (isEditableColumn(column))
|
|
||||||
|
if (isEditableColumn(column)) {
|
||||||
await renderInput(Number(rowIndex), colField, clickedElement);
|
await renderInput(Number(rowIndex), colField, clickedElement);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleTabKey(event, rowIndex, colField) {
|
async function handleTabKey(event, rowIndex, colField) {
|
||||||
if (editingRow.value == rowIndex && editingField.value == colField)
|
if (editingRow.value == rowIndex && editingField.value == colField)
|
||||||
destroyInput(editingRow.value, editingField.value);
|
await destroyInput(editingRow.value, editingField.value);
|
||||||
|
|
||||||
const direction = event.shiftKey ? -1 : 1;
|
const direction = event.shiftKey ? -1 : 1;
|
||||||
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
|
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
|
||||||
|
@ -411,7 +412,7 @@ async function renderInput(rowId, field, clickedElement) {
|
||||||
focusOnMount: true,
|
focusOnMount: true,
|
||||||
eventHandlers: {
|
eventHandlers: {
|
||||||
'update:modelValue': async (value) => {
|
'update:modelValue': async (value) => {
|
||||||
if (isSelect) {
|
if (isSelect && value) {
|
||||||
row[column.name] = value[column.attrs?.optionValue ?? 'id'];
|
row[column.name] = value[column.attrs?.optionValue ?? 'id'];
|
||||||
row[column?.name + 'TextValue'] =
|
row[column?.name + 'TextValue'] =
|
||||||
value[column.attrs?.optionLabel ?? 'name'];
|
value[column.attrs?.optionLabel ?? 'name'];
|
||||||
|
@ -424,7 +425,8 @@ async function renderInput(rowId, field, clickedElement) {
|
||||||
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
|
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
|
||||||
},
|
},
|
||||||
keyup: async (event) => {
|
keyup: async (event) => {
|
||||||
if (event.key === 'Enter') handleBlur(rowId, field, clickedElement);
|
if (event.key === 'Enter')
|
||||||
|
await destroyInput(rowIndex, field, clickedElement);
|
||||||
},
|
},
|
||||||
keydown: async (event) => {
|
keydown: async (event) => {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
|
@ -433,7 +435,7 @@ async function renderInput(rowId, field, clickedElement) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
break;
|
break;
|
||||||
case 'Escape':
|
case 'Escape':
|
||||||
destroyInput(rowId, field, clickedElement);
|
await destroyInput(rowId, field, clickedElement);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -448,16 +450,20 @@ async function renderInput(rowId, field, clickedElement) {
|
||||||
node.appContext = app._context;
|
node.appContext = app._context;
|
||||||
render(node, clickedElement);
|
render(node, clickedElement);
|
||||||
|
|
||||||
if (['checkbox', 'toggle', undefined].includes(column?.component))
|
if (['toggle'].includes(column?.component))
|
||||||
node.el?.querySelector('span > div').focus();
|
node.el?.querySelector('span > div').focus();
|
||||||
|
|
||||||
|
if (['checkbox', undefined].includes(column?.component))
|
||||||
|
node.el?.querySelector('span > div > div').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function destroyInput(rowIndex, field, clickedElement) {
|
async function destroyInput(rowIndex, field, clickedElement) {
|
||||||
if (!clickedElement)
|
if (!clickedElement)
|
||||||
clickedElement = document.querySelector(
|
clickedElement = document.querySelector(
|
||||||
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
|
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
|
||||||
);
|
);
|
||||||
if (clickedElement) {
|
if (clickedElement) {
|
||||||
|
await nextTick();
|
||||||
render(null, clickedElement);
|
render(null, clickedElement);
|
||||||
Array.from(clickedElement.childNodes).forEach((child) => {
|
Array.from(clickedElement.childNodes).forEach((child) => {
|
||||||
child.style.visibility = 'visible';
|
child.style.visibility = 'visible';
|
||||||
|
@ -469,10 +475,6 @@ function destroyInput(rowIndex, field, clickedElement) {
|
||||||
editingField.value = null;
|
editingField.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBlur(rowIndex, field, clickedElement) {
|
|
||||||
destroyInput(rowIndex, field, clickedElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleTabNavigation(rowIndex, colName, direction) {
|
async function handleTabNavigation(rowIndex, colName, direction) {
|
||||||
const columns = $props.columns;
|
const columns = $props.columns;
|
||||||
const totalColumns = columns.length;
|
const totalColumns = columns.length;
|
||||||
|
@ -488,9 +490,7 @@ async function handleTabNavigation(rowIndex, colName, direction) {
|
||||||
if (isEditableColumn(columns[newColumnIndex])) break;
|
if (isEditableColumn(columns[newColumnIndex])) break;
|
||||||
} while (iterations < totalColumns);
|
} while (iterations < totalColumns);
|
||||||
|
|
||||||
if (iterations >= totalColumns) {
|
if (iterations >= totalColumns + 1) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (direction === 1 && newColumnIndex <= currentColumnIndex) {
|
if (direction === 1 && newColumnIndex <= currentColumnIndex) {
|
||||||
rowIndex++;
|
rowIndex++;
|
||||||
|
@ -519,17 +519,44 @@ function getToggleIcon(value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatColumnValue(col, row, dashIfEmpty) {
|
function formatColumnValue(col, row, dashIfEmpty) {
|
||||||
if (col?.format) {
|
if (col?.format || row[col?.name + 'TextValue']) {
|
||||||
if (selectRegex.test(col?.component) && row[col?.name + 'TextValue']) {
|
if (selectRegex.test(col?.component) && row[col?.name + 'TextValue']) {
|
||||||
return dashIfEmpty(row[col?.name + 'TextValue']);
|
return dashIfEmpty(row[col?.name + 'TextValue']);
|
||||||
} else {
|
} else {
|
||||||
return col.format(row, dashIfEmpty);
|
return col.format(row, dashIfEmpty);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return dashIfEmpty(row[col?.name]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (col?.component === 'date') return dashIfEmpty(toDate(row[col?.name]));
|
||||||
|
|
||||||
|
if (col?.component === 'time')
|
||||||
|
return row[col?.name] >= 5
|
||||||
|
? dashIfEmpty(date.formatDate(new Date(row[col?.name]), 'HH:mm'))
|
||||||
|
: row[col?.name];
|
||||||
|
|
||||||
|
if (selectRegex.test(col?.component) && $props.isEditable) {
|
||||||
|
const { find, url } = col.attrs;
|
||||||
|
const urlRelation = url?.charAt(0)?.toLocaleLowerCase() + url?.slice(1, -1);
|
||||||
|
|
||||||
|
if (col?.attrs.options) {
|
||||||
|
const find = col?.attrs.options.find((option) => option.id === row[col.name]);
|
||||||
|
if (!col.attrs?.optionLabel || !find) return dashIfEmpty(row[col?.name]);
|
||||||
|
return dashIfEmpty(find[col.attrs?.optionLabel ?? 'name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof row[urlRelation] == 'object') {
|
||||||
|
if (typeof find == 'object')
|
||||||
|
return dashIfEmpty(row[urlRelation][find?.label ?? 'name']);
|
||||||
|
|
||||||
|
return dashIfEmpty(row[urlRelation][col?.attrs.optionLabel ?? 'name']);
|
||||||
|
}
|
||||||
|
if (typeof row[urlRelation] == 'string') return dashIfEmpty(row[urlRelation]);
|
||||||
|
}
|
||||||
|
return dashIfEmpty(row[col?.name]);
|
||||||
|
}
|
||||||
|
function cardClick(_, row) {
|
||||||
|
if ($props.redirect) router.push({ path: `/${$props.redirect}/${row.id}` });
|
||||||
}
|
}
|
||||||
const checkbox = ref(null);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QDrawer
|
<QDrawer
|
||||||
|
@ -593,6 +620,7 @@ const checkbox = ref(null);
|
||||||
@row-click="(_, row) => rowClickFunction && rowClickFunction(row)"
|
@row-click="(_, row) => rowClickFunction && rowClickFunction(row)"
|
||||||
@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"
|
||||||
>
|
>
|
||||||
<template #top-left v-if="!$props.withoutHeader">
|
<template #top-left v-if="!$props.withoutHeader">
|
||||||
<slot name="top-left"> </slot>
|
<slot name="top-left"> </slot>
|
||||||
|
@ -612,29 +640,21 @@ const checkbox = ref(null);
|
||||||
dense
|
dense
|
||||||
:options="tableModes.filter((mode) => !mode.disable)"
|
:options="tableModes.filter((mode) => !mode.disable)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<QBtn
|
|
||||||
v-if="showRightIcon"
|
|
||||||
icon="filter_alt"
|
|
||||||
class="bg-vn-section-color q-ml-sm"
|
|
||||||
dense
|
|
||||||
@click="stateStore.toggleRightDrawer()"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template #header-cell="{ col }">
|
<template #header-cell="{ col }">
|
||||||
<QTh
|
<QTh
|
||||||
v-if="col.visible ?? true"
|
v-if="col.visible ?? true"
|
||||||
|
v-bind:class="col.headerClass"
|
||||||
class="body-cell"
|
class="body-cell"
|
||||||
:style="col?.width ? `max-width: ${col?.width}` : ''"
|
:style="col?.width ? `max-width: ${col?.width}` : ''"
|
||||||
style="padding: inherit"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="no-padding"
|
class="no-padding"
|
||||||
:style="
|
:style="[
|
||||||
withFilters && $props.columnSearch ? 'height: 75px' : ''
|
withFilters && $props.columnSearch ? 'height: 75px' : '',
|
||||||
"
|
]"
|
||||||
>
|
>
|
||||||
<div class="text-center" style="height: 30px">
|
<div style="height: 30px">
|
||||||
<QTooltip v-if="col.toolTip">{{ col.toolTip }}</QTooltip>
|
<QTooltip v-if="col.toolTip">{{ col.toolTip }}</QTooltip>
|
||||||
<VnTableOrder
|
<VnTableOrder
|
||||||
v-model="orders[col.orderBy ?? col.name]"
|
v-model="orders[col.orderBy ?? col.name]"
|
||||||
|
@ -642,6 +662,7 @@ const checkbox = ref(null);
|
||||||
:label="col?.labelAbbreviation ?? col?.label"
|
:label="col?.labelAbbreviation ?? col?.label"
|
||||||
:data-key="$attrs['data-key']"
|
:data-key="$attrs['data-key']"
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
|
:align="getColAlign(col)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<VnFilter
|
<VnFilter
|
||||||
|
@ -723,7 +744,11 @@ const checkbox = ref(null);
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
:class="hasEditableFormat(col)"
|
:class="hasEditableFormat(col)"
|
||||||
:style="col?.style ? col.style(row) : null"
|
:style="
|
||||||
|
typeof col?.style == 'function'
|
||||||
|
? col.style(row)
|
||||||
|
: col?.style
|
||||||
|
"
|
||||||
style="bottom: 0"
|
style="bottom: 0"
|
||||||
>
|
>
|
||||||
{{ formatColumnValue(col, row, dashIfEmpty) }}
|
{{ formatColumnValue(col, row, dashIfEmpty) }}
|
||||||
|
@ -750,7 +775,7 @@ const checkbox = ref(null);
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
:class="
|
:class="
|
||||||
btn.isPrimary ? 'text-primary-light' : 'color-vn-text '
|
btn.isPrimary ? 'text-primary-light' : 'color-vn-label'
|
||||||
"
|
"
|
||||||
:style="`visibility: ${
|
:style="`visibility: ${
|
||||||
((btn.show && btn.show(row)) ?? true)
|
((btn.show && btn.show(row)) ?? true)
|
||||||
|
@ -758,23 +783,19 @@ const checkbox = ref(null);
|
||||||
: 'hidden'
|
: 'hidden'
|
||||||
}`"
|
}`"
|
||||||
@click="btn.action(row)"
|
@click="btn.action(row)"
|
||||||
|
:data-cy="btn?.name ?? `tableAction-${index}`"
|
||||||
/>
|
/>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #item="{ row, colsMap }">
|
<template #item="{ row, colsMap }">
|
||||||
<component
|
<component
|
||||||
:is="$props.redirect ? 'router-link' : 'span'"
|
v-bind:is="'div'"
|
||||||
:to="`/${$props.redirect}/` + row.id"
|
@click="(event) => cardClick(event, row)"
|
||||||
>
|
>
|
||||||
<QCard
|
<QCard
|
||||||
bordered
|
bordered
|
||||||
flat
|
flat
|
||||||
class="row no-wrap justify-between cursor-pointer q-pa-sm"
|
class="row no-wrap justify-between cursor-pointer q-pa-sm"
|
||||||
@click="
|
|
||||||
(_, row) => {
|
|
||||||
$props.rowClick && $props.rowClick(row);
|
|
||||||
}
|
|
||||||
"
|
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
>
|
>
|
||||||
<QCardSection
|
<QCardSection
|
||||||
|
@ -811,7 +832,7 @@ const checkbox = ref(null);
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<!-- Fields -->
|
<!-- Fields -->
|
||||||
<QCardSection
|
<QCardSection
|
||||||
class="q-pl-sm q-pr-lg q-py-xs"
|
class="q-pl-sm q-py-xs"
|
||||||
:class="$props.cardClass"
|
:class="$props.cardClass"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -858,13 +879,14 @@ const checkbox = ref(null);
|
||||||
:key="index"
|
:key="index"
|
||||||
:title="btn.title"
|
:title="btn.title"
|
||||||
:icon="btn.icon"
|
:icon="btn.icon"
|
||||||
|
data-cy="cardBtn"
|
||||||
class="q-pa-xs"
|
class="q-pa-xs"
|
||||||
flat
|
|
||||||
:class="
|
:class="
|
||||||
btn.isPrimary
|
btn.isPrimary
|
||||||
? 'text-primary-light'
|
? 'text-primary-light'
|
||||||
: 'color-vn-text '
|
: 'color-vn-label'
|
||||||
"
|
"
|
||||||
|
flat
|
||||||
@click="btn.action(row)"
|
@click="btn.action(row)"
|
||||||
/>
|
/>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
|
@ -1022,8 +1044,8 @@ es:
|
||||||
}
|
}
|
||||||
|
|
||||||
.body-cell {
|
.body-cell {
|
||||||
padding-left: 2px !important;
|
padding-left: 4px !important;
|
||||||
padding-right: 2px !important;
|
padding-right: 4px !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.bg-chip-secondary {
|
.bg-chip-secondary {
|
||||||
|
@ -1042,8 +1064,8 @@ es:
|
||||||
|
|
||||||
.grid-three {
|
.grid-three {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
|
grid-template-columns: repeat(auto-fit, minmax(300px, max-content));
|
||||||
max-width: 100%;
|
width: 100%;
|
||||||
grid-gap: 20px;
|
grid-gap: 20px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
@ -1117,6 +1139,7 @@ es:
|
||||||
.vn-label-value {
|
.vn-label-value {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
color: var(--vn-text-color);
|
color: var(--vn-text-color);
|
||||||
.value {
|
.value {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -57,6 +57,7 @@ describe('FormModel', () => {
|
||||||
vm.state.set(model, formInitialData);
|
vm.state.set(model, formInitialData);
|
||||||
expect(vm.hasChanges).toBe(false);
|
expect(vm.hasChanges).toBe(false);
|
||||||
|
|
||||||
|
await vm.$nextTick();
|
||||||
vm.formData.mockKey = 'newVal';
|
vm.formData.mockKey = 'newVal';
|
||||||
await vm.$nextTick();
|
await vm.$nextTick();
|
||||||
expect(vm.hasChanges).toBe(true);
|
expect(vm.hasChanges).toBe(true);
|
||||||
|
@ -94,8 +95,12 @@ describe('FormModel', () => {
|
||||||
it('should call axios.patch with the right data', async () => {
|
it('should call axios.patch with the right data', async () => {
|
||||||
const spy = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} });
|
const spy = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} });
|
||||||
const { vm } = mount({ propsData: { url, model } });
|
const { vm } = mount({ propsData: { url, model } });
|
||||||
vm.formData.mockKey = 'newVal';
|
|
||||||
|
vm.formData = {};
|
||||||
await vm.$nextTick();
|
await vm.$nextTick();
|
||||||
|
vm.formData = { mockKey: 'newVal' };
|
||||||
|
await vm.$nextTick();
|
||||||
|
|
||||||
await vm.save();
|
await vm.save();
|
||||||
expect(spy).toHaveBeenCalled();
|
expect(spy).toHaveBeenCalled();
|
||||||
vm.formData.mockKey = 'mockVal';
|
vm.formData.mockKey = 'mockVal';
|
||||||
|
|
|
@ -39,6 +39,13 @@ onBeforeMount(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
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);
|
||||||
});
|
});
|
||||||
|
@ -50,6 +57,9 @@ 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>
|
||||||
<Teleport to="#left-panel" v-if="stateStore.isHeaderMounted()">
|
<Teleport to="#left-panel" v-if="stateStore.isHeaderMounted()">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
colors: {
|
colors: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '{"value":[]}',
|
default: '{"value": []}',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ const maxHeight = 30;
|
||||||
const colorHeight = maxHeight / colorArray?.length;
|
const colorHeight = maxHeight / colorArray?.length;
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="color-div" :style="{ height: `${maxHeight}px` }">
|
<div v-if="colors" class="color-div" :style="{ height: `${maxHeight}px` }">
|
||||||
<div
|
<div
|
||||||
v-for="(color, index) in colorArray"
|
v-for="(color, index) in colorArray"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
|
|
@ -48,7 +48,8 @@ function toValueAttrs(attrs) {
|
||||||
<span
|
<span
|
||||||
v-for="toComponent of componentArray"
|
v-for="toComponent of componentArray"
|
||||||
:key="toComponent.name"
|
:key="toComponent.name"
|
||||||
class="column flex-center fit"
|
class="column fit"
|
||||||
|
:class="toComponent?.component == 'checkbox' ? 'flex-center' : ''"
|
||||||
>
|
>
|
||||||
<component
|
<component
|
||||||
v-if="toComponent?.component"
|
v-if="toComponent?.component"
|
||||||
|
|
|
@ -107,6 +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'"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
|
|
@ -85,6 +85,7 @@ const handleModelValue = (data) => {
|
||||||
:tooltip="t('Create new location')"
|
:tooltip="t('Create new location')"
|
||||||
:rules="mixinRules"
|
:rules="mixinRules"
|
||||||
:lazy-rules="true"
|
:lazy-rules="true"
|
||||||
|
required
|
||||||
>
|
>
|
||||||
<template #form>
|
<template #form>
|
||||||
<CreateNewPostcode
|
<CreateNewPostcode
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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 } from 'vue-router';
|
||||||
|
import { useClipboard } from 'src/composables/useClipboard';
|
||||||
import VnMoreOptions from './VnMoreOptions.vue';
|
import VnMoreOptions from './VnMoreOptions.vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -29,10 +30,6 @@ const $props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
module: {
|
|
||||||
type: String,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
summary: {
|
summary: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
|
@ -46,6 +43,7 @@ const $props = defineProps({
|
||||||
const state = useState();
|
const state = useState();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const { copyText } = useClipboard();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
let arrayData;
|
let arrayData;
|
||||||
let store;
|
let store;
|
||||||
|
@ -103,6 +101,14 @@ function getValueFromPath(path) {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function copyIdText(id) {
|
||||||
|
copyText(id, {
|
||||||
|
component: {
|
||||||
|
copyValue: id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['onFetch']);
|
const emit = defineEmits(['onFetch']);
|
||||||
|
|
||||||
const iconModule = computed(() => route.matched[1].meta.icon);
|
const iconModule = computed(() => route.matched[1].meta.icon);
|
||||||
|
@ -148,7 +154,9 @@ const toModule = computed(() =>
|
||||||
{{ t('components.smartCard.openSummary') }}
|
{{ t('components.smartCard.openSummary') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<RouterLink :to="{ name: `${module}Summary`, params: { id: entity.id } }">
|
<RouterLink
|
||||||
|
:to="{ name: `${dataKey}Summary`, params: { id: entity.id } }"
|
||||||
|
>
|
||||||
<QBtn
|
<QBtn
|
||||||
class="link"
|
class="link"
|
||||||
color="white"
|
color="white"
|
||||||
|
@ -184,10 +192,25 @@ const toModule = computed(() =>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
<QItem dense>
|
<QItem>
|
||||||
<QItemLabel class="subtitle" caption>
|
<QItemLabel class="subtitle">
|
||||||
#{{ getValueFromPath(subtitle) ?? entity.id }}
|
#{{ getValueFromPath(subtitle) ?? entity.id }}
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
|
|
||||||
|
<QBtn
|
||||||
|
round
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
size="sm"
|
||||||
|
icon="content_copy"
|
||||||
|
color="primary"
|
||||||
|
@click.stop="copyIdText(entity.id)"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('globals.copyId') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<!-- </QItemLabel> -->
|
||||||
</QItem>
|
</QItem>
|
||||||
</QList>
|
</QList>
|
||||||
<div class="list-box q-mt-xs">
|
<div class="list-box q-mt-xs">
|
||||||
|
@ -294,3 +317,11 @@ const toModule = computed(() =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
globals:
|
||||||
|
copyId: Copy ID
|
||||||
|
es:
|
||||||
|
globals:
|
||||||
|
copyId: Copiar ID
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -53,3 +53,8 @@ const manaCode = ref(props.manaCode);
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Promotion mana: Maná promoción
|
||||||
|
Claim mana: Maná reclamación
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
|
import { useRequired } from '../useRequired';
|
||||||
|
|
||||||
|
vi.mock('../useValidator', () => ({
|
||||||
|
useValidator: () => ({
|
||||||
|
validations: () => ({
|
||||||
|
required: vi.fn((isRequired, val) => {
|
||||||
|
if (!isRequired) return true;
|
||||||
|
return val !== null && val !== undefined && val !== '';
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('useRequired', () => {
|
||||||
|
it('should detect required when attr is boolean true', () => {
|
||||||
|
const attrs = { required: true };
|
||||||
|
const { isRequired } = useRequired(attrs);
|
||||||
|
expect(isRequired).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect required when attr is boolean false', () => {
|
||||||
|
const attrs = { required: false };
|
||||||
|
const { isRequired } = useRequired(attrs);
|
||||||
|
expect(isRequired).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect required when attr exists without value', () => {
|
||||||
|
const attrs = { required: '' };
|
||||||
|
const { isRequired } = useRequired(attrs);
|
||||||
|
expect(isRequired).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when required attr does not exist', () => {
|
||||||
|
const attrs = { someOtherAttr: 'value' };
|
||||||
|
const { isRequired } = useRequired(attrs);
|
||||||
|
expect(isRequired).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('requiredFieldRule', () => {
|
||||||
|
it('should validate required field with value', () => {
|
||||||
|
const attrs = { required: true };
|
||||||
|
const { requiredFieldRule } = useRequired(attrs);
|
||||||
|
expect(requiredFieldRule('some value')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should validate required field with empty value', () => {
|
||||||
|
const attrs = { required: true };
|
||||||
|
const { requiredFieldRule } = useRequired(attrs);
|
||||||
|
expect(requiredFieldRule('')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass validation when field is not required', () => {
|
||||||
|
const attrs = { required: false };
|
||||||
|
const { requiredFieldRule } = useRequired(attrs);
|
||||||
|
expect(requiredFieldRule('')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle null and undefined values', () => {
|
||||||
|
const attrs = { required: true };
|
||||||
|
const { requiredFieldRule } = useRequired(attrs);
|
||||||
|
expect(requiredFieldRule(null)).toBe(false);
|
||||||
|
expect(requiredFieldRule(undefined)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,13 +1,14 @@
|
||||||
export function getColAlign(col) {
|
export function getColAlign(col) {
|
||||||
let align;
|
let align;
|
||||||
switch (col.component) {
|
switch (col.component) {
|
||||||
|
case 'time':
|
||||||
|
case 'date':
|
||||||
case 'select':
|
case 'select':
|
||||||
align = 'left';
|
align = 'left';
|
||||||
break;
|
break;
|
||||||
case 'number':
|
case 'number':
|
||||||
align = 'right';
|
align = 'right';
|
||||||
break;
|
break;
|
||||||
case 'date':
|
|
||||||
case 'checkbox':
|
case 'checkbox':
|
||||||
align = 'center';
|
align = 'center';
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,6 +11,7 @@ export async function useCau(res, message) {
|
||||||
const { config, headers, request, status, statusText, data } = res || {};
|
const { config, headers, request, status, statusText, data } = res || {};
|
||||||
const { params, url, method, signal, headers: confHeaders } = config || {};
|
const { params, url, method, signal, headers: confHeaders } = config || {};
|
||||||
const { message: resMessage, code, name } = data?.error || {};
|
const { message: resMessage, code, name } = data?.error || {};
|
||||||
|
delete confHeaders?.Authorization;
|
||||||
|
|
||||||
const additionalData = {
|
const additionalData = {
|
||||||
path: location.hash,
|
path: location.hash,
|
||||||
|
@ -40,7 +41,7 @@ export async function useCau(res, message) {
|
||||||
handler: async () => {
|
handler: async () => {
|
||||||
const locale = i18n.global.t;
|
const locale = i18n.global.t;
|
||||||
const reason = ref(
|
const reason = ref(
|
||||||
code == 'ACCESS_DENIED' ? locale('cau.askPrivileges') : ''
|
code == 'ACCESS_DENIED' ? locale('cau.askPrivileges') : '',
|
||||||
);
|
);
|
||||||
openConfirmationModal(
|
openConfirmationModal(
|
||||||
locale('cau.title'),
|
locale('cau.title'),
|
||||||
|
@ -59,10 +60,9 @@ export async function useCau(res, message) {
|
||||||
'onUpdate:modelValue': (val) => (reason.value = val),
|
'onUpdate:modelValue': (val) => (reason.value = val),
|
||||||
label: locale('cau.inputLabel'),
|
label: locale('cau.inputLabel'),
|
||||||
class: 'full-width',
|
class: 'full-width',
|
||||||
required: true,
|
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,14 +2,10 @@ import { useValidator } from 'src/composables/useValidator';
|
||||||
|
|
||||||
export function useRequired($attrs) {
|
export function useRequired($attrs) {
|
||||||
const { validations } = useValidator();
|
const { validations } = useValidator();
|
||||||
const hasRequired = Object.keys($attrs).includes('required');
|
const isRequired =
|
||||||
let isRequired = false;
|
typeof $attrs['required'] === 'boolean'
|
||||||
if (hasRequired) {
|
? $attrs['required']
|
||||||
const required = $attrs['required'];
|
: Object.keys($attrs).includes('required');
|
||||||
if (typeof required === 'boolean') {
|
|
||||||
isRequired = required;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const requiredFieldRule = (val) => validations().required(isRequired, val);
|
const requiredFieldRule = (val) => validations().required(isRequired, val);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -335,3 +335,7 @@ input::-webkit-inner-spin-button {
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
box-shadow: 0 4px 6px #00000000;
|
box-shadow: 0 4px 6px #00000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.containerShrinked {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { useI18n } from 'vue-i18n';
|
||||||
export default function (value, options = {}) {
|
export default function (value, options = {}) {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
|
|
||||||
|
if (!isValidDate(value)) return null;
|
||||||
|
|
||||||
if (!options.dateStyle && !options.timeStyle) {
|
if (!options.dateStyle && !options.timeStyle) {
|
||||||
options.day = '2-digit';
|
options.day = '2-digit';
|
||||||
options.month = '2-digit';
|
options.month = '2-digit';
|
||||||
|
@ -10,7 +12,12 @@ export default function (value, options = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { locale } = useI18n();
|
const { locale } = useI18n();
|
||||||
const date = new Date(value);
|
const newDate = new Date(value);
|
||||||
|
|
||||||
return new Intl.DateTimeFormat(locale.value, options).format(date);
|
return new Intl.DateTimeFormat(locale.value, options).format(newDate);
|
||||||
|
}
|
||||||
|
// handle 0000-00-00
|
||||||
|
function isValidDate(date) {
|
||||||
|
const parsedDate = new Date(date);
|
||||||
|
return parsedDate instanceof Date && !isNaN(parsedDate.getTime());
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ globals:
|
||||||
rowRemoved: Row removed
|
rowRemoved: Row removed
|
||||||
pleaseWait: Please wait...
|
pleaseWait: Please wait...
|
||||||
noPinnedModules: You don't have any pinned modules
|
noPinnedModules: You don't have any pinned modules
|
||||||
|
enterToConfirm: Press Enter to confirm
|
||||||
summary:
|
summary:
|
||||||
basicData: Basic data
|
basicData: Basic data
|
||||||
daysOnward: Days onward
|
daysOnward: Days onward
|
||||||
|
@ -156,6 +157,7 @@ globals:
|
||||||
changeState: Change state
|
changeState: Change state
|
||||||
raid: 'Raid {daysInForward} days'
|
raid: 'Raid {daysInForward} days'
|
||||||
isVies: Vies
|
isVies: Vies
|
||||||
|
noData: No data available
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Login
|
logIn: Login
|
||||||
addressEdit: Update address
|
addressEdit: Update address
|
||||||
|
@ -829,6 +831,8 @@ travel:
|
||||||
CloneTravelAndEntries: Clone travel and his entries
|
CloneTravelAndEntries: Clone travel and his entries
|
||||||
deleteTravel: Delete travel
|
deleteTravel: Delete travel
|
||||||
AddEntry: Add entry
|
AddEntry: Add entry
|
||||||
|
availabled: Availabled
|
||||||
|
availabledHour: Availabled hour
|
||||||
thermographs: Thermographs
|
thermographs: Thermographs
|
||||||
hb: HB
|
hb: HB
|
||||||
basicData:
|
basicData:
|
||||||
|
|
|
@ -51,6 +51,7 @@ globals:
|
||||||
pleaseWait: Por favor espera...
|
pleaseWait: Por favor espera...
|
||||||
noPinnedModules: No has fijado ningún módulo
|
noPinnedModules: No has fijado ningún módulo
|
||||||
split: Split
|
split: Split
|
||||||
|
enterToConfirm: Pulsa Enter para confirmar
|
||||||
summary:
|
summary:
|
||||||
basicData: Datos básicos
|
basicData: Datos básicos
|
||||||
daysOnward: Días adelante
|
daysOnward: Días adelante
|
||||||
|
@ -160,6 +161,7 @@ globals:
|
||||||
changeState: Cambiar estado
|
changeState: Cambiar estado
|
||||||
raid: 'Redada {daysInForward} días'
|
raid: 'Redada {daysInForward} días'
|
||||||
isVies: Vies
|
isVies: Vies
|
||||||
|
noData: Datos no disponibles
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Inicio de sesión
|
logIn: Inicio de sesión
|
||||||
addressEdit: Modificar consignatario
|
addressEdit: Modificar consignatario
|
||||||
|
@ -838,6 +840,7 @@ supplier:
|
||||||
verified: Verificado
|
verified: Verificado
|
||||||
isActive: Está activo
|
isActive: Está activo
|
||||||
billingData: Forma de pago
|
billingData: Forma de pago
|
||||||
|
financialData: Datos financieros
|
||||||
payDeadline: Plazo de pago
|
payDeadline: Plazo de pago
|
||||||
payDay: Día de pago
|
payDay: Día de pago
|
||||||
account: Cuenta
|
account: Cuenta
|
||||||
|
@ -915,6 +918,8 @@ travel:
|
||||||
deleteTravel: Eliminar envío
|
deleteTravel: Eliminar envío
|
||||||
AddEntry: Añadir entrada
|
AddEntry: Añadir entrada
|
||||||
thermographs: Termógrafos
|
thermographs: Termógrafos
|
||||||
|
availabled: F. Disponible
|
||||||
|
availabledHour: Hora Disponible
|
||||||
hb: HB
|
hb: HB
|
||||||
basicData:
|
basicData:
|
||||||
daysInForward: Desplazamiento automatico (redada)
|
daysInForward: Desplazamiento automatico (redada)
|
||||||
|
|
|
@ -51,7 +51,6 @@ const removeAlias = () => {
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
ref="descriptor"
|
ref="descriptor"
|
||||||
:url="`MailAliases/${entityId}`"
|
:url="`MailAliases/${entityId}`"
|
||||||
module="Alias"
|
|
||||||
data-key="Alias"
|
data-key="Alias"
|
||||||
title="alias"
|
title="alias"
|
||||||
>
|
>
|
||||||
|
|
|
@ -24,7 +24,6 @@ onMounted(async () => {
|
||||||
ref="descriptor"
|
ref="descriptor"
|
||||||
:url="`VnUsers/preview`"
|
:url="`VnUsers/preview`"
|
||||||
:filter="{ ...filter, where: { id: entityId } }"
|
:filter="{ ...filter, where: { id: entityId } }"
|
||||||
module="Account"
|
|
||||||
data-key="Account"
|
data-key="Account"
|
||||||
title="nickname"
|
title="nickname"
|
||||||
>
|
>
|
||||||
|
|
|
@ -35,6 +35,12 @@ account.value.hasAccount = hasAccount.value;
|
||||||
const entityId = computed(() => +route.params.id);
|
const entityId = computed(() => +route.params.id);
|
||||||
const hasitManagementAccess = ref();
|
const hasitManagementAccess = ref();
|
||||||
const hasSysadminAccess = ref();
|
const hasSysadminAccess = ref();
|
||||||
|
const isHimself = computed(() => user.value.id === account.value.id);
|
||||||
|
const url = computed(() =>
|
||||||
|
isHimself.value
|
||||||
|
? 'Accounts/change-password'
|
||||||
|
: `Accounts/${entityId.value}/setPassword`
|
||||||
|
);
|
||||||
|
|
||||||
async function updateStatusAccount(active) {
|
async function updateStatusAccount(active) {
|
||||||
if (active) {
|
if (active) {
|
||||||
|
@ -107,11 +113,8 @@ onMounted(() => {
|
||||||
:ask-old-pass="askOldPass"
|
:ask-old-pass="askOldPass"
|
||||||
:submit-fn="
|
:submit-fn="
|
||||||
async (newPassword, oldPassword) => {
|
async (newPassword, oldPassword) => {
|
||||||
await axios.patch(`Accounts/change-password`, {
|
const body = isHimself ? { userId: entityId, oldPassword } : {};
|
||||||
userId: entityId,
|
await axios.patch(url, { ...body, newPassword });
|
||||||
newPassword,
|
|
||||||
oldPassword,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
@ -155,16 +158,10 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<QItemSection>{{ t('globals.delete') }}</QItemSection>
|
<QItemSection>{{ t('globals.delete') }}</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem
|
<QItem v-if="hasSysadminAccess || isHimself" v-ripple clickable>
|
||||||
v-if="hasSysadminAccess"
|
<QItemSection @click="onChangePass(isHimself)">
|
||||||
v-ripple
|
{{ isHimself ? t('globals.changePass') : t('globals.setPass') }}
|
||||||
clickable
|
|
||||||
@click="user.id === account.id ? onChangePass(true) : onChangePass(false)"
|
|
||||||
>
|
|
||||||
<QItemSection v-if="user.id === account.id">
|
|
||||||
{{ t('globals.changePass') }}
|
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
<QItemSection v-else>{{ t('globals.setPass') }}</QItemSection>
|
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem
|
<QItem
|
||||||
v-if="!account.hasAccount && hasSysadminAccess"
|
v-if="!account.hasAccount && hasSysadminAccess"
|
||||||
|
|
|
@ -35,7 +35,6 @@ const removeRole = async () => {
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
url="VnRoles"
|
url="VnRoles"
|
||||||
:filter="{ where: { id: entityId } }"
|
:filter="{ where: { id: entityId } }"
|
||||||
module="Role"
|
|
||||||
data-key="Role"
|
data-key="Role"
|
||||||
:summary="$props.summary"
|
:summary="$props.summary"
|
||||||
>
|
>
|
||||||
|
|
|
@ -46,7 +46,6 @@ onMounted(async () => {
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
:url="`Claims/${entityId}`"
|
:url="`Claims/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
module="Claim"
|
|
||||||
title="client.name"
|
title="client.name"
|
||||||
data-key="Claim"
|
data-key="Claim"
|
||||||
>
|
>
|
||||||
|
|
|
@ -190,7 +190,7 @@ async function saveWhenHasChanges() {
|
||||||
ref="claimLinesForm"
|
ref="claimLinesForm"
|
||||||
:url="`Claims/${route.params.id}/lines`"
|
:url="`Claims/${route.params.id}/lines`"
|
||||||
save-url="ClaimBeginnings/crud"
|
save-url="ClaimBeginnings/crud"
|
||||||
:filter="linesFilter"
|
:user-filter="linesFilter"
|
||||||
@on-fetch="onFetch"
|
@on-fetch="onFetch"
|
||||||
v-model:selected="selected"
|
v-model:selected="selected"
|
||||||
:default-save="false"
|
:default-save="false"
|
||||||
|
|
|
@ -156,7 +156,6 @@ function onDrag() {
|
||||||
url="Claims"
|
url="Claims"
|
||||||
:filter="claimDmsFilter"
|
:filter="claimDmsFilter"
|
||||||
@on-fetch="([data]) => setClaimDms(data)"
|
@on-fetch="([data]) => setClaimDms(data)"
|
||||||
limit="20"
|
|
||||||
auto-load
|
auto-load
|
||||||
ref="claimDmsRef"
|
ref="claimDmsRef"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
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';
|
||||||
|
@ -14,15 +12,14 @@ const props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
states: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const states = ref([]);
|
|
||||||
|
|
||||||
defineExpose({ states });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData url="ClaimStates" @on-fetch="(data) => (states = data)" auto-load />
|
|
||||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
|
|
|
@ -10,12 +10,13 @@ import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
import ZoneDescriptorProxy from '../Zone/Card/ZoneDescriptorProxy.vue';
|
import ZoneDescriptorProxy from '../Zone/Card/ZoneDescriptorProxy.vue';
|
||||||
import VnSection from 'src/components/common/VnSection.vue';
|
import VnSection from 'src/components/common/VnSection.vue';
|
||||||
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
const dataKey = 'ClaimList';
|
const dataKey = 'ClaimList';
|
||||||
|
|
||||||
const claimFilterRef = ref();
|
const states = ref([]);
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -81,8 +82,7 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('claim.state'),
|
label: t('claim.state'),
|
||||||
format: ({ stateCode }) =>
|
format: ({ stateCode }) =>
|
||||||
claimFilterRef.value?.states.find(({ code }) => code === stateCode)
|
states.value?.find(({ code }) => code === stateCode)?.description,
|
||||||
?.description,
|
|
||||||
name: 'stateCode',
|
name: 'stateCode',
|
||||||
chip: {
|
chip: {
|
||||||
condition: () => true,
|
condition: () => true,
|
||||||
|
@ -92,7 +92,7 @@ const columns = computed(() => [
|
||||||
name: 'claimStateFk',
|
name: 'claimStateFk',
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
options: claimFilterRef.value?.states,
|
options: states.value,
|
||||||
optionLabel: 'description',
|
optionLabel: 'description',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -125,6 +125,7 @@ const STATE_COLOR = {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<FetchData url="ClaimStates" @on-fetch="(data) => (states = data)" auto-load />
|
||||||
<VnSection
|
<VnSection
|
||||||
:data-key="dataKey"
|
:data-key="dataKey"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
@ -135,7 +136,7 @@ const STATE_COLOR = {
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #advanced-menu>
|
<template #advanced-menu>
|
||||||
<ClaimFilter data-key="ClaimList" ref="claimFilterRef" />
|
<ClaimFilter :data-key ref="claimFilterRef" :states />
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<VnTable
|
<VnTable
|
||||||
|
|
|
@ -17,8 +17,7 @@ const bankEntitiesRef = ref(null);
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
fields: ['id', 'bic', 'name'],
|
fields: ['id', 'bic', 'name'],
|
||||||
order: 'bic ASC',
|
order: 'bic ASC'
|
||||||
limit: 30,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBankEntities = (data, formData) => {
|
const getBankEntities = (data, formData) => {
|
||||||
|
|
|
@ -232,7 +232,6 @@ const updateDateParams = (value, params) => {
|
||||||
:include="'category'"
|
:include="'category'"
|
||||||
:sortBy="'name ASC'"
|
:sortBy="'name ASC'"
|
||||||
dense
|
dense
|
||||||
@update:model-value="(data) => updateDateParams(data, params)"
|
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
|
@ -254,7 +253,6 @@ const updateDateParams = (value, params) => {
|
||||||
:fields="['id', 'name']"
|
:fields="['id', 'name']"
|
||||||
:sortBy="'name ASC'"
|
:sortBy="'name ASC'"
|
||||||
dense
|
dense
|
||||||
@update:model-value="(data) => updateDateParams(data, params)"
|
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
v-model="params.campaign"
|
v-model="params.campaign"
|
||||||
|
@ -303,12 +301,14 @@ en:
|
||||||
valentinesDay: Valentine's Day
|
valentinesDay: Valentine's Day
|
||||||
mothersDay: Mother's Day
|
mothersDay: Mother's Day
|
||||||
allSaints: All Saints' Day
|
allSaints: All Saints' Day
|
||||||
|
frenchMothersDay: Mother's Day in France
|
||||||
es:
|
es:
|
||||||
Enter a new search: Introduce una nueva búsqueda
|
Enter a new search: Introduce una nueva búsqueda
|
||||||
Group by items: Agrupar por artículos
|
Group by items: Agrupar por artículos
|
||||||
valentinesDay: Día de San Valentín
|
valentinesDay: Día de San Valentín
|
||||||
mothersDay: Día de la Madre
|
mothersDay: Día de la Madre
|
||||||
allSaints: Día de Todos los Santos
|
allSaints: Día de Todos los Santos
|
||||||
|
frenchMothersDay: (Francia) Día de la Madre
|
||||||
Campaign consumption: Consumo campaña
|
Campaign consumption: Consumo campaña
|
||||||
Campaign: Campaña
|
Campaign: Campaña
|
||||||
From: Desde
|
From: Desde
|
||||||
|
|
|
@ -55,7 +55,6 @@ const debtWarning = computed(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Customer"
|
|
||||||
:url="`Clients/${entityId}/getCard`"
|
:url="`Clients/${entityId}/getCard`"
|
||||||
:summary="$props.summary"
|
:summary="$props.summary"
|
||||||
data-key="Customer"
|
data-key="Customer"
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
@ -10,9 +13,13 @@ 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 VnLocation from 'src/components/common/VnLocation.vue';
|
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||||
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
|
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
|
||||||
|
import { getDifferences, getUpdatedValues } from 'src/filters';
|
||||||
|
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||||
|
|
||||||
|
const quasar = useQuasar();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const { notify } = useNotify();
|
||||||
|
|
||||||
const typesTaxes = ref([]);
|
const typesTaxes = ref([]);
|
||||||
const typesTransactions = ref([]);
|
const typesTransactions = ref([]);
|
||||||
|
@ -24,6 +31,37 @@ function handleLocation(data, location) {
|
||||||
data.provinceFk = provinceFk;
|
data.provinceFk = provinceFk;
|
||||||
data.countryFk = countryFk;
|
data.countryFk = countryFk;
|
||||||
}
|
}
|
||||||
|
function onBeforeSave(formData, originalData) {
|
||||||
|
return getUpdatedValues(
|
||||||
|
Object.keys(getDifferences(formData, originalData)),
|
||||||
|
formData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkEtChanges(data, _, originalData) {
|
||||||
|
const equalizatedHasChanged = originalData.isEqualizated != data.isEqualizated;
|
||||||
|
const hasToInvoiceByAddress =
|
||||||
|
originalData.hasToInvoiceByAddress || data.hasToInvoiceByAddress;
|
||||||
|
if (equalizatedHasChanged && hasToInvoiceByAddress) {
|
||||||
|
quasar.dialog({
|
||||||
|
component: VnConfirm,
|
||||||
|
componentProps: {
|
||||||
|
title: t('You changed the equalization tax'),
|
||||||
|
message: t('Do you want to spread the change?'),
|
||||||
|
promise: () => acceptPropagate(data),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (equalizatedHasChanged) {
|
||||||
|
await acceptPropagate(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function acceptPropagate({ isEqualizated }) {
|
||||||
|
await axios.patch(`Clients/${route.params.id}/addressesPropagateRe`, {
|
||||||
|
isEqualizated,
|
||||||
|
});
|
||||||
|
notify(t('Equivalent tax spreaded'), 'warning');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -37,6 +75,9 @@ function handleLocation(data, location) {
|
||||||
:url-update="`Clients/${route.params.id}/updateFiscalData`"
|
:url-update="`Clients/${route.params.id}/updateFiscalData`"
|
||||||
auto-load
|
auto-load
|
||||||
model="Customer"
|
model="Customer"
|
||||||
|
:mapper="onBeforeSave"
|
||||||
|
observe-form-changes
|
||||||
|
@on-data-saved="checkEtChanges"
|
||||||
>
|
>
|
||||||
<template #form="{ data, validate }">
|
<template #form="{ data, validate }">
|
||||||
<VnRow>
|
<VnRow>
|
||||||
|
@ -114,7 +155,7 @@ function handleLocation(data, location) {
|
||||||
<VnCheckbox
|
<VnCheckbox
|
||||||
v-model="data.isVies"
|
v-model="data.isVies"
|
||||||
:label="t('globals.isVies')"
|
:label="t('globals.isVies')"
|
||||||
:info="t('whenActivatingIt')"
|
:info="t('whenActivatingIt')"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
|
@ -127,7 +168,7 @@ function handleLocation(data, location) {
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnCheckbox
|
<VnCheckbox
|
||||||
v-model="data.isEqualizated"
|
v-model="data.isEqualizated"
|
||||||
:label="t('Is equalizated')"
|
:label="t('Is equalizated')"
|
||||||
:info="t('inOrderToInvoice')"
|
:info="t('inOrderToInvoice')"
|
||||||
|
@ -172,6 +213,9 @@ es:
|
||||||
whenActivatingIt: Al activarlo, no informar el código del país en el campo nif
|
whenActivatingIt: Al activarlo, no informar el código del país en el campo nif
|
||||||
inOrderToInvoice: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automaticamente el cambio a todos lo consignatarios, en caso contrario preguntará al usuario si quiere o no propagar
|
inOrderToInvoice: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automaticamente el cambio a todos lo consignatarios, en caso contrario preguntará al usuario si quiere o no propagar
|
||||||
Daily invoice: Facturación diaria
|
Daily invoice: Facturación diaria
|
||||||
|
Equivalent tax spreaded: Recargo de equivalencia propagado
|
||||||
|
You changed the equalization tax: Has cambiado el recargo de equivalencia
|
||||||
|
Do you want to spread the change?: ¿Deseas propagar el cambio a sus consignatarios?
|
||||||
en:
|
en:
|
||||||
onlyLetters: Only letters, numbers and spaces can be used
|
onlyLetters: Only letters, numbers and spaces can be used
|
||||||
whenActivatingIt: When activating it, do not enter the country code in the ID field
|
whenActivatingIt: When activating it, do not enter the country code in the ID field
|
||||||
|
|
|
@ -270,7 +270,7 @@ const sumRisk = ({ clientRisks }) => {
|
||||||
<VnTitle
|
<VnTitle
|
||||||
target="_blank"
|
target="_blank"
|
||||||
:url="`${grafanaUrl}/d/40buzE4Vk/comportamiento-pagos-clientes?orgId=1&var-clientFk=${entityId}`"
|
:url="`${grafanaUrl}/d/40buzE4Vk/comportamiento-pagos-clientes?orgId=1&var-clientFk=${entityId}`"
|
||||||
:text="t('customer.summary.payMethodFk')"
|
:text="t('customer.summary.financialData')"
|
||||||
icon="vn:grafana"
|
icon="vn:grafana"
|
||||||
/>
|
/>
|
||||||
<VnLv
|
<VnLv
|
||||||
|
|
|
@ -87,7 +87,7 @@ onMounted(async () => {
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Campaigns/latest"
|
url="Campaigns/latest"
|
||||||
@on-fetch="(data) => (campaignsOptions = data)"
|
@on-fetch="(data) => (campaignsOptions = data)"
|
||||||
:filter="{ fields: ['id', 'code', 'dated'], order: 'code ASC', limit: 30 }"
|
:filter="{ fields: ['id', 'code', 'dated'], order: 'code ASC' }"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
|
|
@ -98,7 +98,6 @@ function onAgentCreated({ id, fiscalName }, data) {
|
||||||
:rules="validate('Worker.postcode')"
|
:rules="validate('Worker.postcode')"
|
||||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||||
v-model="data.location"
|
v-model="data.location"
|
||||||
:required="true"
|
|
||||||
@update:model-value="(location) => handleLocation(data, location)"
|
@update:model-value="(location) => handleLocation(data, location)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -96,11 +96,11 @@ const updateObservations = async (payload) => {
|
||||||
await axios.post('AddressObservations/crud', payload);
|
await axios.post('AddressObservations/crud', payload);
|
||||||
notes.value = [];
|
notes.value = [];
|
||||||
deletes.value = [];
|
deletes.value = [];
|
||||||
toCustomerAddress();
|
|
||||||
};
|
};
|
||||||
async function updateAll({ data, payload }) {
|
async function updateAll({ data, payload }) {
|
||||||
await updateObservations(payload);
|
await updateObservations(payload);
|
||||||
await updateAddress(data);
|
await updateAddress(data);
|
||||||
|
toCustomerAddress();
|
||||||
}
|
}
|
||||||
function getPayload() {
|
function getPayload() {
|
||||||
return {
|
return {
|
||||||
|
@ -137,15 +137,12 @@ async function handleDialog(data) {
|
||||||
.onOk(async () => {
|
.onOk(async () => {
|
||||||
await updateAddressTicket();
|
await updateAddressTicket();
|
||||||
await updateAll(body);
|
await updateAll(body);
|
||||||
toCustomerAddress();
|
|
||||||
})
|
})
|
||||||
.onCancel(async () => {
|
.onCancel(async () => {
|
||||||
await updateAll(body);
|
await updateAll(body);
|
||||||
toCustomerAddress();
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
updateAll(body);
|
await updateAll(body);
|
||||||
toCustomerAddress();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +233,7 @@ function handleLocation(data, location) {
|
||||||
postcode: data.postalCode,
|
postcode: data.postalCode,
|
||||||
city: data.city,
|
city: data.city,
|
||||||
province: data.province,
|
province: data.province,
|
||||||
country: data.province.country,
|
country: data.province?.country,
|
||||||
}"
|
}"
|
||||||
@update:model-value="(location) => handleLocation(data, location)"
|
@update:model-value="(location) => handleLocation(data, location)"
|
||||||
></VnLocation>
|
></VnLocation>
|
||||||
|
|
|
@ -84,7 +84,7 @@ function setPaymentType(accounting) {
|
||||||
viewReceipt.value = isCash.value;
|
viewReceipt.value = isCash.value;
|
||||||
if (accountingType.value.daysInFuture)
|
if (accountingType.value.daysInFuture)
|
||||||
initialData.payed.setDate(
|
initialData.payed.setDate(
|
||||||
initialData.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;
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ 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;
|
data.bankFk = data.bankFk?.id;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ async function getAmountPaid() {
|
||||||
:url-create="urlCreate"
|
:url-create="urlCreate"
|
||||||
:mapper="onBeforeSave"
|
:mapper="onBeforeSave"
|
||||||
@on-data-saved="onDataSaved"
|
@on-data-saved="onDataSaved"
|
||||||
:prevent-submit="true"
|
prevent-submit
|
||||||
>
|
>
|
||||||
<template #form="{ data, validate }">
|
<template #form="{ data, validate }">
|
||||||
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
||||||
|
|
|
@ -16,7 +16,6 @@ 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 SkeletonDescriptor from 'src/components/ui/SkeletonDescriptor.vue';
|
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
@ -103,7 +102,7 @@ const columns = [
|
||||||
name: 'itemFk',
|
name: 'itemFk',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
width: '40px',
|
width: '35px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelAbbreviation: '',
|
labelAbbreviation: '',
|
||||||
|
@ -111,7 +110,7 @@ const columns = [
|
||||||
name: 'hex',
|
name: 'hex',
|
||||||
columnSearch: false,
|
columnSearch: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
width: '5px',
|
width: '9px',
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'Inks',
|
url: 'Inks',
|
||||||
|
@ -156,10 +155,10 @@ const columns = [
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
labelAbbreviation: t('Sti.'),
|
labelAbbreviation: t('Sti.'),
|
||||||
label: t('Printed Stickers/Stickers'),
|
label: t('Stickers'),
|
||||||
toolTip: t('Printed Stickers/Stickers'),
|
toolTip: t('Printed Stickers/Stickers'),
|
||||||
name: 'stickers',
|
name: 'stickers',
|
||||||
component: 'number',
|
component: 'input',
|
||||||
create: true,
|
create: true,
|
||||||
attrs: {
|
attrs: {
|
||||||
positive: false,
|
positive: false,
|
||||||
|
@ -179,8 +178,9 @@ const columns = [
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'packagings',
|
url: 'packagings',
|
||||||
fields: ['id', 'volume'],
|
fields: ['id'],
|
||||||
optionLabel: 'id',
|
optionLabel: 'id',
|
||||||
|
optionValue: 'id',
|
||||||
},
|
},
|
||||||
create: true,
|
create: true,
|
||||||
width: '40px',
|
width: '40px',
|
||||||
|
@ -192,10 +192,10 @@ const columns = [
|
||||||
component: 'number',
|
component: 'number',
|
||||||
create: true,
|
create: true,
|
||||||
width: '35px',
|
width: '35px',
|
||||||
|
format: (row) => parseFloat(row['weight']).toFixed(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
labelAbbreviation: 'P',
|
||||||
labelAbbreviation: 'Pack',
|
|
||||||
label: 'Packing',
|
label: 'Packing',
|
||||||
toolTip: 'Packing',
|
toolTip: 'Packing',
|
||||||
name: 'packing',
|
name: 'packing',
|
||||||
|
@ -209,7 +209,7 @@ const columns = [
|
||||||
row['amount'] = row['quantity'] * row['buyingValue'];
|
row['amount'] = row['quantity'] * row['buyingValue'];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
width: '35px',
|
width: '30px',
|
||||||
style: (row) => {
|
style: (row) => {
|
||||||
if (row.groupingMode === 'grouping')
|
if (row.groupingMode === 'grouping')
|
||||||
return { color: 'var(--vn-label-color)' };
|
return { color: 'var(--vn-label-color)' };
|
||||||
|
@ -229,7 +229,7 @@ const columns = [
|
||||||
indeterminateValue: null,
|
indeterminateValue: null,
|
||||||
},
|
},
|
||||||
size: 'xs',
|
size: 'xs',
|
||||||
width: '30px',
|
width: '25px',
|
||||||
create: true,
|
create: true,
|
||||||
rightFilter: false,
|
rightFilter: false,
|
||||||
getIcon: (value) => {
|
getIcon: (value) => {
|
||||||
|
@ -245,12 +245,12 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
labelAbbreviation: 'Group',
|
labelAbbreviation: 'G',
|
||||||
label: 'Grouping',
|
label: 'Grouping',
|
||||||
toolTip: 'Grouping',
|
toolTip: 'Grouping',
|
||||||
name: 'grouping',
|
name: 'grouping',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
width: '35px',
|
width: '30px',
|
||||||
create: true,
|
create: true,
|
||||||
style: (row) => {
|
style: (row) => {
|
||||||
if (row.groupingMode === 'packing') return { color: 'var(--vn-label-color)' };
|
if (row.groupingMode === 'packing') return { color: 'var(--vn-label-color)' };
|
||||||
|
@ -290,6 +290,7 @@ const columns = [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
width: '45px',
|
width: '45px',
|
||||||
|
format: (row) => parseFloat(row['buyingValue']).toFixed(3),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -301,6 +302,7 @@ const columns = [
|
||||||
positive: false,
|
positive: false,
|
||||||
},
|
},
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
format: (row) => parseFloat(row['amount']).toFixed(2),
|
||||||
style: getAmountStyle,
|
style: getAmountStyle,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -312,6 +314,7 @@ const columns = [
|
||||||
component: 'number',
|
component: 'number',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
create: true,
|
create: true,
|
||||||
|
format: (row) => parseFloat(row['price2']).toFixed(2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -325,25 +328,7 @@ const columns = [
|
||||||
},
|
},
|
||||||
width: '35px',
|
width: '35px',
|
||||||
create: true,
|
create: true,
|
||||||
},
|
format: (row) => parseFloat(row['price3']).toFixed(2),
|
||||||
{
|
|
||||||
align: 'center',
|
|
||||||
labelAbbreviation: 'Min.',
|
|
||||||
label: t('Minimum price'),
|
|
||||||
toolTip: t('Minimum price'),
|
|
||||||
name: 'minPrice',
|
|
||||||
component: 'number',
|
|
||||||
cellEvent: {
|
|
||||||
'update:modelValue': async (value, oldValue, row) => {
|
|
||||||
await axios.patch(`Items/${row['itemFk']}`, {
|
|
||||||
minPrice: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
width: '35px',
|
|
||||||
style: (row) => {
|
|
||||||
if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -364,6 +349,26 @@ const columns = [
|
||||||
},
|
},
|
||||||
width: '25px',
|
width: '25px',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
align: 'center',
|
||||||
|
labelAbbreviation: 'Min.',
|
||||||
|
label: t('Minimum price'),
|
||||||
|
toolTip: t('Minimum price'),
|
||||||
|
name: 'minPrice',
|
||||||
|
component: 'number',
|
||||||
|
cellEvent: {
|
||||||
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
|
await axios.patch(`Items/${row['itemFk']}`, {
|
||||||
|
minPrice: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
width: '35px',
|
||||||
|
style: (row) => {
|
||||||
|
if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
|
||||||
|
},
|
||||||
|
format: (row) => parseFloat(row['minPrice']).toFixed(2),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
labelAbbreviation: t('P.Sen'),
|
labelAbbreviation: t('P.Sen'),
|
||||||
|
@ -373,6 +378,9 @@ const columns = [
|
||||||
component: 'number',
|
component: 'number',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
width: '40px',
|
width: '40px',
|
||||||
|
style: () => {
|
||||||
|
return { color: 'var(--vn-label-color)' };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -412,6 +420,9 @@ const columns = [
|
||||||
component: 'input',
|
component: 'input',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
width: '35px',
|
width: '35px',
|
||||||
|
style: () => {
|
||||||
|
return { color: 'var(--vn-label-color)' };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -504,7 +515,7 @@ async function setBuyUltimate(itemFk, data) {
|
||||||
|
|
||||||
allowedKeys.forEach((key) => {
|
allowedKeys.forEach((key) => {
|
||||||
if (buyUltimateData.hasOwnProperty(key) && key !== 'entryFk') {
|
if (buyUltimateData.hasOwnProperty(key) && key !== 'entryFk') {
|
||||||
data[key] = buyUltimateData[key];
|
if (!['stickers', 'quantity'].includes(key)) data[key] = buyUltimateData[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -518,7 +529,7 @@ onMounted(() => {
|
||||||
<Teleport to="#st-data" v-if="stateStore?.isSubToolbarShown() && editableMode">
|
<Teleport to="#st-data" v-if="stateStore?.isSubToolbarShown() && editableMode">
|
||||||
<QBtnGroup push style="column-gap: 1px">
|
<QBtnGroup push style="column-gap: 1px">
|
||||||
<QBtnDropdown
|
<QBtnDropdown
|
||||||
icon="exposure_neg_1"
|
label="+/-"
|
||||||
color="primary"
|
color="primary"
|
||||||
flat
|
flat
|
||||||
:title="t('Invert quantity value')"
|
:title="t('Invert quantity value')"
|
||||||
|
@ -533,7 +544,7 @@ onMounted(() => {
|
||||||
@click="invertQuantitySign(selectedRows, -1)"
|
@click="invertQuantitySign(selectedRows, -1)"
|
||||||
data-cy="set-negative-quantity"
|
data-cy="set-negative-quantity"
|
||||||
>
|
>
|
||||||
<span style="font-size: medium">-1</span>
|
<span style="font-size: large">-</span>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
@ -544,7 +555,7 @@ onMounted(() => {
|
||||||
@click="invertQuantitySign(selectedRows, 1)"
|
@click="invertQuantitySign(selectedRows, 1)"
|
||||||
data-cy="set-positive-quantity"
|
data-cy="set-positive-quantity"
|
||||||
>
|
>
|
||||||
<span style="font-size: medium">1</span>
|
<span style="font-size: large">+</span>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
@ -558,11 +569,11 @@ onMounted(() => {
|
||||||
:disable="!selectedRows.length"
|
:disable="!selectedRows.length"
|
||||||
data-cy="check-buy-amount"
|
data-cy="check-buy-amount"
|
||||||
>
|
>
|
||||||
<QTooltip>{{}}</QTooltip>
|
|
||||||
<QList>
|
<QList>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
size="sm"
|
||||||
icon="check"
|
icon="check"
|
||||||
flat
|
flat
|
||||||
@click="setIsChecked(selectedRows, true)"
|
@click="setIsChecked(selectedRows, true)"
|
||||||
|
@ -573,6 +584,7 @@ onMounted(() => {
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
size="sm"
|
||||||
icon="close"
|
icon="close"
|
||||||
flat
|
flat
|
||||||
@click="setIsChecked(selectedRows, false)"
|
@click="setIsChecked(selectedRows, false)"
|
||||||
|
@ -595,7 +607,6 @@ onMounted(() => {
|
||||||
ref="entryBuysRef"
|
ref="entryBuysRef"
|
||||||
data-key="EntryBuys"
|
data-key="EntryBuys"
|
||||||
:url="`Entries/${entityId}/getBuyList`"
|
:url="`Entries/${entityId}/getBuyList`"
|
||||||
order="name DESC"
|
|
||||||
save-url="Buys/crud"
|
save-url="Buys/crud"
|
||||||
:disable-option="{ card: true }"
|
:disable-option="{ card: true }"
|
||||||
v-model:selected="selectedRows"
|
v-model:selected="selectedRows"
|
||||||
|
@ -639,7 +650,8 @@ onMounted(() => {
|
||||||
:is-editable="editableMode"
|
:is-editable="editableMode"
|
||||||
:without-header="!editableMode"
|
:without-header="!editableMode"
|
||||||
:with-filters="editableMode"
|
:with-filters="editableMode"
|
||||||
:right-search="editableMode"
|
:right-search="true"
|
||||||
|
:right-search-icon="true"
|
||||||
:row-click="false"
|
:row-click="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:beforeSaveFn="beforeSave"
|
:beforeSaveFn="beforeSave"
|
||||||
|
@ -662,7 +674,7 @@ onMounted(() => {
|
||||||
<FetchedTags :item="row" :columns="3" />
|
<FetchedTags :item="row" :columns="3" />
|
||||||
</template>
|
</template>
|
||||||
<template #column-stickers="{ row }">
|
<template #column-stickers="{ row }">
|
||||||
<span class="editable-text">
|
<span :class="editableMode ? 'editable-text' : ''">
|
||||||
<span style="color: var(--vn-label-color)">
|
<span style="color: var(--vn-label-color)">
|
||||||
{{ row.printedStickers }}
|
{{ row.printedStickers }}
|
||||||
</span>
|
</span>
|
||||||
|
@ -693,20 +705,36 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
<template #column-create-itemFk="{ data }">
|
<template #column-create-itemFk="{ data }">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
url="Items"
|
url="Items/search"
|
||||||
v-model="data.itemFk"
|
v-model="data.itemFk"
|
||||||
:label="t('Article')"
|
:label="t('Article')"
|
||||||
:fields="['id', 'name']"
|
:fields="['id', 'name', 'size', 'producerName']"
|
||||||
|
:filter-options="['id', 'name', 'size', 'producerName']"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
@update:modelValue="
|
@update:modelValue="
|
||||||
async (value) => {
|
async (value) => {
|
||||||
setBuyUltimate(value, data);
|
await setBuyUltimate(value, data);
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
:required="true"
|
:required="true"
|
||||||
data-cy="itemFk-create-popup"
|
data-cy="itemFk-create-popup"
|
||||||
/>
|
sort-by="nickname DESC"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{ scope.opt.name }}
|
||||||
|
</QItemLabel>
|
||||||
|
<QItemLabel caption>
|
||||||
|
#{{ scope.opt.id }}, {{ scope.opt?.size }},
|
||||||
|
{{ scope.opt?.producerName }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
</template>
|
</template>
|
||||||
<template #column-create-groupingMode="{ data }">
|
<template #column-create-groupingMode="{ data }">
|
||||||
<VnSelectEnum
|
<VnSelectEnum
|
||||||
|
@ -720,9 +748,14 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #previous-create-dialog="{ data }">
|
<template #previous-create-dialog="{ data }">
|
||||||
<div style="position: absolute">
|
<div
|
||||||
|
style="position: absolute"
|
||||||
|
:class="{ 'centered-container': !data.itemFk }"
|
||||||
|
>
|
||||||
<ItemDescriptor :id="data.itemFk" v-if="data.itemFk" />
|
<ItemDescriptor :id="data.itemFk" v-if="data.itemFk" />
|
||||||
<SkeletonDescriptor v-if="!data.itemFk" :has-image="true" />
|
<div v-else>
|
||||||
|
<span>{{ t('globals.noData') }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VnTable>
|
</VnTable>
|
||||||
|
@ -744,6 +777,7 @@ es:
|
||||||
Com.: Ref.
|
Com.: Ref.
|
||||||
Comment: Referencia
|
Comment: Referencia
|
||||||
Minimum price: Precio mínimo
|
Minimum price: Precio mínimo
|
||||||
|
Stickers: Etiquetas
|
||||||
Printed Stickers/Stickers: Etiquetas impresas/Etiquetas
|
Printed Stickers/Stickers: Etiquetas impresas/Etiquetas
|
||||||
Cost: Cost.
|
Cost: Cost.
|
||||||
Buying value: Coste
|
Buying value: Coste
|
||||||
|
@ -761,7 +795,12 @@ es:
|
||||||
Check buy amount: Marcar como correcta la cantidad de compra
|
Check buy amount: Marcar como correcta la cantidad de compra
|
||||||
</i18n>
|
</i18n>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.test {
|
.centered-container {
|
||||||
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
width: 40%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -147,7 +147,6 @@ async function deleteEntry() {
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
ref="entryDescriptorRef"
|
ref="entryDescriptorRef"
|
||||||
module="Entry"
|
|
||||||
:url="`Entries/${entityId}`"
|
:url="`Entries/${entityId}`"
|
||||||
:userFilter="entryFilter"
|
:userFilter="entryFilter"
|
||||||
title="supplier.nickname"
|
title="supplier.nickname"
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
|
@ -18,18 +16,10 @@ defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const itemTypeWorkersOptions = ref([]);
|
|
||||||
const tagValues = ref([]);
|
const tagValues = ref([]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
url="TicketRequests/getItemTypeWorker"
|
|
||||||
limit="30"
|
|
||||||
auto-load
|
|
||||||
:filter="{ fields: ['id', 'nickname'], order: 'nickname ASC', limit: 30 }"
|
|
||||||
@on-fetch="(data) => (itemTypeWorkersOptions = data)"
|
|
||||||
/>
|
|
||||||
<ItemsFilterPanel :data-key="dataKey" :custom-tags="['tags']">
|
<ItemsFilterPanel :data-key="dataKey" :custom-tags="['tags']">
|
||||||
<template #body="{ params, searchFn }">
|
<template #body="{ params, searchFn }">
|
||||||
<QItem class="q-my-md">
|
<QItem class="q-my-md">
|
||||||
|
@ -37,9 +27,10 @@ const tagValues = ref([]);
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('components.itemsFilterPanel.salesPersonFk')"
|
:label="t('components.itemsFilterPanel.salesPersonFk')"
|
||||||
v-model="params.salesPersonFk"
|
v-model="params.salesPersonFk"
|
||||||
:options="itemTypeWorkersOptions"
|
url="TicketRequests/getItemTypeWorker"
|
||||||
option-value="id"
|
|
||||||
option-label="nickname"
|
option-label="nickname"
|
||||||
|
:fields="['id', 'nickname']"
|
||||||
|
sort-by="nickname ASC"
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
@ -52,8 +43,9 @@ const tagValues = ref([]);
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnSelectSupplier
|
<VnSelectSupplier
|
||||||
v-model="params.supplierFk"
|
v-model="params.supplierFk"
|
||||||
@update:model-value="searchFn()"
|
url="Suppliers"
|
||||||
hide-selected
|
:fields="['id', 'name', 'nickname']"
|
||||||
|
sort-by="name ASC"
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
|
|
@ -44,28 +44,32 @@ const entryQueryFilter = {
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
label: 'Ex',
|
labelAbbreviation: 'Ex',
|
||||||
|
label: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
|
||||||
toolTip: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
|
toolTip: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
|
||||||
name: 'isExcludedFromAvailable',
|
name: 'isExcludedFromAvailable',
|
||||||
component: 'checkbox',
|
component: 'checkbox',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Pe',
|
labelAbbreviation: 'Pe',
|
||||||
|
label: t('entry.list.tableVisibleColumns.isOrdered'),
|
||||||
toolTip: t('entry.list.tableVisibleColumns.isOrdered'),
|
toolTip: t('entry.list.tableVisibleColumns.isOrdered'),
|
||||||
name: 'isOrdered',
|
name: 'isOrdered',
|
||||||
component: 'checkbox',
|
component: 'checkbox',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Le',
|
labelAbbreviation: 'LE',
|
||||||
|
label: t('entry.list.tableVisibleColumns.isConfirmed'),
|
||||||
toolTip: t('entry.list.tableVisibleColumns.isConfirmed'),
|
toolTip: t('entry.list.tableVisibleColumns.isConfirmed'),
|
||||||
name: 'isConfirmed',
|
name: 'isConfirmed',
|
||||||
component: 'checkbox',
|
component: 'checkbox',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Re',
|
labelAbbreviation: 'Re',
|
||||||
|
label: t('entry.list.tableVisibleColumns.isReceived'),
|
||||||
toolTip: t('entry.list.tableVisibleColumns.isReceived'),
|
toolTip: t('entry.list.tableVisibleColumns.isReceived'),
|
||||||
name: 'isReceived',
|
name: 'isReceived',
|
||||||
component: 'checkbox',
|
component: 'checkbox',
|
||||||
|
@ -89,6 +93,7 @@ const columns = computed(() => [
|
||||||
chip: {
|
chip: {
|
||||||
condition: () => true,
|
condition: () => true,
|
||||||
},
|
},
|
||||||
|
width: '50px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('entry.list.tableVisibleColumns.supplierFk'),
|
label: t('entry.list.tableVisibleColumns.supplierFk'),
|
||||||
|
@ -99,8 +104,10 @@ const columns = computed(() => [
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'suppliers',
|
url: 'suppliers',
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name'],
|
||||||
|
where: { order: 'name DESC' },
|
||||||
},
|
},
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName),
|
format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName),
|
||||||
|
width: '110px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -124,6 +131,7 @@ const columns = computed(() => [
|
||||||
label: 'AWB',
|
label: 'AWB',
|
||||||
name: 'awbCode',
|
name: 'awbCode',
|
||||||
component: 'input',
|
component: 'input',
|
||||||
|
width: '100px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -160,6 +168,7 @@ const columns = computed(() => [
|
||||||
component: null,
|
component: null,
|
||||||
},
|
},
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseOutName),
|
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseOutName),
|
||||||
|
width: '65px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -175,20 +184,23 @@ const columns = computed(() => [
|
||||||
component: null,
|
component: null,
|
||||||
},
|
},
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseInName),
|
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseInName),
|
||||||
|
width: '65px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
labelAbbreviation: t('Type'),
|
||||||
label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
||||||
|
toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
||||||
name: 'entryTypeCode',
|
name: 'entryTypeCode',
|
||||||
cardVisible: true,
|
component: 'select',
|
||||||
},
|
attrs: {
|
||||||
{
|
url: 'entryTypes',
|
||||||
name: 'dated',
|
fields: ['code', 'description'],
|
||||||
label: t('entry.list.tableVisibleColumns.dated'),
|
optionValue: 'code',
|
||||||
component: 'date',
|
optionLabel: 'description',
|
||||||
cardVisible: false,
|
},
|
||||||
visible: false,
|
width: '65px',
|
||||||
create: true,
|
format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'companyFk',
|
name: 'companyFk',
|
||||||
|
@ -220,7 +232,8 @@ function getBadgeAttrs(row) {
|
||||||
|
|
||||||
let timeDiff = today - timeTicket;
|
let timeDiff = today - timeTicket;
|
||||||
|
|
||||||
if (timeDiff > 0) return { color: 'warning', 'text-color': 'black' };
|
if (timeDiff > 0) return { color: 'info', 'text-color': 'black' };
|
||||||
|
if (timeDiff < 0) return { color: 'warning', 'text-color': 'black' };
|
||||||
switch (row.entryTypeCode) {
|
switch (row.entryTypeCode) {
|
||||||
case 'regularization':
|
case 'regularization':
|
||||||
case 'life':
|
case 'life':
|
||||||
|
@ -245,7 +258,6 @@ function getBadgeAttrs(row) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (timeDiff < 0) return { color: 'info', 'text-color': 'black' };
|
|
||||||
return { color: 'transparent' };
|
return { color: 'transparent' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,4 +340,5 @@ es:
|
||||||
Search entries: Buscar entradas
|
Search entries: Buscar entradas
|
||||||
You can search by entry reference: Puedes buscar por referencia de la entrada
|
You can search by entry reference: Puedes buscar por referencia de la entrada
|
||||||
Create entry: Crear entrada
|
Create entry: Crear entrada
|
||||||
|
Type: Tipo
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -34,18 +34,20 @@ const columns = computed(() => [
|
||||||
label: t('entryStockBought.buyer'),
|
label: t('entryStockBought.buyer'),
|
||||||
isTitle: true,
|
isTitle: true,
|
||||||
component: 'select',
|
component: 'select',
|
||||||
|
isEditable: false,
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'Workers/activeWithInheritedRole',
|
url: 'Workers/activeWithInheritedRole',
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name', 'nickname'],
|
||||||
where: { role: 'buyer' },
|
where: { role: 'buyer' },
|
||||||
optionFilter: 'firstName',
|
optionFilter: 'firstName',
|
||||||
optionLabel: 'name',
|
optionLabel: 'nickname',
|
||||||
optionValue: 'id',
|
optionValue: 'id',
|
||||||
useLike: false,
|
useLike: false,
|
||||||
},
|
},
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
|
width: '70px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -55,6 +57,7 @@ const columns = computed(() => [
|
||||||
create: true,
|
create: true,
|
||||||
component: 'number',
|
component: 'number',
|
||||||
summation: true,
|
summation: true,
|
||||||
|
width: '50px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -78,6 +81,7 @@ const columns = computed(() => [
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
title: t('entryStockBought.viewMoreDetails'),
|
title: t('entryStockBought.viewMoreDetails'),
|
||||||
|
name: 'searchBtn',
|
||||||
icon: 'search',
|
icon: 'search',
|
||||||
isPrimary: true,
|
isPrimary: true,
|
||||||
action: (row) => {
|
action: (row) => {
|
||||||
|
@ -91,6 +95,7 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'data-cy': 'table-actions',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -158,7 +163,7 @@ function round(value) {
|
||||||
@on-fetch="
|
@on-fetch="
|
||||||
(data) => {
|
(data) => {
|
||||||
travel = data.find(
|
travel = data.find(
|
||||||
(data) => data.warehouseIn?.code.toLowerCase() === 'vnh'
|
(data) => data.warehouseIn?.code.toLowerCase() === 'vnh',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
|
@ -179,6 +184,7 @@ function round(value) {
|
||||||
@click="openDialog()"
|
@click="openDialog()"
|
||||||
:title="t('entryStockBought.editTravel')"
|
:title="t('entryStockBought.editTravel')"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
data-cy="edit-travel"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
@ -239,10 +245,11 @@ function round(value) {
|
||||||
table-height="80vh"
|
table-height="80vh"
|
||||||
auto-load
|
auto-load
|
||||||
:column-search="false"
|
:column-search="false"
|
||||||
|
:without-header="true"
|
||||||
>
|
>
|
||||||
<template #column-workerFk="{ row }">
|
<template #column-workerFk="{ row }">
|
||||||
<span class="link" @click.stop>
|
<span class="link" @click.stop>
|
||||||
{{ row?.worker?.user?.name }}
|
{{ row?.worker?.user?.nickname }}
|
||||||
<WorkerDescriptorProxy :id="row?.workerFk" />
|
<WorkerDescriptorProxy :id="row?.workerFk" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -279,10 +286,11 @@ function round(value) {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.column {
|
.column {
|
||||||
|
min-width: 40%;
|
||||||
|
margin-top: 5%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 35%;
|
|
||||||
}
|
}
|
||||||
.text-negative {
|
.text-negative {
|
||||||
color: $negative !important;
|
color: $negative !important;
|
||||||
|
|
|
@ -21,7 +21,7 @@ const $props = defineProps({
|
||||||
const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&dated=${$props.dated}`;
|
const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&dated=${$props.dated}`;
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
label: t('Entry'),
|
label: t('Entry'),
|
||||||
name: 'entryFk',
|
name: 'entryFk',
|
||||||
isTitle: true,
|
isTitle: true,
|
||||||
|
@ -29,7 +29,7 @@ const columns = [
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
name: 'itemFk',
|
name: 'itemFk',
|
||||||
label: t('Item'),
|
label: t('Item'),
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
|
@ -44,21 +44,21 @@ const columns = [
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
name: 'volume',
|
name: 'volume',
|
||||||
label: t('Volume'),
|
label: t('Volume'),
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
label: t('Packaging'),
|
label: t('Packaging'),
|
||||||
name: 'packagingFk',
|
name: 'packagingFk',
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
label: 'Packing',
|
label: 'Packing',
|
||||||
name: 'packing',
|
name: 'packing',
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
|
@ -73,12 +73,14 @@ const columns = [
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
data-key="StockBoughtsDetail"
|
data-key="StockBoughtsDetail"
|
||||||
:url="customUrl"
|
:url="customUrl"
|
||||||
order="itemName DESC"
|
order="volume DESC"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
:disable-infinite-scroll="true"
|
:disable-infinite-scroll="true"
|
||||||
:disable-option="{ card: true }"
|
:disable-option="{ card: true }"
|
||||||
:limit="0"
|
:limit="0"
|
||||||
|
:without-header="true"
|
||||||
|
:with-filters="false"
|
||||||
auto-load
|
auto-load
|
||||||
>
|
>
|
||||||
<template #column-entryFk="{ row }">
|
<template #column-entryFk="{ row }">
|
||||||
|
@ -99,16 +101,14 @@ const columns = [
|
||||||
</template>
|
</template>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.container {
|
.container {
|
||||||
max-width: 50vw;
|
max-width: 100%;
|
||||||
|
width: 50%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
background-color: var(--vn-section-color);
|
background-color: var(--vn-section-color);
|
||||||
padding: 4px;
|
padding: 2%;
|
||||||
}
|
|
||||||
.container > div > div > .q-table__top.relative-position.row.items-center {
|
|
||||||
background-color: red !important;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -90,7 +90,6 @@ async function setInvoiceCorrection(id) {
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
ref="cardDescriptorRef"
|
ref="cardDescriptorRef"
|
||||||
module="InvoiceIn"
|
|
||||||
data-key="InvoiceIn"
|
data-key="InvoiceIn"
|
||||||
:url="`InvoiceIns/${entityId}`"
|
:url="`InvoiceIns/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { toDate } from 'src/filters';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import { getTotal } from 'src/composables/getTotal';
|
import { getTotal } from 'src/composables/getTotal';
|
||||||
import CrudModel from 'src/components/CrudModel.vue';
|
import CrudModel from 'src/components/CrudModel.vue';
|
||||||
import FetchData from 'src/components/FetchData.vue';
|
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import useNotify from 'src/composables/useNotify.js';
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
@ -22,7 +21,6 @@ const invoiceIn = computed(() => arrayData.store.data);
|
||||||
const currency = computed(() => invoiceIn.value?.currency?.code);
|
const currency = computed(() => invoiceIn.value?.currency?.code);
|
||||||
|
|
||||||
const rowsSelected = ref([]);
|
const rowsSelected = ref([]);
|
||||||
const banks = ref([]);
|
|
||||||
const invoiceInFormRef = ref();
|
const invoiceInFormRef = ref();
|
||||||
const invoiceId = +route.params.id;
|
const invoiceId = +route.params.id;
|
||||||
const filter = { where: { invoiceInFk: invoiceId } };
|
const filter = { where: { invoiceInFk: invoiceId } };
|
||||||
|
@ -41,10 +39,9 @@ const columns = computed(() => [
|
||||||
name: 'bank',
|
name: 'bank',
|
||||||
label: t('Bank'),
|
label: t('Bank'),
|
||||||
field: (row) => row.bankFk,
|
field: (row) => row.bankFk,
|
||||||
options: banks.value,
|
|
||||||
model: 'bankFk',
|
model: 'bankFk',
|
||||||
optionValue: 'id',
|
|
||||||
optionLabel: 'bank',
|
optionLabel: 'bank',
|
||||||
|
url: 'Accountings',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
tabIndex: 2,
|
tabIndex: 2,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -82,12 +79,6 @@ onBeforeMount(async () => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
url="Accountings"
|
|
||||||
auto-load
|
|
||||||
limit="30"
|
|
||||||
@on-fetch="(data) => (banks = data)"
|
|
||||||
/>
|
|
||||||
<CrudModel
|
<CrudModel
|
||||||
v-if="invoiceIn"
|
v-if="invoiceIn"
|
||||||
ref="invoiceInFormRef"
|
ref="invoiceInFormRef"
|
||||||
|
@ -117,9 +108,9 @@ onBeforeMount(async () => {
|
||||||
<QTd>
|
<QTd>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
v-model="row[col.model]"
|
v-model="row[col.model]"
|
||||||
:options="col.options"
|
:url="col.url"
|
||||||
:option-value="col.optionValue"
|
|
||||||
:option-label="col.optionLabel"
|
:option-label="col.optionLabel"
|
||||||
|
:option-value="col.optionValue"
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
|
@ -193,8 +184,7 @@ onBeforeMount(async () => {
|
||||||
:label="t('Bank')"
|
:label="t('Bank')"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
v-model="props.row['bankFk']"
|
v-model="props.row['bankFk']"
|
||||||
:options="banks"
|
url="Accountings"
|
||||||
option-value="id"
|
|
||||||
option-label="bank"
|
option-label="bank"
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
|
|
|
@ -36,7 +36,6 @@ function ticketFilter(invoice) {
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
ref="descriptor"
|
ref="descriptor"
|
||||||
module="InvoiceOut"
|
|
||||||
:url="`InvoiceOuts/${entityId}`"
|
:url="`InvoiceOuts/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
title="ref"
|
title="ref"
|
||||||
|
|
|
@ -103,7 +103,7 @@ const refundInvoice = async (withWarehouse) => {
|
||||||
t('refundInvoiceSuccessMessage', {
|
t('refundInvoiceSuccessMessage', {
|
||||||
refundTicket: data[0].id,
|
refundTicket: data[0].id,
|
||||||
}),
|
}),
|
||||||
'positive'
|
'positive',
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,6 +124,13 @@ const showRefundInvoiceForm = () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showExportationLetter = () => {
|
||||||
|
openReport(`InvoiceOuts/${$props.invoiceOutData.ref}/exportation-pdf`, {
|
||||||
|
recipientId: $props.invoiceOutData.client.id,
|
||||||
|
refFk: $props.invoiceOutData.ref,
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -156,10 +163,14 @@ const showRefundInvoiceForm = () => {
|
||||||
<QMenu anchor="top end" self="top start">
|
<QMenu anchor="top end" self="top start">
|
||||||
<QList>
|
<QList>
|
||||||
<QItem v-ripple clickable @click="showSendInvoiceDialog('pdf')">
|
<QItem v-ripple clickable @click="showSendInvoiceDialog('pdf')">
|
||||||
<QItemSection>{{ t('Send PDF') }}</QItemSection>
|
<QItemSection data-cy="InvoiceOutDescriptorMenuSendPdfOption">
|
||||||
|
{{ t('Send PDF') }}
|
||||||
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem v-ripple clickable @click="showSendInvoiceDialog('csv')">
|
<QItem v-ripple clickable @click="showSendInvoiceDialog('csv')">
|
||||||
<QItemSection>{{ t('Send CSV') }}</QItemSection>
|
<QItemSection data-cy="InvoiceOutDescriptorMenuSendCsvOption">
|
||||||
|
{{ t('Send CSV') }}
|
||||||
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
</QList>
|
</QList>
|
||||||
</QMenu>
|
</QMenu>
|
||||||
|
@ -172,7 +183,7 @@ const showRefundInvoiceForm = () => {
|
||||||
t('Confirm deletion'),
|
t('Confirm deletion'),
|
||||||
t('Are you sure you want to delete this invoice?'),
|
t('Are you sure you want to delete this invoice?'),
|
||||||
deleteInvoice,
|
deleteInvoice,
|
||||||
redirectToInvoiceOutList
|
redirectToInvoiceOutList,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
@ -185,7 +196,7 @@ const showRefundInvoiceForm = () => {
|
||||||
openConfirmationModal(
|
openConfirmationModal(
|
||||||
'',
|
'',
|
||||||
t('Are you sure you want to book this invoice?'),
|
t('Are you sure you want to book this invoice?'),
|
||||||
bookInvoice
|
bookInvoice,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
@ -198,7 +209,7 @@ const showRefundInvoiceForm = () => {
|
||||||
openConfirmationModal(
|
openConfirmationModal(
|
||||||
t('Generate PDF invoice document'),
|
t('Generate PDF invoice document'),
|
||||||
t('Are you sure you want to generate/regenerate the PDF invoice?'),
|
t('Are you sure you want to generate/regenerate the PDF invoice?'),
|
||||||
generateInvoicePdf
|
generateInvoicePdf,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
@ -226,6 +237,14 @@ const showRefundInvoiceForm = () => {
|
||||||
{{ t('Create a single ticket with all the content of the current invoice') }}
|
{{ t('Create a single ticket with all the content of the current invoice') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
<QItem
|
||||||
|
v-if="$props.invoiceOutData.serial === 'E'"
|
||||||
|
v-ripple
|
||||||
|
clickable
|
||||||
|
@click="showExportationLetter()"
|
||||||
|
>
|
||||||
|
<QItemSection>{{ t('Show CITES letter') }}</QItemSection>
|
||||||
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
@ -255,7 +274,7 @@ es:
|
||||||
Create a single ticket with all the content of the current invoice: Crear un ticket único con todo el contenido de la factura actual
|
Create a single ticket with all the content of the current invoice: Crear un ticket único con todo el contenido de la factura actual
|
||||||
refundInvoiceSuccessMessage: Se ha creado el siguiente ticket de abono {refundTicket}
|
refundInvoiceSuccessMessage: Se ha creado el siguiente ticket de abono {refundTicket}
|
||||||
The email can't be empty: El email no puede estar vacío
|
The email can't be empty: El email no puede estar vacío
|
||||||
|
Show CITES letter: Ver carta CITES
|
||||||
en:
|
en:
|
||||||
refundInvoiceSuccessMessage: The following refund ticket have been created {refundTicket}
|
refundInvoiceSuccessMessage: The following refund ticket have been created {refundTicket}
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -125,7 +125,7 @@ const ticketsColumns = ref([
|
||||||
:value="toDate(invoiceOut.issued)"
|
:value="toDate(invoiceOut.issued)"
|
||||||
/>
|
/>
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('invoiceOut.summary.dued')"
|
:label="t('invoiceOut.summary.expirationDate')"
|
||||||
:value="toDate(invoiceOut.dued)"
|
:value="toDate(invoiceOut.dued)"
|
||||||
/>
|
/>
|
||||||
<VnLv :label="t('globals.created')" :value="toDate(invoiceOut.created)" />
|
<VnLv :label="t('globals.created')" :value="toDate(invoiceOut.created)" />
|
||||||
|
|
|
@ -22,7 +22,7 @@ const states = ref();
|
||||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
<strong>{{ t(`invoiceOut.params.${tag.label}`) }}: </strong>
|
||||||
<span>{{ formatFn(tag.value) }}</span>
|
<span>{{ formatFn(tag.value) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -84,15 +84,6 @@ const states = ref();
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
|
||||||
<QItemSection>
|
|
||||||
<VnInputDate
|
|
||||||
v-model="params.issued"
|
|
||||||
:label="t('Issued')"
|
|
||||||
is-outlined
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
|
@ -110,37 +101,3 @@ const states = ref();
|
||||||
</template>
|
</template>
|
||||||
</VnFilterPanel>
|
</VnFilterPanel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
|
||||||
en:
|
|
||||||
params:
|
|
||||||
search: Contains
|
|
||||||
clientFk: Customer
|
|
||||||
fi: FI
|
|
||||||
amount: Amount
|
|
||||||
min: Min
|
|
||||||
max: Max
|
|
||||||
hasPdf: Has PDF
|
|
||||||
issued: Issued
|
|
||||||
created: Created
|
|
||||||
dued: Dued
|
|
||||||
es:
|
|
||||||
params:
|
|
||||||
search: Contiene
|
|
||||||
clientFk: Cliente
|
|
||||||
fi: CIF
|
|
||||||
amount: Importe
|
|
||||||
min: Min
|
|
||||||
max: Max
|
|
||||||
hasPdf: Tiene PDF
|
|
||||||
issued: Emitida
|
|
||||||
created: Creada
|
|
||||||
dued: Vencida
|
|
||||||
Customer ID: ID cliente
|
|
||||||
FI: CIF
|
|
||||||
Amount: Importe
|
|
||||||
Has PDF: Tiene PDF
|
|
||||||
Issued: Fecha emisión
|
|
||||||
Created: Fecha creación
|
|
||||||
Dued: Fecha vencimiento
|
|
||||||
</i18n>
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ import VnSection from 'src/components/common/VnSection.vue';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const invoiceOutSerialsOptions = ref([]);
|
|
||||||
const customerOptions = ref([]);
|
const customerOptions = ref([]);
|
||||||
const selectedRows = ref([]);
|
const selectedRows = ref([]);
|
||||||
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
|
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
|
||||||
|
@ -71,14 +70,6 @@ const columns = computed(() => [
|
||||||
inWhere: true,
|
inWhere: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
align: 'left',
|
|
||||||
name: 'issued',
|
|
||||||
label: t('invoiceOut.summary.issued'),
|
|
||||||
component: 'date',
|
|
||||||
format: (row) => toDate(row.issued),
|
|
||||||
columnField: { component: null },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'clientFk',
|
name: 'clientFk',
|
||||||
|
@ -376,7 +367,6 @@ watchEffect(selectedRows);
|
||||||
url="InvoiceOutSerials"
|
url="InvoiceOutSerials"
|
||||||
v-model="data.serial"
|
v-model="data.serial"
|
||||||
:label="t('invoiceOutModule.serial')"
|
:label="t('invoiceOutModule.serial')"
|
||||||
:options="invoiceOutSerialsOptions"
|
|
||||||
option-label="description"
|
option-label="description"
|
||||||
option-value="code"
|
option-value="code"
|
||||||
option-filter
|
option-filter
|
||||||
|
|
|
@ -10,6 +10,8 @@ import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vu
|
||||||
import TicketDescriptorProxy from '../Ticket/Card/TicketDescriptorProxy.vue';
|
import TicketDescriptorProxy from '../Ticket/Card/TicketDescriptorProxy.vue';
|
||||||
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
|
import InvoiceOutNegativeBasesFilter from './InvoiceOutNegativeBasesFilter.vue';
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
|
@ -97,16 +99,19 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'isActive',
|
name: 'isActive',
|
||||||
label: t('invoiceOut.negativeBases.active'),
|
label: t('invoiceOut.negativeBases.active'),
|
||||||
|
component: 'checkbox',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'hasToInvoice',
|
name: 'hasToInvoice',
|
||||||
label: t('invoiceOut.negativeBases.hasToInvoice'),
|
label: t('invoiceOut.negativeBases.hasToInvoice'),
|
||||||
|
component: 'checkbox',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'hasVerifiedData',
|
name: 'isTaxDataChecked',
|
||||||
label: t('invoiceOut.negativeBases.verifiedData'),
|
label: t('invoiceOut.negativeBases.verifiedData'),
|
||||||
|
component: 'checkbox',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -142,7 +147,7 @@ const downloadCSV = async () => {
|
||||||
await invoiceOutGlobalStore.getNegativeBasesCsv(
|
await invoiceOutGlobalStore.getNegativeBasesCsv(
|
||||||
userParams.from,
|
userParams.from,
|
||||||
userParams.to,
|
userParams.to,
|
||||||
filterParams
|
filterParams,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -154,6 +159,11 @@ const downloadCSV = async () => {
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</template>
|
</template>
|
||||||
</VnSubToolbar>
|
</VnSubToolbar>
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<InvoiceOutNegativeBasesFilter data-key="negativeFilter" />
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
<VnTable
|
<VnTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
data-key="negativeFilter"
|
data-key="negativeFilter"
|
||||||
|
@ -174,6 +184,7 @@ const downloadCSV = async () => {
|
||||||
auto-load
|
auto-load
|
||||||
:is-editable="false"
|
:is-editable="false"
|
||||||
:use-model="true"
|
:use-model="true"
|
||||||
|
:right-search="false"
|
||||||
>
|
>
|
||||||
<template #column-clientId="{ row }">
|
<template #column-clientId="{ row }">
|
||||||
<span class="link" @click.stop>
|
<span class="link" @click.stop>
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -24,11 +25,11 @@ const props = defineProps({
|
||||||
>
|
>
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
<strong>{{ t(`invoiceOut.params.${tag.label}`) }}: </strong>
|
||||||
<span>{{ formatFn(tag.value) }}</span>
|
<span>{{ formatFn(tag.value) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ params }">
|
<template #body="{ params, searchFn }">
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
|
@ -49,38 +50,70 @@ const props = defineProps({
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnSelect
|
||||||
v-model="params.company"
|
url="Companies"
|
||||||
:label="t('globals.company')"
|
:label="t('globals.company')"
|
||||||
is-outlined
|
v-model="params.company"
|
||||||
/>
|
option-label="code"
|
||||||
|
option-value="code"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{ scope.opt?.code }}
|
||||||
|
</QItemLabel>
|
||||||
|
<QItemLabel caption>
|
||||||
|
{{ `#${scope.opt?.id}` }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnSelect
|
||||||
|
url="Countries"
|
||||||
|
:label="t('globals.params.countryFk')"
|
||||||
v-model="params.country"
|
v-model="params.country"
|
||||||
:label="t('globals.country')"
|
option-label="name"
|
||||||
is-outlined
|
option-value="name"
|
||||||
/>
|
outlined
|
||||||
</QItemSection>
|
dense
|
||||||
</QItem>
|
rounded
|
||||||
|
@update:model-value="searchFn()"
|
||||||
<QItem>
|
>
|
||||||
<QItemSection>
|
<template #option="scope">
|
||||||
<VnInput
|
<QItem v-bind="scope.itemProps">
|
||||||
v-model="params.clientId"
|
<QItemSection>
|
||||||
:label="t('invoiceOut.negativeBases.clientId')"
|
<QItemLabel>
|
||||||
is-outlined
|
{{ scope.opt?.name }}
|
||||||
/>
|
</QItemLabel>
|
||||||
|
<QItemLabel caption>
|
||||||
|
{{ `#${scope.opt?.id}` }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnSelect
|
||||||
v-model="params.clientSocialName"
|
url="Clients"
|
||||||
:label="t('globals.client')"
|
:label="t('globals.client')"
|
||||||
is-outlined
|
v-model="params.clientId"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
@update:model-value="searchFn()"
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
@ -90,15 +123,18 @@ const props = defineProps({
|
||||||
v-model="params.amount"
|
v-model="params.amount"
|
||||||
:label="t('globals.amount')"
|
:label="t('globals.amount')"
|
||||||
is-outlined
|
is-outlined
|
||||||
|
:positive="false"
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnSelectWorker
|
||||||
v-model="params.comercialName"
|
|
||||||
:label="t('invoiceOut.negativeBases.comercial')"
|
:label="t('invoiceOut.negativeBases.comercial')"
|
||||||
|
v-model="params.workerName"
|
||||||
|
option-value="name"
|
||||||
is-outlined
|
is-outlined
|
||||||
|
@update:model-value="searchFn()"
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
|
@ -4,7 +4,7 @@ invoiceOut:
|
||||||
params:
|
params:
|
||||||
company: Company
|
company: Company
|
||||||
country: Country
|
country: Country
|
||||||
clientId: Client ID
|
clientId: Client
|
||||||
clientSocialName: Client
|
clientSocialName: Client
|
||||||
taxableBase: Base
|
taxableBase: Base
|
||||||
ticketFk: Ticket
|
ticketFk: Ticket
|
||||||
|
@ -12,6 +12,19 @@ invoiceOut:
|
||||||
hasToInvoice: Has to invoice
|
hasToInvoice: Has to invoice
|
||||||
hasVerifiedData: Verified data
|
hasVerifiedData: Verified data
|
||||||
workerName: Worker
|
workerName: Worker
|
||||||
|
isTaxDataChecked: Verified data
|
||||||
|
amount: Amount
|
||||||
|
clientFk: Client
|
||||||
|
companyFk: Company
|
||||||
|
created: Created
|
||||||
|
dued: Dued
|
||||||
|
customsAgentFk: Custom Agent
|
||||||
|
ref: Reference
|
||||||
|
fi: FI
|
||||||
|
min: Min
|
||||||
|
max: Max
|
||||||
|
hasPdf: Has PDF
|
||||||
|
search: Contains
|
||||||
card:
|
card:
|
||||||
issued: Issued
|
issued: Issued
|
||||||
customerCard: Customer card
|
customerCard: Customer card
|
||||||
|
@ -19,6 +32,7 @@ invoiceOut:
|
||||||
summary:
|
summary:
|
||||||
issued: Issued
|
issued: Issued
|
||||||
dued: Due
|
dued: Due
|
||||||
|
expirationDate: Expiration date
|
||||||
booked: Booked
|
booked: Booked
|
||||||
taxBreakdown: Tax breakdown
|
taxBreakdown: Tax breakdown
|
||||||
taxableBase: Taxable base
|
taxableBase: Taxable base
|
||||||
|
@ -52,7 +66,7 @@ invoiceOut:
|
||||||
active: Active
|
active: Active
|
||||||
hasToInvoice: Has to Invoice
|
hasToInvoice: Has to Invoice
|
||||||
verifiedData: Verified Data
|
verifiedData: Verified Data
|
||||||
comercial: Commercial
|
comercial: Sales person
|
||||||
errors:
|
errors:
|
||||||
downloadCsvFailed: CSV download failed
|
downloadCsvFailed: CSV download failed
|
||||||
invoiceOutModule:
|
invoiceOutModule:
|
||||||
|
|
|
@ -4,7 +4,7 @@ invoiceOut:
|
||||||
params:
|
params:
|
||||||
company: Empresa
|
company: Empresa
|
||||||
country: País
|
country: País
|
||||||
clientId: ID del cliente
|
clientId: Cliente
|
||||||
clientSocialName: Cliente
|
clientSocialName: Cliente
|
||||||
taxableBase: Base
|
taxableBase: Base
|
||||||
ticketFk: Ticket
|
ticketFk: Ticket
|
||||||
|
@ -12,6 +12,19 @@ invoiceOut:
|
||||||
hasToInvoice: Debe facturar
|
hasToInvoice: Debe facturar
|
||||||
hasVerifiedData: Datos verificados
|
hasVerifiedData: Datos verificados
|
||||||
workerName: Comercial
|
workerName: Comercial
|
||||||
|
isTaxDataChecked: Datos comprobados
|
||||||
|
amount: Importe
|
||||||
|
clientFk: Cliente
|
||||||
|
companyFk: Empresa
|
||||||
|
created: Creada
|
||||||
|
dued: Vencida
|
||||||
|
customsAgentFk: Agente aduanas
|
||||||
|
ref: Referencia
|
||||||
|
fi: CIF
|
||||||
|
min: Min
|
||||||
|
max: Max
|
||||||
|
hasPdf: Tiene PDF
|
||||||
|
search: Contiene
|
||||||
card:
|
card:
|
||||||
issued: Fecha emisión
|
issued: Fecha emisión
|
||||||
customerCard: Ficha del cliente
|
customerCard: Ficha del cliente
|
||||||
|
@ -19,6 +32,7 @@ invoiceOut:
|
||||||
summary:
|
summary:
|
||||||
issued: Fecha
|
issued: Fecha
|
||||||
dued: Fecha límite
|
dued: Fecha límite
|
||||||
|
expirationDate: Fecha vencimiento
|
||||||
booked: Contabilizada
|
booked: Contabilizada
|
||||||
taxBreakdown: Desglose impositivo
|
taxBreakdown: Desglose impositivo
|
||||||
taxableBase: Base imp.
|
taxableBase: Base imp.
|
||||||
|
|
|
@ -92,7 +92,6 @@ const updateStock = async () => {
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
data-key="Item"
|
data-key="Item"
|
||||||
module="Item"
|
|
||||||
:summary="$props.summary"
|
:summary="$props.summary"
|
||||||
:url="`Items/${entityId}/getCard`"
|
:url="`Items/${entityId}/getCard`"
|
||||||
@on-fetch="setData"
|
@on-fetch="setData"
|
||||||
|
|
|
@ -110,10 +110,16 @@ const columns = computed(() => [
|
||||||
attrs: { inWhere: true },
|
attrs: { inWhere: true },
|
||||||
align: 'left',
|
align: 'left',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: t('globals.visible'),
|
||||||
|
name: 'stock',
|
||||||
|
attrs: { inWhere: true },
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const totalLabels = computed(() =>
|
const totalLabels = computed(() =>
|
||||||
rows.value.reduce((acc, row) => acc + row.stock / row.packing, 0).toFixed(2)
|
rows.value.reduce((acc, row) => acc + row.stock / row.packing, 0).toFixed(2),
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeLines = async () => {
|
const removeLines = async () => {
|
||||||
|
@ -157,7 +163,7 @@ watchEffect(selectedRows);
|
||||||
openConfirmationModal(
|
openConfirmationModal(
|
||||||
t('shelvings.removeConfirmTitle'),
|
t('shelvings.removeConfirmTitle'),
|
||||||
t('shelvings.removeConfirmSubtitle'),
|
t('shelvings.removeConfirmSubtitle'),
|
||||||
removeLines
|
removeLines,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
|
import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
|
||||||
|
@ -16,17 +14,9 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const itemTypeWorkersOptions = ref([]);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
url="TicketRequests/getItemTypeWorker"
|
|
||||||
limit="30"
|
|
||||||
auto-load
|
|
||||||
:filter="{ fields: ['id', 'nickname'], order: 'nickname ASC', limit: 30 }"
|
|
||||||
@on-fetch="(data) => (itemTypeWorkersOptions = data)"
|
|
||||||
/>
|
|
||||||
<ItemsFilterPanel :data-key="props.dataKey" :custom-tags="['tags']">
|
<ItemsFilterPanel :data-key="props.dataKey" :custom-tags="['tags']">
|
||||||
<template #body="{ params, searchFn }">
|
<template #body="{ params, searchFn }">
|
||||||
<QItem class="q-my-md">
|
<QItem class="q-my-md">
|
||||||
|
@ -34,14 +24,15 @@ const itemTypeWorkersOptions = ref([]);
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('params.buyerFk')"
|
:label="t('params.buyerFk')"
|
||||||
v-model="params.buyerFk"
|
v-model="params.buyerFk"
|
||||||
:options="itemTypeWorkersOptions"
|
url="TicketRequests/getItemTypeWorker"
|
||||||
option-value="id"
|
:fields="['id', 'nickname']"
|
||||||
option-label="nickname"
|
option-label="nickname"
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
use-input
|
use-input
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
|
sort-by="nickname ASC"
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
@ -50,11 +41,10 @@ const itemTypeWorkersOptions = ref([]);
|
||||||
<VnSelect
|
<VnSelect
|
||||||
url="Warehouses"
|
url="Warehouses"
|
||||||
auto-load
|
auto-load
|
||||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
:fields="['id', 'name']"
|
||||||
|
sort-by="name ASC"
|
||||||
:label="t('params.warehouseFk')"
|
:label="t('params.warehouseFk')"
|
||||||
v-model="params.warehouseFk"
|
v-model="params.warehouseFk"
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
|
|
@ -8,6 +8,7 @@ import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -52,7 +53,7 @@ onMounted(async () => {
|
||||||
name: key,
|
name: key,
|
||||||
value,
|
value,
|
||||||
selectedField: { name: key, label: t(`params.${key}`) },
|
selectedField: { name: key, label: t(`params.${key}`) },
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
exprBuilder('state', arrayData.store?.userParams?.state);
|
exprBuilder('state', arrayData.store?.userParams?.state);
|
||||||
|
@ -157,6 +158,32 @@ onMounted(async () => {
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInputDate
|
||||||
|
v-model="params.from"
|
||||||
|
:label="t('params.from')"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInputDate
|
||||||
|
v-model="params.to"
|
||||||
|
:label="t('params.to')"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.daysOnward')"
|
||||||
|
v-model="params.daysOnward"
|
||||||
|
lazy-rules
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
@ -175,11 +202,10 @@ onMounted(async () => {
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<QCheckbox
|
||||||
:label="t('params.daysOnward')"
|
:label="t('params.mine')"
|
||||||
v-model="params.daysOnward"
|
v-model="params.mine"
|
||||||
lazy-rules
|
:toggle-indeterminate="false"
|
||||||
is-outlined
|
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
|
@ -26,7 +26,6 @@ const entityId = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="ItemType"
|
|
||||||
:url="`ItemTypes/${entityId}`"
|
:url="`ItemTypes/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
title="code"
|
title="code"
|
||||||
|
|
|
@ -61,6 +61,7 @@ function exprBuilder(param, value) {
|
||||||
case 'nickname':
|
case 'nickname':
|
||||||
return { [`t.nickname`]: { like: `%${value}%` } };
|
return { [`t.nickname`]: { like: `%${value}%` } };
|
||||||
case 'zoneFk':
|
case 'zoneFk':
|
||||||
|
return { 't.zoneFk': value };
|
||||||
case 'department':
|
case 'department':
|
||||||
return { 'd.name': value };
|
return { 'd.name': value };
|
||||||
case 'totalWithVat':
|
case 'totalWithVat':
|
||||||
|
|
|
@ -39,7 +39,7 @@ const addToOrder = async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: orderTotal } = await axios.get(
|
const { data: orderTotal } = await axios.get(
|
||||||
`Orders/${Number(route.params.id)}/getTotal`
|
`Orders/${Number(route.params.id)}/getTotal`,
|
||||||
);
|
);
|
||||||
|
|
||||||
state.set('orderTotal', orderTotal);
|
state.set('orderTotal', orderTotal);
|
||||||
|
@ -56,7 +56,7 @@ const canAddToOrder = () => {
|
||||||
if (canAddToOrder) {
|
if (canAddToOrder) {
|
||||||
const excedQuantity = prices.value.reduce(
|
const excedQuantity = prices.value.reduce(
|
||||||
(acc, { quantity }) => acc + quantity,
|
(acc, { quantity }) => acc + quantity,
|
||||||
0
|
0,
|
||||||
);
|
);
|
||||||
if (excedQuantity > props.item.available) {
|
if (excedQuantity > props.item.available) {
|
||||||
canAddToOrder = false;
|
canAddToOrder = false;
|
||||||
|
|
|
@ -57,7 +57,6 @@ const total = ref(0);
|
||||||
ref="descriptor"
|
ref="descriptor"
|
||||||
:url="`Orders/${entityId}`"
|
:url="`Orders/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
module="Order"
|
|
||||||
title="client.name"
|
title="client.name"
|
||||||
@on-fetch="setData"
|
@on-fetch="setData"
|
||||||
data-key="Order"
|
data-key="Order"
|
||||||
|
|
|
@ -22,7 +22,6 @@ const card = computed(() => store.data);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Agency"
|
|
||||||
data-key="Agency"
|
data-key="Agency"
|
||||||
:url="`Agencies/${entityId}`"
|
:url="`Agencies/${entityId}`"
|
||||||
:title="card?.name"
|
:title="card?.name"
|
||||||
|
|
|
@ -46,7 +46,6 @@ const exprBuilder = (param, value) => {
|
||||||
url="AgencyModes"
|
url="AgencyModes"
|
||||||
:filter="{ fields: ['id', 'name'] }"
|
:filter="{ fields: ['id', 'name'] }"
|
||||||
sort-by="name ASC"
|
sort-by="name ASC"
|
||||||
limit="30"
|
|
||||||
@on-fetch="(data) => (agencyList = data)"
|
@on-fetch="(data) => (agencyList = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
|
@ -54,7 +53,6 @@ const exprBuilder = (param, value) => {
|
||||||
url="Agencies"
|
url="Agencies"
|
||||||
:filter="{ fields: ['id', 'name'] }"
|
:filter="{ fields: ['id', 'name'] }"
|
||||||
sort-by="name ASC"
|
sort-by="name ASC"
|
||||||
limit="30"
|
|
||||||
@on-fetch="(data) => (agencyAgreementList = data)"
|
@on-fetch="(data) => (agencyAgreementList = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
|
@ -120,7 +118,11 @@ const exprBuilder = (param, value) => {
|
||||||
<VnSelectSupplier
|
<VnSelectSupplier
|
||||||
:label="t('Autonomous')"
|
:label="t('Autonomous')"
|
||||||
v-model="params.supplierFk"
|
v-model="params.supplierFk"
|
||||||
hide-selected
|
url="Suppliers"
|
||||||
|
:fields="['name']"
|
||||||
|
sort-by="name ASC"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||||
import VnLv from 'components/ui/VnLv.vue';
|
import VnLv from 'components/ui/VnLv.vue';
|
||||||
import { dashIfEmpty, toDate } from 'src/filters';
|
import { dashIfEmpty, toDate } from 'src/filters';
|
||||||
import RouteDescriptorMenu from 'pages/Route/Card/RouteDescriptorMenu.vue';
|
import RouteDescriptorMenu from 'pages/Route/Card/RouteDescriptorMenu.vue';
|
||||||
import filter from './RouteFilter.js';
|
import filter from './RouteFilter.js';
|
||||||
|
import useCardDescription from 'src/composables/useCardDescription';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
@ -16,14 +18,32 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const zone = ref();
|
||||||
|
const zoneId = ref();
|
||||||
const entityId = computed(() => {
|
const entityId = computed(() => {
|
||||||
return $props.id || route.params.id;
|
return $props.id || route.params.id;
|
||||||
});
|
});
|
||||||
|
const getZone = async () => {
|
||||||
|
const filter = {
|
||||||
|
where: { routeFk: $props.id ? $props.id : route.params.id },
|
||||||
|
};
|
||||||
|
const { data } = await axios.get('Tickets/findOne', {
|
||||||
|
params: {
|
||||||
|
filter: JSON.stringify(filter),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
zoneId.value = data.zoneFk;
|
||||||
|
const { data: zoneData } = await axios.get(`Zones/${zoneId.value}`);
|
||||||
|
zone.value = zoneData.name;
|
||||||
|
};
|
||||||
|
const data = ref(useCardDescription());
|
||||||
|
const setData = (entity) => (data.value = useCardDescription(entity.code, entity.id));
|
||||||
|
onMounted(async () => {
|
||||||
|
getZone();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Route"
|
|
||||||
:url="`Routes/${entityId}`"
|
:url="`Routes/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
:title="null"
|
:title="null"
|
||||||
|
@ -31,9 +51,9 @@ const entityId = computed(() => {
|
||||||
width="lg-width"
|
width="lg-width"
|
||||||
>
|
>
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<VnLv :label="$t('Date')" :value="toDate(entity?.created)" />
|
<VnLv :label="$t('Date')" :value="toDate(entity?.dated)" />
|
||||||
<VnLv :label="$t('Agency')" :value="entity?.agencyMode?.name" />
|
<VnLv :label="$t('Agency')" :value="entity?.agencyMode?.name" />
|
||||||
<VnLv :label="$t('Zone')" :value="entity?.zone?.name" />
|
<VnLv :label="$t('Zone')" :value="zone" />
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="$t('Volume')"
|
:label="$t('Volume')"
|
||||||
:value="`${dashIfEmpty(entity?.m3)} / ${dashIfEmpty(
|
:value="`${dashIfEmpty(entity?.m3)} / ${dashIfEmpty(
|
||||||
|
|
|
@ -14,7 +14,6 @@ export default {
|
||||||
'started',
|
'started',
|
||||||
'finished',
|
'finished',
|
||||||
'cost',
|
'cost',
|
||||||
'zoneFk',
|
|
||||||
'isOk',
|
'isOk',
|
||||||
],
|
],
|
||||||
include: [
|
include: [
|
||||||
|
@ -23,7 +22,6 @@ export default {
|
||||||
relation: 'vehicle',
|
relation: 'vehicle',
|
||||||
scope: { fields: ['id', 'm3'] },
|
scope: { fields: ['id', 'm3'] },
|
||||||
},
|
},
|
||||||
{ relation: 'zone', scope: { fields: ['id', 'name'] } },
|
|
||||||
{
|
{
|
||||||
relation: 'worker',
|
relation: 'worker',
|
||||||
scope: {
|
scope: {
|
||||||
|
|
|
@ -28,7 +28,6 @@ const defaultInitialData = {
|
||||||
isOk: false,
|
isOk: false,
|
||||||
};
|
};
|
||||||
const maxDistance = ref();
|
const maxDistance = ref();
|
||||||
|
|
||||||
const onSave = (data, response) => {
|
const onSave = (data, response) => {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
axios.post(`Routes/${response?.id}/updateWorkCenter`);
|
axios.post(`Routes/${response?.id}/updateWorkCenter`);
|
||||||
|
|
|
@ -48,7 +48,6 @@ const onFetch = (data) => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}"
|
}"
|
||||||
limit="30"
|
|
||||||
@on-fetch="onFetch"
|
@on-fetch="onFetch"
|
||||||
/>
|
/>
|
||||||
<div :class="[isDialog ? 'column' : 'form-gap', 'full-width flex']">
|
<div :class="[isDialog ? 'column' : 'form-gap', 'full-width flex']">
|
||||||
|
|
|
@ -18,6 +18,7 @@ const onSave = (data, response) => {
|
||||||
<template>
|
<template>
|
||||||
<FormModel
|
<FormModel
|
||||||
:update-url="`Roadmaps/${$route.params?.id}`"
|
:update-url="`Roadmaps/${$route.params?.id}`"
|
||||||
|
:url="`Roadmaps/${$route.params?.id}`"
|
||||||
observe-form-changes
|
observe-form-changes
|
||||||
model="Roadmap"
|
model="Roadmap"
|
||||||
auto-load
|
auto-load
|
||||||
|
|
|
@ -26,12 +26,7 @@ const entityId = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor :url="`Roadmaps/${entityId}`" :filter="filter" data-key="Roadmap">
|
||||||
module="Roadmap"
|
|
||||||
:url="`Roadmaps/${entityId}`"
|
|
||||||
:filter="filter"
|
|
||||||
data-key="Roadmap"
|
|
||||||
>
|
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<VnLv :label="t('Roadmap')" :value="entity?.name" />
|
<VnLv :label="t('Roadmap')" :value="entity?.name" />
|
||||||
<VnLv :label="t('ETD')" :value="toDateHourMin(entity?.etd)" />
|
<VnLv :label="t('ETD')" :value="toDateHourMin(entity?.etd)" />
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
|
@ -65,6 +63,7 @@ const emit = defineEmits(['search']);
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnSelectSupplier
|
<VnSelectSupplier
|
||||||
:label="t('Carrier')"
|
:label="t('Carrier')"
|
||||||
|
:fields="['id', 'nickname']"
|
||||||
v-model="params.supplierFk"
|
v-model="params.supplierFk"
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
|
|
|
@ -280,7 +280,7 @@ const openTicketsDialog = (id) => {
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="q-pt-none">
|
<QCardSection class="q-pt-none">
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
:label="t('route.Stating date')"
|
:label="t('route.Starting date')"
|
||||||
v-model="startingDate"
|
v-model="startingDate"
|
||||||
autofocus
|
autofocus
|
||||||
/>
|
/>
|
||||||
|
@ -335,6 +335,7 @@ const openTicketsDialog = (id) => {
|
||||||
<QBtn
|
<QBtn
|
||||||
icon="vn:clone"
|
icon="vn:clone"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
flat
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
:disable="!selectedRows?.length"
|
:disable="!selectedRows?.length"
|
||||||
@click="confirmationDialog = true"
|
@click="confirmationDialog = true"
|
||||||
|
@ -344,6 +345,7 @@ const openTicketsDialog = (id) => {
|
||||||
<QBtn
|
<QBtn
|
||||||
icon="cloud_download"
|
icon="cloud_download"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
flat
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
:disable="!selectedRows?.length"
|
:disable="!selectedRows?.length"
|
||||||
@click="showRouteReport"
|
@click="showRouteReport"
|
||||||
|
@ -353,6 +355,7 @@ const openTicketsDialog = (id) => {
|
||||||
<QBtn
|
<QBtn
|
||||||
icon="check"
|
icon="check"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
flat
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
:disable="!selectedRows?.length"
|
:disable="!selectedRows?.length"
|
||||||
@click="markAsServed()"
|
@click="markAsServed()"
|
||||||
|
|
|
@ -9,7 +9,6 @@ const { notify } = useNotify();
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
:url="`Vehicles/${$route.params.id}`"
|
:url="`Vehicles/${$route.params.id}`"
|
||||||
module="Vehicle"
|
|
||||||
data-key="Vehicle"
|
data-key="Vehicle"
|
||||||
title="numberPlate"
|
title="numberPlate"
|
||||||
:to-module="{ name: 'VehicleList' }"
|
:to-module="{ name: 'VehicleList' }"
|
||||||
|
|
|
@ -25,7 +25,6 @@ const entityId = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Shelving"
|
|
||||||
:url="`Shelvings/${entityId}`"
|
:url="`Shelvings/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
title="code"
|
title="code"
|
||||||
|
|
|
@ -8,6 +8,11 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
|
||||||
const sectors = ref([]);
|
const sectors = ref([]);
|
||||||
const sectorFilter = { fields: ['id', 'description'] };
|
const sectorFilter = { fields: ['id', 'description'] };
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
fields: ['sectorFk', 'code', 'pickingOrder'],
|
||||||
|
include: [{ relation: 'sector', scope: sectorFilter }],
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -26,10 +31,6 @@ const sectorFilter = { fields: ['id', 'description'] };
|
||||||
:label="$t('parking.pickingOrder')"
|
:label="$t('parking.pickingOrder')"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
|
||||||
<VnInput v-model="data.row" :label="$t('parking.row')" />
|
|
||||||
<VnInput v-model="data.column" :label="$t('parking.column')" />
|
|
||||||
</VnRow>
|
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
v-model="data.sectorFk"
|
v-model="data.sectorFk"
|
||||||
|
|
|
@ -17,7 +17,6 @@ const entityId = computed(() => props.id || route.params.id);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Parking"
|
|
||||||
data-key="Parking"
|
data-key="Parking"
|
||||||
:url="`Parkings/${entityId}`"
|
:url="`Parkings/${entityId}`"
|
||||||
title="code"
|
title="code"
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
parking:
|
parking:
|
||||||
pickingOrder: Picking order
|
pickingOrder: Picking order
|
||||||
sector: Sector
|
sector: Sector
|
||||||
row: Row
|
|
||||||
column: Column
|
|
||||||
search: Search parking
|
search: Search parking
|
||||||
searchInfo: You can search by parking code
|
searchInfo: You can search by parking code
|
|
@ -1,7 +1,5 @@
|
||||||
parking:
|
parking:
|
||||||
pickingOrder: Orden de recogida
|
pickingOrder: Orden de recogida
|
||||||
row: Fila
|
|
||||||
sector: Sector
|
sector: Sector
|
||||||
column: Columna
|
|
||||||
search: Buscar parking
|
search: Buscar parking
|
||||||
searchInfo: Puedes buscar por código de parking
|
searchInfo: Puedes buscar por código de parking
|
|
@ -62,7 +62,6 @@ const getEntryQueryParams = (supplier) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Supplier"
|
|
||||||
:url="`Suppliers/${entityId}`"
|
:url="`Suppliers/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
data-key="Supplier"
|
data-key="Supplier"
|
||||||
|
|
|
@ -44,7 +44,6 @@ function ticketFilter(ticket) {
|
||||||
@on-fetch="(data) => ([problems] = data)"
|
@on-fetch="(data) => ([problems] = data)"
|
||||||
/>
|
/>
|
||||||
<CardDescriptor
|
<CardDescriptor
|
||||||
module="Ticket"
|
|
||||||
:url="`Tickets/${entityId}`"
|
:url="`Tickets/${entityId}`"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
data-key="Ticket"
|
data-key="Ticket"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue