Merge branch 'dev' into 6768-VnLocationRefact
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
447cbdeca8
|
@ -75,16 +75,12 @@ pipeline {
|
|||
steps {
|
||||
sh 'npm run test:unit:ci'
|
||||
}
|
||||
post {
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
try {
|
||||
junit 'junitresults.xml'
|
||||
junit 'junit.xml'
|
||||
} catch (e) {
|
||||
echo e.toString()
|
||||
}
|
||||
}
|
||||
junit(
|
||||
testResults: 'junitresults.xml',
|
||||
allowEmptyResults: true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,8 +176,8 @@ async function remove(data) {
|
|||
.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
title: t('confirmDeletion'),
|
||||
message: t('confirmDeletionMessage'),
|
||||
title: t('globals.confirmDeletion'),
|
||||
message: t('globals.confirmDeletionMessage'),
|
||||
newData,
|
||||
ids,
|
||||
},
|
||||
|
@ -317,16 +317,3 @@ watch(formUrl, async () => {
|
|||
color="primary"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"confirmDeletion": "Confirm deletion",
|
||||
"confirmDeletionMessage": "Are you sure you want to delete this?"
|
||||
},
|
||||
"es": {
|
||||
"confirmDeletion": "Confirmar eliminación",
|
||||
"confirmDeletionMessage": "Seguro que quieres eliminar?"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
|
|
@ -272,7 +272,7 @@ const makeRequest = async () => {
|
|||
class="cursor-pointer q-mr-sm"
|
||||
@click="openInputFile()"
|
||||
>
|
||||
<!-- <QTooltip>{{ t('Select a file') }}</QTooltip> -->
|
||||
<!-- <QTooltip>{{ t('globals.selectFile') }}</QTooltip> -->
|
||||
</QIcon>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{
|
||||
|
|
|
@ -59,11 +59,4 @@ async function fetch(fetchFilter = {}) {
|
|||
//
|
||||
}
|
||||
}
|
||||
|
||||
const render = () => {
|
||||
return h('div', []);
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<render />
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup>
|
||||
import axios from 'axios';
|
||||
import { onMounted, onUnmounted, computed, ref, watch, nextTick } from 'vue';
|
||||
import { onBeforeRouteLeave } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useState } from 'src/composables/useState';
|
||||
|
@ -8,6 +9,7 @@ import { useStateStore } from 'stores/useStateStore';
|
|||
import { useValidator } from 'src/composables/useValidator';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import SkeletonForm from 'components/ui/SkeletonForm.vue';
|
||||
import VnConfirm from './ui/VnConfirm.vue';
|
||||
|
||||
const quasar = useQuasar();
|
||||
const state = useState();
|
||||
|
@ -59,6 +61,10 @@ const $props = defineProps({
|
|||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
saveFn: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['onFetch', 'onDataSaved']);
|
||||
|
@ -75,9 +81,8 @@ onMounted(async () => {
|
|||
});
|
||||
|
||||
// Podemos enviarle al form la estructura de data inicial sin necesidad de fetchearla
|
||||
if ($props.formInitialData && !$props.autoLoad) {
|
||||
state.set($props.model, $props.formInitialData);
|
||||
} else {
|
||||
state.set($props.model, $props.formInitialData ?? {});
|
||||
if ($props.autoLoad && !$props.formInitialData) {
|
||||
await fetch();
|
||||
}
|
||||
|
||||
|
@ -90,6 +95,19 @@ onMounted(async () => {
|
|||
}
|
||||
});
|
||||
|
||||
onBeforeRouteLeave((to, from, next) => {
|
||||
if (!hasChanges.value) next();
|
||||
|
||||
quasar.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
title: t('Unsaved changes will be lost'),
|
||||
message: t('Are you sure exit without saving?'),
|
||||
promise: () => next(),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
state.unset($props.model);
|
||||
});
|
||||
|
@ -138,17 +156,20 @@ async function save() {
|
|||
try {
|
||||
const body = $props.mapper ? $props.mapper(formData.value) : formData.value;
|
||||
let response;
|
||||
if ($props.urlCreate) {
|
||||
response = await axios.post($props.urlCreate, body);
|
||||
notify('globals.dataCreated', 'positive');
|
||||
} else {
|
||||
response = await axios.patch($props.urlUpdate || $props.url, body);
|
||||
}
|
||||
if ($props.saveFn) response = await $props.saveFn(body);
|
||||
else
|
||||
response = await axios[$props.urlCreate ? 'post' : 'patch'](
|
||||
$props.urlCreate || $props.urlUpdate || $props.url,
|
||||
body
|
||||
);
|
||||
if ($props.urlCreate) notify('globals.dataCreated', 'positive');
|
||||
|
||||
emit('onDataSaved', formData.value, response?.data);
|
||||
originalData.value = JSON.parse(JSON.stringify(formData.value));
|
||||
hasChanges.value = false;
|
||||
} catch (err) {
|
||||
notify('errors.create', 'negative');
|
||||
console.error(err);
|
||||
notify('errors.writeRequest', 'negative');
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
@ -249,3 +270,8 @@ watch(formUrl, async () => {
|
|||
padding: 32px;
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
es:
|
||||
Unsaved changes will be lost: Los cambios que no haya guardado se perderán
|
||||
Are you sure exit without saving?: ¿Seguro que quiere salir sin guardar?
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import axios from 'axios';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(['onDataSaved']);
|
||||
|
||||
const $props = defineProps({
|
||||
model: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
defaultDmsCode: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
formInitialData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const warehouses = ref();
|
||||
const companies = ref();
|
||||
const dmsTypes = ref();
|
||||
const allowedContentTypes = ref();
|
||||
const inputFileRef = ref();
|
||||
const dms = ref({});
|
||||
|
||||
onMounted(() => {
|
||||
defaultData();
|
||||
if (!$props.formInitialData)
|
||||
dms.value.description = t($props.model + 'Description', dms.value);
|
||||
});
|
||||
function onFileChange(files) {
|
||||
dms.value.hasFileAttached = !!files;
|
||||
dms.value.file = files?.name;
|
||||
}
|
||||
|
||||
function mapperDms(data) {
|
||||
const formData = new FormData();
|
||||
const { files } = data;
|
||||
if (files) formData.append(files?.name, files);
|
||||
delete data.files;
|
||||
|
||||
const dms = {
|
||||
hasFile: !!data.hasFile,
|
||||
hasFileAttached: data.hasFileAttached,
|
||||
reference: data.reference,
|
||||
warehouseId: data.warehouseFk,
|
||||
companyId: data.companyFk,
|
||||
dmsTypeId: data.dmsTypeFk,
|
||||
description: data.description,
|
||||
};
|
||||
return [formData, { params: dms }];
|
||||
}
|
||||
|
||||
function getUrl() {
|
||||
if ($props.formInitialData) return 'dms/' + $props.formInitialData.id + '/updateFile';
|
||||
return `${$props.model}/${route.params.id}/uploadFile`;
|
||||
}
|
||||
|
||||
async function save() {
|
||||
const body = mapperDms(dms.value);
|
||||
await axios.post(getUrl(), body[0], body[1]);
|
||||
emit('onDataSaved', body[1].params);
|
||||
}
|
||||
|
||||
function defaultData() {
|
||||
if ($props.formInitialData) return (dms.value = $props.formInitialData);
|
||||
return addDefaultData({
|
||||
reference: route.params.id,
|
||||
});
|
||||
}
|
||||
|
||||
function setDmsTypes(data) {
|
||||
dmsTypes.value = data;
|
||||
if (!$props.formInitialData && $props.defaultDmsCode) {
|
||||
const { id } = data.find((dmsType) => dmsType.code == $props.defaultDmsCode);
|
||||
addDefaultData({ dmsTypeFk: id });
|
||||
}
|
||||
}
|
||||
|
||||
function addDefaultData(data) {
|
||||
Object.assign(dms.value, data);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData url="Warehouses" @on-fetch="(data) => (warehouses = data)" auto-load />
|
||||
<FetchData url="Companies" @on-fetch="(data) => (companies = data)" auto-load />
|
||||
<FetchData url="DmsTypes" @on-fetch="setDmsTypes" auto-load />
|
||||
<FetchData
|
||||
url="DmsContainers/allowedContentTypes"
|
||||
@on-fetch="(data) => (allowedContentTypes = data.join(','))"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="UserConfigs/getUserConfig"
|
||||
@on-fetch="addDefaultData"
|
||||
:auto-load="!$props.formInitialData"
|
||||
/>
|
||||
<FormModelPopup
|
||||
:title="formInitialData ? t('globals.edit') : t('globals.create')"
|
||||
model="dms"
|
||||
:form-initial-data="formInitialData"
|
||||
:save-fn="save"
|
||||
>
|
||||
<template #form-inputs>
|
||||
<div class="q-gutter-y-ms">
|
||||
<VnRow>
|
||||
<VnInput :label="t('globals.reference')" v-model="dms.reference" />
|
||||
<VnSelectFilter
|
||||
:label="t('globals.company')"
|
||||
v-model="dms.companyFk"
|
||||
:options="companies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
input-debounce="0"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelectFilter
|
||||
:label="t('globals.warehouse')"
|
||||
v-model="dms.warehouseFk"
|
||||
:options="warehouses"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
input-debounce="0"
|
||||
/>
|
||||
<VnSelectFilter
|
||||
:label="t('globals.type')"
|
||||
v-model="dms.dmsTypeFk"
|
||||
:options="dmsTypes"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
input-debounce="0"
|
||||
/>
|
||||
</VnRow>
|
||||
<QInput
|
||||
:label="t('globals.description')"
|
||||
v-model="dms.description"
|
||||
type="textarea"
|
||||
/>
|
||||
<QFile
|
||||
ref="inputFileRef"
|
||||
:label="t('entry.buys.file')"
|
||||
v-model="dms.files"
|
||||
:multiple="false"
|
||||
:accept="allowedContentTypes"
|
||||
@update:model-value="onFileChange(dms.files)"
|
||||
class="required"
|
||||
:display-value="dms.file"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon
|
||||
name="vn:attach"
|
||||
class="cursor-pointer"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>{{ t('globals.selectFile') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{
|
||||
t('contentTypesInfo', { allowedContentTypes })
|
||||
}}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QFile>
|
||||
<QCheckbox
|
||||
v-model="dms.hasFile"
|
||||
:label="t('Generate identifier for original file')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</FormModelPopup>
|
||||
</template>
|
||||
<style scoped>
|
||||
.q-gutter-y-ms {
|
||||
display: grid;
|
||||
row-gap: 20px;
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
en:
|
||||
contentTypesInfo: Allowed file types {allowedContentTypes}
|
||||
EntryDmsDescription: Reference {reference}
|
||||
es:
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
contentTypesInfo: Tipos de archivo permitidos {allowedContentTypes}
|
||||
EntryDmsDescription: Referencia {reference}
|
||||
|
||||
</i18n>
|
|
@ -0,0 +1,316 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar';
|
||||
import axios from 'axios';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnDms from 'src/components/common/VnDms.vue';
|
||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
|
||||
const route = useRoute();
|
||||
const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
const rows = ref();
|
||||
const dmsRef = ref();
|
||||
const formDialog = ref({});
|
||||
|
||||
const $props = defineProps({
|
||||
model: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
updateModel: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
defaultDmsCode: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
filter: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const dmsFilter = {
|
||||
include: {
|
||||
relation: 'dms',
|
||||
scope: {
|
||||
fields: [
|
||||
'dmsTypeFk',
|
||||
'reference',
|
||||
'hardCopyNumber',
|
||||
'workerFk',
|
||||
'description',
|
||||
'hasFile',
|
||||
'file',
|
||||
'created',
|
||||
'companyFk',
|
||||
'warehouseFk',
|
||||
],
|
||||
include: [
|
||||
{
|
||||
relation: 'dmsType',
|
||||
scope: {
|
||||
fields: ['name'],
|
||||
},
|
||||
},
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['id'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['name'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
order: ['dmsFk DESC'],
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
field: 'id',
|
||||
label: t('globals.id'),
|
||||
name: 'id',
|
||||
component: 'span',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'type',
|
||||
label: t('globals.type'),
|
||||
name: 'type',
|
||||
component: QInput,
|
||||
props: (prop) => ({
|
||||
readonly: true,
|
||||
borderless: true,
|
||||
'model-value': prop.row.dmsType.name,
|
||||
}),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'order',
|
||||
label: t('globals.order'),
|
||||
name: 'order',
|
||||
component: 'span',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'reference',
|
||||
label: t('globals.reference'),
|
||||
name: 'reference',
|
||||
component: 'span',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'description',
|
||||
label: t('globals.description'),
|
||||
name: 'description',
|
||||
component: 'span',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'hasFile',
|
||||
label: t('globals.original'),
|
||||
name: 'hasFile',
|
||||
component: QCheckbox,
|
||||
props: (prop) => ({
|
||||
disable: true,
|
||||
'model-value': Boolean(prop.value),
|
||||
}),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'file',
|
||||
label: t('globals.file'),
|
||||
name: 'file',
|
||||
component: 'span',
|
||||
},
|
||||
{
|
||||
field: 'options',
|
||||
name: 'options',
|
||||
components: [
|
||||
{
|
||||
component: QBtn,
|
||||
props: () => ({
|
||||
icon: 'cloud_download',
|
||||
flat: true,
|
||||
color: 'primary',
|
||||
}),
|
||||
click: (prop) => downloadFile(prop.row.id),
|
||||
},
|
||||
{
|
||||
component: QBtn,
|
||||
props: () => ({
|
||||
icon: 'edit',
|
||||
flat: true,
|
||||
color: 'primary',
|
||||
}),
|
||||
click: (prop) => showFormDialog(prop.row),
|
||||
},
|
||||
{
|
||||
component: QBtn,
|
||||
props: () => ({
|
||||
icon: 'delete',
|
||||
flat: true,
|
||||
color: 'primary',
|
||||
}),
|
||||
click: (prop) => deleteDms(prop.row.id),
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
function setData(data) {
|
||||
const newData = data.map((value) => value.dms);
|
||||
rows.value = newData;
|
||||
}
|
||||
|
||||
function deleteDms(dmsFk) {
|
||||
quasar
|
||||
.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
title: t('globals.confirmDeletion'),
|
||||
message: t('globals.confirmDeletionMessage'),
|
||||
},
|
||||
})
|
||||
.onOk(async () => {
|
||||
await axios.post(`${$props.model}/${dmsFk}/removeFile`);
|
||||
const index = rows.value.findIndex((row) => row.id == dmsFk);
|
||||
rows.value.splice(index, 1);
|
||||
});
|
||||
}
|
||||
|
||||
function showFormDialog(dms) {
|
||||
if (dms) dms = parseDms(dms);
|
||||
formDialog.value = {
|
||||
show: true,
|
||||
dms,
|
||||
};
|
||||
}
|
||||
|
||||
function parseDms(data) {
|
||||
for (let prop in data) {
|
||||
if (prop.endsWith('Fk')) data[prop.replace('Fk', 'Id')] = data[prop];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
ref="dmsRef"
|
||||
:url="$props.model"
|
||||
:filter="dmsFilter"
|
||||
:where="{ [$props.filter]: route.params.id }"
|
||||
@on-fetch="setData"
|
||||
auto-load
|
||||
/>
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:pagination="{ rowsPerPage: 0 }"
|
||||
:rows="rows"
|
||||
class="full-width q-mt-md"
|
||||
hide-bottom
|
||||
row-key="clientFk"
|
||||
:grid="$q.screen.lt.sm"
|
||||
>
|
||||
<template #body-cell="props">
|
||||
<QTd :props="props">
|
||||
<QTr :props="props">
|
||||
<component
|
||||
v-if="props.col.component"
|
||||
:is="props.col.component"
|
||||
v-bind="props.col.props && props.col.props(props)"
|
||||
>
|
||||
<span
|
||||
v-if="props.col.component == 'span'"
|
||||
style="white-space: wrap"
|
||||
>{{ props.value }}</span
|
||||
>
|
||||
</component>
|
||||
</QTr>
|
||||
|
||||
<div class="flex justify-center" v-if="props.col.name == 'options'">
|
||||
<div v-for="button of props.col.components" :key="button.id">
|
||||
<component
|
||||
:is="button.component"
|
||||
v-bind="button.props(props)"
|
||||
@click="button.click(props)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard
|
||||
bordered
|
||||
flat
|
||||
@keyup.ctrl.enter.stop="claimDevelopmentForm?.saveChanges()"
|
||||
>
|
||||
<QSeparator />
|
||||
<QList dense>
|
||||
<QItem v-for="col in props.cols" :key="col.name">
|
||||
<div v-if="col.name != 'options'" class="row">
|
||||
<span class="labelColor">{{ col.label }}:</span>
|
||||
<span>{{ col.value }}</span>
|
||||
</div>
|
||||
<div v-if="col.name == 'options'" class="row">
|
||||
<div
|
||||
v-for="button of col.components"
|
||||
:key="button.id"
|
||||
class="row"
|
||||
>
|
||||
<component
|
||||
:is="button.component"
|
||||
v-bind="button.props(col)"
|
||||
@click="button.click(col)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</QTable>
|
||||
<QDialog v-model="formDialog.show">
|
||||
<VnDms
|
||||
:model="updateModel ?? model"
|
||||
:default-dms-code="defaultDmsCode"
|
||||
:form-initial-data="formDialog.dms"
|
||||
@on-data-saved="dmsRef.fetch()"
|
||||
:description="$props.description"
|
||||
/>
|
||||
</QDialog>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn fab color="primary" icon="add" @click="showFormDialog()" />
|
||||
</QPageSticky>
|
||||
</template>
|
||||
<style scoped>
|
||||
.q-gutter-y-ms {
|
||||
display: grid;
|
||||
row-gap: 20px;
|
||||
}
|
||||
.labelColor {
|
||||
color: var(--vn-label);
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
en:
|
||||
contentTypesInfo: Allowed file types {allowedContentTypes}
|
||||
es:
|
||||
contentTypesInfo: Tipos de archivo permitidos {allowedContentTypes}
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
</i18n>
|
|
@ -94,16 +94,6 @@ async function send() {
|
|||
<QSpace />
|
||||
<QBtn icon="close" :disable="isLoading" flat round dense v-close-popup />
|
||||
</QCardSection>
|
||||
<QCardSection v-if="props.locale">
|
||||
<QBanner class="bg-amber text-white" rounded dense>
|
||||
<template #avatar>
|
||||
<QIcon name="warning" />
|
||||
</template>
|
||||
<span
|
||||
v-html="t('CustomerDefaultLanguage', { locale: t(props.locale) })"
|
||||
></span>
|
||||
</QBanner>
|
||||
</QCardSection>
|
||||
<QCardSection class="q-pb-xs">
|
||||
<QSelect
|
||||
:label="t('Language')"
|
||||
|
@ -184,7 +174,6 @@ async function send() {
|
|||
|
||||
<i18n>
|
||||
en:
|
||||
CustomerDefaultLanguage: This customer uses <strong>{locale}</strong> as their default language
|
||||
templates:
|
||||
pendingPayment: 'Your order is pending of payment.
|
||||
Please, enter the website and make the payment with a credit card. Thank you.'
|
||||
|
@ -197,7 +186,6 @@ en:
|
|||
pt: Portuguese
|
||||
es:
|
||||
Send SMS: Enviar SMS
|
||||
CustomerDefaultLanguage: Este cliente utiliza <strong>{locale}</strong> como idioma por defecto
|
||||
Language: Idioma
|
||||
Phone: Móvil
|
||||
Subject: Asunto
|
||||
|
|
|
@ -188,16 +188,18 @@ const emit = defineEmits(['onFetch']);
|
|||
.label {
|
||||
color: var(--vn-label);
|
||||
font-size: 12px;
|
||||
width: 47%;
|
||||
::after {
|
||||
content: ':';
|
||||
}
|
||||
}
|
||||
.value {
|
||||
color: var(--vn-text);
|
||||
font-size: 14px;
|
||||
margin-left: 12px;
|
||||
width: 47%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
.info {
|
||||
margin-left: 5px;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useClipboard } from 'src/composables/useClipboard';
|
||||
|
||||
const $props = defineProps({
|
||||
label: { type: String, default: null },
|
||||
value: {
|
||||
|
@ -13,8 +14,9 @@ const $props = defineProps({
|
|||
dash: { type: Boolean, default: true },
|
||||
copy: { type: Boolean, default: false },
|
||||
});
|
||||
const isBooleanValue = computed(() => typeof $props.value === 'boolean');
|
||||
|
||||
const { t } = useI18n();
|
||||
const isBooleanValue = computed(() => typeof $props.value === 'boolean');
|
||||
const { copyText } = useClipboard();
|
||||
|
||||
function copyValueText() {
|
||||
|
@ -54,22 +56,29 @@ function copyValueText() {
|
|||
</slot>
|
||||
</div>
|
||||
<div class="info" v-if="$props.info">
|
||||
<QIcon name="info">
|
||||
<QIcon name="info" class="cursor-pointer" size="xs" color="grey">
|
||||
<QTooltip class="bg-dark text-white shadow-4" :offset="[10, 10]">
|
||||
{{ $props.info }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</div>
|
||||
<div class="copy" v-if="$props.copy && $props.value" @click="copyValueText()">
|
||||
<QIcon name="Content_Copy" color="primary" />
|
||||
<QIcon name="Content_Copy" color="primary">
|
||||
<QTooltip>{{ t('globals.copyClipboard') }}</QTooltip>
|
||||
</QIcon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vn-label-value:hover .copy {
|
||||
visibility: visible;
|
||||
cursor: pointer;
|
||||
}
|
||||
.copy {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
visibility: hidden;
|
||||
}
|
||||
.info {
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<template>
|
||||
<div id="row">
|
||||
<div id="row" class="q-gutter-md">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scopped>
|
||||
#row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
#row {
|
||||
flex-direction: column;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -24,6 +24,7 @@ export default {
|
|||
dataCreated: 'Data created',
|
||||
add: 'Add',
|
||||
create: 'Create',
|
||||
edit: 'Edit',
|
||||
save: 'Save',
|
||||
remove: 'Remove',
|
||||
reset: 'Reset',
|
||||
|
@ -64,12 +65,23 @@ export default {
|
|||
markAll: 'Mark all',
|
||||
requiredField: 'Required field',
|
||||
class: 'clase',
|
||||
type: 'type',
|
||||
type: 'Type',
|
||||
reason: 'reason',
|
||||
noResults: 'No results',
|
||||
system: 'System',
|
||||
warehouse: 'Warehouse',
|
||||
company: 'Company',
|
||||
fieldRequired: 'Field required',
|
||||
allowedFilesText: 'Allowed file types: { allowedContentTypes }',
|
||||
confirmDeletion: 'Confirm deletion',
|
||||
confirmDeletionMessage: 'Are you sure you want to delete this?',
|
||||
description: 'Description',
|
||||
id: 'Id',
|
||||
order: 'Order',
|
||||
original: 'Original',
|
||||
file: 'File',
|
||||
selectFile: 'Select a file',
|
||||
copyClipboard: 'Copy on clipboard',
|
||||
},
|
||||
errors: {
|
||||
statusUnauthorized: 'Access denied',
|
||||
|
@ -77,7 +89,7 @@ export default {
|
|||
statusBadGateway: 'It seems that the server has fall down',
|
||||
statusGatewayTimeout: 'Could not contact the server',
|
||||
userConfig: 'Error fetching user config',
|
||||
create: 'Error during creation',
|
||||
writeRequest: 'The requested operation could not be completed',
|
||||
},
|
||||
login: {
|
||||
title: 'Login',
|
||||
|
@ -166,7 +178,7 @@ export default {
|
|||
fiscalAddress: 'Fiscal address',
|
||||
fiscalData: 'Fiscal data',
|
||||
billingData: 'Billing data',
|
||||
consignee: 'Consignee',
|
||||
consignee: 'Default consignee',
|
||||
businessData: 'Business data',
|
||||
financialData: 'Financial data',
|
||||
customerId: 'Customer ID',
|
||||
|
@ -219,6 +231,8 @@ export default {
|
|||
recoverySince: 'Recovery since',
|
||||
businessType: 'Business Type',
|
||||
city: 'City',
|
||||
rating: 'Rating',
|
||||
recommendCredit: 'Recommended credit',
|
||||
},
|
||||
basicData: {
|
||||
socialName: 'Fiscal name',
|
||||
|
@ -273,6 +287,7 @@ export default {
|
|||
basicData: 'Basic data',
|
||||
buys: 'Buys',
|
||||
notes: 'Notes',
|
||||
dms: 'File management',
|
||||
log: 'Log',
|
||||
create: 'Create',
|
||||
latestBuys: 'Latest buys',
|
||||
|
@ -344,7 +359,6 @@ export default {
|
|||
reference: 'Reference',
|
||||
observations: 'Observations',
|
||||
item: 'Item',
|
||||
description: 'Description',
|
||||
size: 'Size',
|
||||
packing: 'Packing',
|
||||
grouping: 'Grouping',
|
||||
|
@ -359,7 +373,6 @@ export default {
|
|||
},
|
||||
notes: {
|
||||
observationType: 'Observation type',
|
||||
description: 'Description',
|
||||
},
|
||||
descriptor: {
|
||||
agency: 'Agency',
|
||||
|
@ -372,7 +385,6 @@ export default {
|
|||
packing: 'Packing',
|
||||
grouping: 'Grouping',
|
||||
quantity: 'Quantity',
|
||||
description: 'Description',
|
||||
size: 'Size',
|
||||
tags: 'Tags',
|
||||
type: 'Type',
|
||||
|
@ -458,7 +470,6 @@ export default {
|
|||
visible: 'Visible',
|
||||
available: 'Available',
|
||||
quantity: 'Quantity',
|
||||
description: 'Description',
|
||||
price: 'Price',
|
||||
discount: 'Discount',
|
||||
packing: 'Packing',
|
||||
|
@ -531,7 +542,6 @@ export default {
|
|||
landed: 'Landed',
|
||||
quantity: 'Quantity',
|
||||
claimed: 'Claimed',
|
||||
description: 'Description',
|
||||
price: 'Price',
|
||||
discount: 'Discount',
|
||||
total: 'Total',
|
||||
|
@ -793,7 +803,6 @@ export default {
|
|||
orderTicketList: 'Order Ticket List',
|
||||
details: 'Details',
|
||||
item: 'Item',
|
||||
description: 'Description',
|
||||
quantity: 'Quantity',
|
||||
price: 'Price',
|
||||
amount: 'Amount',
|
||||
|
@ -1138,7 +1147,6 @@ export default {
|
|||
warehouse: 'Warehouse',
|
||||
travelFileDescription: 'Travel id { travelId }',
|
||||
file: 'File',
|
||||
description: 'Description',
|
||||
},
|
||||
},
|
||||
item: {
|
||||
|
@ -1172,7 +1180,6 @@ export default {
|
|||
clone: 'Clone',
|
||||
openCard: 'View',
|
||||
openSummary: 'Summary',
|
||||
viewDescription: 'Description',
|
||||
},
|
||||
cardDescriptor: {
|
||||
mainList: 'Main list',
|
||||
|
|
|
@ -24,6 +24,7 @@ export default {
|
|||
dataCreated: 'Datos creados',
|
||||
add: 'Añadir',
|
||||
create: 'Crear',
|
||||
edit: 'Modificar',
|
||||
save: 'Guardar',
|
||||
remove: 'Eliminar',
|
||||
reset: 'Restaurar',
|
||||
|
@ -64,12 +65,23 @@ export default {
|
|||
markAll: 'Marcar todo',
|
||||
requiredField: 'Campo obligatorio',
|
||||
class: 'clase',
|
||||
type: 'tipo',
|
||||
type: 'Tipo',
|
||||
reason: 'motivo',
|
||||
noResults: 'Sin resultados',
|
||||
system: 'Sistema',
|
||||
warehouse: 'Almacén',
|
||||
company: 'Empresa',
|
||||
fieldRequired: 'Campo requerido',
|
||||
allowedFilesText: 'Tipos de archivo permitidos: { allowedContentTypes }',
|
||||
confirmDeletion: 'Confirmar eliminación',
|
||||
confirmDeletionMessage: '¿Seguro que quieres eliminar?',
|
||||
description: 'Descripción',
|
||||
id: 'Id',
|
||||
order: 'Orden',
|
||||
original: 'Original',
|
||||
file: 'Fichero',
|
||||
selectFile: 'Seleccione un fichero',
|
||||
copyClipboard: 'Copiar en portapapeles',
|
||||
},
|
||||
errors: {
|
||||
statusUnauthorized: 'Acceso denegado',
|
||||
|
@ -77,7 +89,7 @@ export default {
|
|||
statusBadGateway: 'Parece ser que el servidor ha caído',
|
||||
statusGatewayTimeout: 'No se ha podido contactar con el servidor',
|
||||
userConfig: 'Error al obtener configuración de usuario',
|
||||
create: 'Error al crear',
|
||||
writeRequest: 'No se pudo completar la operación solicitada',
|
||||
},
|
||||
login: {
|
||||
title: 'Inicio de sesión',
|
||||
|
@ -165,7 +177,7 @@ export default {
|
|||
fiscalAddress: 'Dirección fiscal',
|
||||
fiscalData: 'Datos fiscales',
|
||||
billingData: 'Datos de facturación',
|
||||
consignee: 'Consignatario',
|
||||
consignee: 'Consignatario pred.',
|
||||
businessData: 'Datos comerciales',
|
||||
financialData: 'Datos financieros',
|
||||
customerId: 'ID cliente',
|
||||
|
@ -218,6 +230,8 @@ export default {
|
|||
recoverySince: 'Recobro desde',
|
||||
businessType: 'Tipo de negocio',
|
||||
city: 'Población',
|
||||
rating: 'Clasificación',
|
||||
recommendCredit: 'Crédito recomendado',
|
||||
},
|
||||
basicData: {
|
||||
socialName: 'Nombre fiscal',
|
||||
|
@ -272,6 +286,7 @@ export default {
|
|||
basicData: 'Datos básicos',
|
||||
buys: 'Compras',
|
||||
notes: 'Notas',
|
||||
dms: 'Gestión documental',
|
||||
log: 'Historial',
|
||||
create: 'Crear',
|
||||
latestBuys: 'Últimas compras',
|
||||
|
@ -343,7 +358,6 @@ export default {
|
|||
reference: 'Referencia',
|
||||
observations: 'Observaciónes',
|
||||
item: 'Artículo',
|
||||
description: 'Descripción',
|
||||
size: 'Medida',
|
||||
packing: 'Packing',
|
||||
grouping: 'Grouping',
|
||||
|
@ -358,7 +372,6 @@ export default {
|
|||
},
|
||||
notes: {
|
||||
observationType: 'Tipo de observación',
|
||||
description: 'Descripción',
|
||||
},
|
||||
descriptor: {
|
||||
agency: 'Agencia',
|
||||
|
@ -371,7 +384,6 @@ export default {
|
|||
packing: 'Packing',
|
||||
grouping: 'Grouping',
|
||||
quantity: 'Cantidad',
|
||||
description: 'Descripción',
|
||||
size: 'Medida',
|
||||
tags: 'Etiquetas',
|
||||
type: 'Tipo',
|
||||
|
@ -457,7 +469,6 @@ export default {
|
|||
visible: 'Visible',
|
||||
available: 'Disponible',
|
||||
quantity: 'Cantidad',
|
||||
description: 'Descripción',
|
||||
price: 'Precio',
|
||||
discount: 'Descuento',
|
||||
packing: 'Encajado',
|
||||
|
@ -530,7 +541,6 @@ export default {
|
|||
landed: 'Entregado',
|
||||
quantity: 'Cantidad',
|
||||
claimed: 'Reclamado',
|
||||
description: 'Descripción',
|
||||
price: 'Precio',
|
||||
discount: 'Descuento',
|
||||
total: 'Total',
|
||||
|
@ -701,7 +711,6 @@ export default {
|
|||
orderTicketList: 'Tickets del pedido',
|
||||
details: 'Detalles',
|
||||
item: 'Item',
|
||||
description: 'Descripción',
|
||||
quantity: 'Cantidad',
|
||||
price: 'Precio',
|
||||
amount: 'Monto',
|
||||
|
@ -1138,7 +1147,6 @@ export default {
|
|||
warehouse: 'Almacén',
|
||||
travelFileDescription: 'Id envío { travelId }',
|
||||
file: 'Fichero',
|
||||
description: 'Descripción',
|
||||
},
|
||||
},
|
||||
item: {
|
||||
|
@ -1172,7 +1180,6 @@ export default {
|
|||
clone: 'Clonar',
|
||||
openCard: 'Ficha',
|
||||
openSummary: 'Detalles',
|
||||
viewDescription: 'Descripción',
|
||||
},
|
||||
cardDescriptor: {
|
||||
mainList: 'Listado principal',
|
||||
|
|
|
@ -35,7 +35,6 @@ const claimDmsFilter = ref({
|
|||
relation: 'dms',
|
||||
},
|
||||
],
|
||||
where: { claimFk: entityId.value },
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
|
@ -141,6 +140,11 @@ const claimDms = ref([]);
|
|||
const multimediaDialog = ref();
|
||||
const multimediaSlide = ref();
|
||||
|
||||
async function getClaimDms() {
|
||||
claimDmsFilter.value.where = { claimFk: entityId.value };
|
||||
await claimDmsRef.value.fetch();
|
||||
}
|
||||
|
||||
function setClaimDms(data) {
|
||||
claimDms.value = [];
|
||||
data.forEach((media) => {
|
||||
|
@ -163,10 +167,13 @@ function openDialog(dmsId) {
|
|||
url="ClaimDms"
|
||||
:filter="claimDmsFilter"
|
||||
@on-fetch="(data) => setClaimDms(data)"
|
||||
limit="20"
|
||||
ref="claimDmsRef"
|
||||
/>
|
||||
<CardSummary ref="summary" :url="`Claims/${entityId}/getSummary`">
|
||||
<CardSummary
|
||||
ref="summary"
|
||||
:url="`Claims/${entityId}/getSummary`"
|
||||
@on-fetch="getClaimDms"
|
||||
>
|
||||
<template #header="{ entity: { claim } }">
|
||||
{{ claim.id }} - {{ claim.client.name }}
|
||||
</template>
|
||||
|
@ -252,7 +259,8 @@ function openDialog(dmsId) {
|
|||
>
|
||||
<ItemDescriptorProxy
|
||||
v-if="col.name == 'description'"
|
||||
:id="2"
|
||||
:id="props.row.id"
|
||||
:sale-fk="props.row.saleFk"
|
||||
></ItemDescriptorProxy>
|
||||
</QTh>
|
||||
</QTr>
|
||||
|
@ -274,7 +282,6 @@ function openDialog(dmsId) {
|
|||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
|
||||
<QCard class="vn-max" v-if="claimDms.length > 0">
|
||||
<a class="header" :href="`#/claim/${entityId}/photos`">
|
||||
{{ t('claim.summary.photos') }}
|
||||
|
|
|
@ -116,7 +116,13 @@ function navigate(event, id) {
|
|||
</template>
|
||||
<template #actions>
|
||||
<QBtn
|
||||
:label="t('components.smartCard.viewDescription')"
|
||||
:label="t('components.smartCard.openCard')"
|
||||
@click.stop="navigate(row.id)"
|
||||
class="bg-vn-dark"
|
||||
outline
|
||||
/>
|
||||
<QBtn
|
||||
:label="t('globals.description')"
|
||||
@click.stop
|
||||
class="bg-vn-dark"
|
||||
outline
|
||||
|
|
|
@ -122,7 +122,7 @@ const creditWarning = computed(() => {
|
|||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<a class="header link" :href="clientUrl + `fiscal-data`" link>
|
||||
{{ t('customer.summary.fiscalAddress') }}
|
||||
{{ t('customer.summary.fiscalData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<VnLv
|
||||
|
@ -235,7 +235,8 @@ const creditWarning = computed(() => {
|
|||
link
|
||||
>
|
||||
{{ t('customer.summary.financialData') }}
|
||||
<QIcon name="vn:grafana" color="primary" />
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
<!-- Pendiente de añadir el icono <QIcon name="vn:grafana" color="primary" /> -->
|
||||
</a>
|
||||
<VnLv
|
||||
:label="t('customer.summary.risk')"
|
||||
|
@ -276,7 +277,30 @@ const creditWarning = computed(() => {
|
|||
:label="t('customer.summary.recoverySince')"
|
||||
:value="toDate(entity.recovery.started)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('customer.summary.rating')"
|
||||
:value="entity.rating"
|
||||
:info="t('valueInfo', { min: 1, max: 20 })"
|
||||
/>
|
||||
|
||||
<VnLv
|
||||
:label="t('customer.summary.recommendCredit')"
|
||||
:value="entity.recommendedCredit"
|
||||
/>
|
||||
</QCard>
|
||||
</template>
|
||||
</CardSummary>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
@media (min-width: $breakpoint-md) {
|
||||
.summary .vn-one {
|
||||
min-width: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
en:
|
||||
valueInfo: Value from {min} to {max}. The higher the better value
|
||||
es:
|
||||
valueInfo: Valor de {min} a {max}. Cuanto más alto, mejor valor
|
||||
</i18n>
|
||||
|
|
|
@ -13,7 +13,7 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|||
|
||||
import { useArrayData } from 'composables/useArrayData';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { dashIfEmpty, toDate } from 'src/filters';
|
||||
import { toDate } from 'src/filters';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
@ -477,17 +477,11 @@ const stopEventPropagation = (event, col) => {
|
|||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const navigateToTravelId = (id) => {
|
||||
router.push({ path: `/customer/${id}` });
|
||||
};
|
||||
const navigateToTravelId = (id) => router.push({ path: `/customer/${id}` });
|
||||
|
||||
const selectCustomerId = (id) => {
|
||||
selectedCustomerId.value = id;
|
||||
};
|
||||
const selectCustomerId = (id) => (selectedCustomerId.value = id);
|
||||
|
||||
const selectSalesPersonId = (id) => {
|
||||
selectedSalesPersonId.value = id;
|
||||
};
|
||||
const selectSalesPersonId = (id) => (selectedSalesPersonId.value = id);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -521,37 +515,50 @@ const selectSalesPersonId = (id) => {
|
|||
class="full-width q-mt-md"
|
||||
row-key="id"
|
||||
:visible-columns="visibleColumns"
|
||||
@row-click="(evt, row, id) => navigateToTravelId(row.id)"
|
||||
>
|
||||
<template #body="props">
|
||||
<QTr
|
||||
:props="props"
|
||||
@click="navigateToTravelId(props.row.id)"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
<QTd
|
||||
v-for="col in props.cols"
|
||||
:key="col.name"
|
||||
:props="props"
|
||||
@click="stopEventPropagation($event, col)"
|
||||
<template #body-cell="{ col, value }">
|
||||
<QTd @click="stopEventPropagation($event, col)">
|
||||
{{ value }}
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-id="props">
|
||||
<QTd @click="stopEventPropagation($event, props.col)">
|
||||
<component
|
||||
:is="tableColumnComponents[props.col.name].component"
|
||||
class="col-content"
|
||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||
@click="tableColumnComponents[props.col.name].event(props)"
|
||||
>
|
||||
<component
|
||||
:is="tableColumnComponents[col.name].component"
|
||||
class="col-content"
|
||||
v-bind="tableColumnComponents[col.name].props(props)"
|
||||
@click="tableColumnComponents[col.name].event(props)"
|
||||
>
|
||||
{{ dashIfEmpty(col.value) }}
|
||||
<WorkerDescriptorProxy
|
||||
v-if="props.row.salesPersonFk"
|
||||
:id="selectedSalesPersonId"
|
||||
/>
|
||||
<CustomerDescriptorProxy
|
||||
v-if="props.row.id"
|
||||
:id="selectedCustomerId"
|
||||
/>
|
||||
</component>
|
||||
</QTd>
|
||||
</QTr>
|
||||
<CustomerDescriptorProxy :id="props.row.id" />
|
||||
{{ props.row.id }}
|
||||
</component>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-salesPersonFk="props">
|
||||
<QTd @click="stopEventPropagation($event, props.col)">
|
||||
<component
|
||||
v-if="props.row.salesPerson"
|
||||
class="col-content"
|
||||
:is="tableColumnComponents[props.col.name].component"
|
||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||
@click="tableColumnComponents[props.col.name].event(props)"
|
||||
>
|
||||
<WorkerDescriptorProxy :id="props.row.salesPersonFk" />
|
||||
{{ props.row.salesPerson }}
|
||||
</component>
|
||||
<span class="col-content" v-else>-</span>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-actions="props">
|
||||
<QTd @click="stopEventPropagation($event, props.col)">
|
||||
<component
|
||||
:is="tableColumnComponents[props.col.name].component"
|
||||
class="col-content"
|
||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||
@click="tableColumnComponents[props.col.name].event(props)"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
</QPage>
|
||||
|
|
|
@ -44,7 +44,7 @@ const columns = computed(() => [
|
|||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('entry.buys.description'),
|
||||
label: t('globals.description'),
|
||||
name: 'description',
|
||||
field: 'description',
|
||||
align: 'left',
|
||||
|
@ -214,7 +214,7 @@ const redirectToBuysView = () => {
|
|||
class="cursor-pointer"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>{{ t('Select a file') }}</QTooltip>
|
||||
<QTooltip>{{ t('globals.selectFile') }}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QFile>
|
||||
|
@ -292,6 +292,6 @@ const redirectToBuysView = () => {
|
|||
|
||||
<i18n>
|
||||
es:
|
||||
Select a file: Selecciona un fichero
|
||||
globals.selectFile: Selecciona un fichero
|
||||
Some of the imported buys does not have an item: Algunas de las compras importadas no tienen un artículo
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<script setup>
|
||||
import VnDmsList from 'src/components/common/VnDmsList.vue';
|
||||
</script>
|
||||
<template>
|
||||
<VnDmsList
|
||||
model="EntryDms"
|
||||
update-model="EntryDms"
|
||||
default-dms-code="entry"
|
||||
filter="entryFk"
|
||||
/>
|
||||
</template>
|
|
@ -63,7 +63,7 @@ onMounted(() => {
|
|||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('entry.notes.description')"
|
||||
:label="t('globals.description')"
|
||||
v-model="row.description"
|
||||
:rules="validate('EntryObservation.description')"
|
||||
/>
|
||||
|
|
|
@ -59,7 +59,7 @@ const columns = computed(() => [
|
|||
align: 'left',
|
||||
},
|
||||
{
|
||||
label: t('entry.latestBuys.description'),
|
||||
label: t('globals.description'),
|
||||
field: 'description',
|
||||
name: 'description',
|
||||
align: 'left',
|
||||
|
@ -214,7 +214,7 @@ const editTableCellFormFieldsOptions = [
|
|||
{ field: 'grouping', label: t('entry.latestBuys.grouping') },
|
||||
{ field: 'packageValue', label: t('entry.latestBuys.packageValue') },
|
||||
{ field: 'weight', label: t('entry.latestBuys.weight') },
|
||||
{ field: 'description', label: t('entry.latestBuys.description') },
|
||||
{ field: 'description', label: t('globals.description') },
|
||||
{ field: 'size', label: t('entry.latestBuys.size') },
|
||||
{ field: 'weightByPiece', label: t('entry.latestBuys.weightByPiece') },
|
||||
{ field: 'packingOut', label: t('entry.latestBuys.packingOut') },
|
||||
|
|
|
@ -174,7 +174,12 @@ async function upsert() {
|
|||
@on-fetch="(data) => (userConfig = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FormModel v-if="invoiceIn" :url="`InvoiceIns/${route.params.id}`" model="invoiceIn">
|
||||
<FormModel
|
||||
v-if="invoiceIn"
|
||||
:url="`InvoiceIns/${route.params.id}`"
|
||||
model="invoiceIn"
|
||||
:auto-load="true"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
|
@ -509,7 +514,7 @@ async function upsert() {
|
|||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Select a file') }}
|
||||
{{ t('globals.selectFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn icon="info" flat round padding="xs">
|
||||
|
@ -618,7 +623,7 @@ async function upsert() {
|
|||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Select a file') }}
|
||||
{{ t('globals.selectFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn icon="info" flat round padding="xs">
|
||||
|
@ -687,7 +692,6 @@ async function upsert() {
|
|||
Generate identifier for original file: Generar identificador para archivo original
|
||||
File: Fichero
|
||||
Create document: Crear documento
|
||||
Select a file: Seleccione un fichero
|
||||
Allowed content types: Tipos de archivo permitidos
|
||||
The company can't be empty: La empresa no puede estar vacía
|
||||
The warehouse can't be empty: El almacén no puede estar vacío
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { computed, ref, onMounted, onUnmounted } from 'vue';
|
||||
import { computed, ref, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
@ -14,6 +14,7 @@ import EditPictureForm from 'components/EditPictureForm.vue';
|
|||
import { useState } from 'src/composables/useState';
|
||||
import useCardDescription from 'src/composables/useCardDescription';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
import { getUrl } from 'src/composables/getUrl';
|
||||
import axios from 'axios';
|
||||
|
||||
const $props = defineProps({
|
||||
|
@ -30,6 +31,10 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: null,
|
||||
},
|
||||
saleFk: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const quasar = useQuasar();
|
||||
|
@ -51,6 +56,7 @@ const available = ref(null);
|
|||
const visible = ref(null);
|
||||
const _warehouseFk = ref(null);
|
||||
const warehouseText = ref(null);
|
||||
const salixUrl = ref();
|
||||
const warehouseFk = computed({
|
||||
get() {
|
||||
return _warehouseFk.value;
|
||||
|
@ -69,6 +75,7 @@ const showEditPhotoForm = ref(false);
|
|||
onMounted(async () => {
|
||||
await getItemAvatar();
|
||||
warehouseFk.value = user.value.warehouseFk;
|
||||
salixUrl.value = await getUrl('');
|
||||
});
|
||||
|
||||
const getItemAvatar = async () => {
|
||||
|
@ -276,7 +283,16 @@ const openCloneDialog = async () => {
|
|||
<template #actions="{}">
|
||||
<QCardActions class="row justify-center">
|
||||
<QBtn
|
||||
:to="{ name: 'ItemDiary' }"
|
||||
:href="
|
||||
salixUrl +
|
||||
'item/' +
|
||||
entityId +
|
||||
'/diary?' +
|
||||
'warehouseFk=' +
|
||||
warehouseFk +
|
||||
'&lineFk=' +
|
||||
$props.saleFk
|
||||
"
|
||||
size="md"
|
||||
icon="vn:transaction"
|
||||
color="primary"
|
||||
|
|
|
@ -11,6 +11,10 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: null,
|
||||
},
|
||||
saleFk: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -21,6 +25,7 @@ const $props = defineProps({
|
|||
:id="$props.id"
|
||||
:summary="ItemSummary"
|
||||
:dated="dated"
|
||||
:sale-fk="saleFk"
|
||||
/>
|
||||
</QPopupProxy>
|
||||
</template>
|
||||
|
|
|
@ -199,7 +199,7 @@ const openBuscaman = async (route, ticket) => {
|
|||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<div class="header">
|
||||
{{ t('route.summary.description') }}
|
||||
{{ t('globals.description') }}
|
||||
</div>
|
||||
<p>
|
||||
{{ dashIfEmpty(entity?.route?.description) }}
|
||||
|
|
|
@ -270,7 +270,7 @@ async function changeState(value) {
|
|||
<QTh auto-width>{{ t('ticket.summary.visible') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.available') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.quantity') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.description') }}</QTh>
|
||||
<QTh auto-width>{{ t('globals.description') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.price') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.discount') }}</QTh>
|
||||
<QTh auto-width>{{ t('globals.amount') }}</QTh>
|
||||
|
@ -425,7 +425,7 @@ async function changeState(value) {
|
|||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh auto-width>{{ t('ticket.summary.quantity') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.description') }}</QTh>
|
||||
<QTh auto-width>{{ t('globals.description') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.price') }}</QTh>
|
||||
<QTh auto-width>{{ t('ticket.summary.taxClass') }}</QTh>
|
||||
<QTh auto-width>{{ t('globals.amount') }}</QTh>
|
||||
|
|
|
@ -300,7 +300,7 @@ const onThermographCreated = async (data) => {
|
|||
<VnRow v-if="viewAction === 'edit'" class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('travel.thermographs.description')"
|
||||
:label="t('globals.description')"
|
||||
type="textarea"
|
||||
v-model="thermographForm.description"
|
||||
fill-input
|
||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
|||
redirect: { name: 'EntryMain' },
|
||||
menus: {
|
||||
main: ['EntryList', 'EntryLatestBuys'],
|
||||
card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryLog'],
|
||||
card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
@ -95,6 +95,15 @@ export default {
|
|||
},
|
||||
component: () => import('src/pages/Entry/Card/EntryNotes.vue'),
|
||||
},
|
||||
{
|
||||
path: 'dms',
|
||||
name: 'EntryDms',
|
||||
meta: {
|
||||
title: 'dms',
|
||||
icon: 'smb_share',
|
||||
},
|
||||
component: () => import('src/pages/Entry/Card/EntryDms.vue'),
|
||||
},
|
||||
{
|
||||
path: 'log',
|
||||
name: 'EntryLog',
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('ClaimDevelopment', () => {
|
|||
it('should reset line', () => {
|
||||
cy.selectOption(firstLineReason, 'Novato');
|
||||
cy.resetCard();
|
||||
cy.getValue(firstLineReason).should('have.value', 'Prisas');
|
||||
cy.getValue(firstLineReason).should('equal', 'Prisas');
|
||||
});
|
||||
|
||||
it('should edit line', () => {
|
||||
|
@ -23,7 +23,7 @@ describe('ClaimDevelopment', () => {
|
|||
cy.login('developer');
|
||||
cy.visit(`/#/claim/${claimId}/development`);
|
||||
|
||||
cy.getValue(firstLineReason).should('have.value', 'Novato');
|
||||
cy.getValue(firstLineReason).should('equal', 'Novato');
|
||||
|
||||
//Restart data
|
||||
cy.selectOption(firstLineReason, 'Prisas');
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
describe('WagonTypeCreate', () => {
|
||||
const entryId = 1;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080);
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/entry/${entryId}/dms`);
|
||||
|
||||
});
|
||||
|
||||
it('should create edit and remove new dms', () => {
|
||||
cy.addRow();
|
||||
cy.get('.icon-attach').click()
|
||||
cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', {
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get("tbody > tr").then((value) => {
|
||||
//Create and check if exist new row
|
||||
let newFileTd = Cypress.$(value).length;
|
||||
cy.get('.q-btn--standard > .q-btn__content > .block').click();
|
||||
expect(value).to.have.length(newFileTd++);
|
||||
const newRowSelector = `tbody > :nth-child(${newFileTd})`
|
||||
cy.waitForElement(newRowSelector);
|
||||
|
||||
//Edit new dms
|
||||
const u = undefined;
|
||||
cy.validateRow(newRowSelector, [u,u,u,u,'ENTRADA ID 1'])
|
||||
cy.get(`tbody :nth-child(${newFileTd}) > .text-right > .flex > :nth-child(2) > .q-btn > .q-btn__content > .q-icon`).click();
|
||||
})
|
||||
// cy.log('newFileTd', newFileTd)
|
||||
|
||||
// //Create and check if exist new row
|
||||
// cy.log('newFileTd:', newFileTd);
|
||||
// cy.get(`tbody :nth-child(${newFileTd}) > .text-right > .flex > :nth-child(2) > .q-btn > .q-btn__content > .q-icon`).click()
|
||||
|
||||
// cy.get(`tbody :nth-child(${newFileTd}) > :nth-child(5) > .q-tr > :nth-child(1) > span`).then((value) => {
|
||||
// cy.log(value)
|
||||
// });
|
||||
});
|
||||
});
|
|
@ -18,7 +18,7 @@ describe('InvoiceInIntrastat', () => {
|
|||
cy.visit(`/#/invoice-in/1/intrastat`);
|
||||
|
||||
cy.getValue(firstLineCode).should(
|
||||
'have.value',
|
||||
'equal',
|
||||
'Plantas vivas: Esqueje/injerto, Vid'
|
||||
);
|
||||
});
|
||||
|
|
|
@ -21,7 +21,7 @@ describe('InvoiceInVat', () => {
|
|||
cy.saveCard();
|
||||
cy.visit(`/#/invoice-in/1/vat`);
|
||||
|
||||
cy.getValue(firstLineVat).should('have.value', 'H.P. IVA 21% CEE');
|
||||
cy.getValue(firstLineVat).should('equal', 'H.P. IVA 21% CEE');
|
||||
});
|
||||
|
||||
it('should add a new row', () => {
|
||||
|
|
|
@ -42,7 +42,7 @@ Cypress.Commands.add('login', (user) => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add('waitForElement', (element) => {
|
||||
cy.get(element, { timeout: 2000 }).should('be.visible');
|
||||
cy.get(element, { timeout: 5000 }).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('getValue', (selector) => {
|
||||
|
@ -55,7 +55,13 @@ Cypress.Commands.add('getValue', (selector) => {
|
|||
return cy.get(
|
||||
selector +
|
||||
'> .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > input'
|
||||
);
|
||||
).invoke('val')
|
||||
}
|
||||
// Si es un QSelect
|
||||
if ($el.find('span').length) {
|
||||
return cy.get(
|
||||
selector + ' span'
|
||||
).then(($span) => { return $span[0].innerText })
|
||||
}
|
||||
// Puedes añadir un log o lanzar un error si el elemento no es reconocido
|
||||
cy.log('Elemento no soportado');
|
||||
|
@ -126,12 +132,13 @@ Cypress.Commands.add('validateRow', (rowSelector, expectedValues) => {
|
|||
cy.get(rowSelector).within(() => {
|
||||
for (const [index, value] of expectedValues.entries()) {
|
||||
cy.log('CHECKING ', index, value);
|
||||
if(value === undefined) continue
|
||||
if (typeof value == 'boolean') {
|
||||
const prefix = value ? '' : 'not.';
|
||||
cy.getValue(`:nth-child(${index + 1})`).should(`${prefix}be.checked`);
|
||||
continue;
|
||||
}
|
||||
cy.getValue(`:nth-child(${index + 1})`).should('have.value', value);
|
||||
cy.getValue(`:nth-child(${index + 1})`).should('equal', value)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue