From 5b6a526932b0bdc232fd8ac8a05f5c0da378f9c3 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 29 Jan 2024 15:12:30 +0100
Subject: [PATCH 01/11] refs #5509 feat: VnDms feat: EntryDms

---
 src/components/FormModel.vue       |  2 +-
 src/components/common/VnDms.vue    | 75 ++++++++++++++++++++++++++++++
 src/components/ui/VnRow.vue        |  8 +++-
 src/components/ui/VnSubToolbar.vue |  2 +-
 src/i18n/en/index.js               |  4 ++
 src/i18n/es/index.js               |  4 ++
 src/pages/Entry/Card/EntryDms.vue  |  6 +++
 src/router/modules/entry.js        | 11 ++++-
 8 files changed, 107 insertions(+), 5 deletions(-)
 create mode 100644 src/components/common/VnDms.vue
 create mode 100644 src/pages/Entry/Card/EntryDms.vue

diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 4ad566bf8..153c086bb 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -128,7 +128,7 @@ async function save() {
 
     try {
         const body = $props.mapper ? $props.mapper(formData.value) : formData.value;
-        let response
+        let response;
         if ($props.urlCreate) {
             response = await axios.post($props.urlCreate, body);
             notify('globals.dataCreated', 'positive');
diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue
new file mode 100644
index 000000000..cdc54b786
--- /dev/null
+++ b/src/components/common/VnDms.vue
@@ -0,0 +1,75 @@
+<script setup>
+import { ref } from 'vue';
+import { useRoute } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+
+import FetchData from 'components/FetchData.vue';
+import FormModel from 'components/FormModel.vue';
+import VnRow from 'components/ui/VnRow.vue';
+import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
+import VnInput from 'src/components/common/VnInput.vue';
+
+const route = useRoute();
+const { t } = useI18n();
+
+const warehouses = ref();
+const companies = ref();
+const dmsTypes = ref();
+</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="(data) => (dmsTypes = data)" auto-load />
+    <FormModel
+        :url="`Dms/${route.params.id}`"
+        :url-update="`Claims/updateClaim/${route.params.id}`"
+        model="dms"
+    >
+        <template #form="{ data }">
+            <div class="q-gutter-y-ms">
+                <VnRow>
+                    <VnInput :label="t('Reference')" v-model="data.reference" />
+                    <VnSelectFilter
+                        :label="t('globals.company')"
+                        v-model="data.companyFk"
+                        :options="companies"
+                        option-value="id"
+                        option-label="code"
+                        input-debounce="0"
+                    />
+                </VnRow>
+                <VnRow>
+                    <VnSelectFilter
+                        :label="t('globals.warehouse')"
+                        v-model="data.warehouseFk"
+                        :options="warehouses"
+                        option-value="id"
+                        option-label="name"
+                        input-debounce="0"
+                    />
+                    <VnSelectFilter
+                        :label="t('globals.type')"
+                        v-model="data.dmsTypeFk"
+                        :options="dmsTypes"
+                        option-value="id"
+                        option-label="name"
+                        input-debounce="0"
+                    />
+                </VnRow>
+                <VnRow>
+                    <QInput
+                        :label="t('globals.description')"
+                        v-model="data.description"
+                        type="textarea"
+                    />
+                </VnRow>
+            </div>
+        </template>
+    </FormModel>
+</template>
+<style scoped>
+.q-gutter-y-ms {
+    display: grid;
+    row-gap: 20px;
+}
+</style>
diff --git a/src/components/ui/VnRow.vue b/src/components/ui/VnRow.vue
index c3c951528..e13730e62 100644
--- a/src/components/ui/VnRow.vue
+++ b/src/components/ui/VnRow.vue
@@ -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>
diff --git a/src/components/ui/VnSubToolbar.vue b/src/components/ui/VnSubToolbar.vue
index 81a1820f1..b314716ce 100644
--- a/src/components/ui/VnSubToolbar.vue
+++ b/src/components/ui/VnSubToolbar.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { onMounted, onUnmounted, ref } from 'vue';
+import { onMounted, onUnmounted } from 'vue';
 import { useStateStore } from 'stores/useStateStore';
 const stateStore = useStateStore();
 
diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js
index 1a7a4c27e..2f680280c 100644
--- a/src/i18n/en/index.js
+++ b/src/i18n/en/index.js
@@ -64,6 +64,9 @@ export default {
         markAll: 'Mark all',
         noResults: 'No results',
         system: 'System',
+        warehouse: 'Warehouse',
+        company: 'Company',
+        type: 'Type',
     },
     errors: {
         statusUnauthorized: 'Access denied',
@@ -265,6 +268,7 @@ export default {
             basicData: 'Basic data',
             buys: 'Buys',
             notes: 'Notes',
+            dms: 'File management',
             log: 'Log',
         },
         list: {
diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js
index 83de42ee0..023c339a4 100644
--- a/src/i18n/es/index.js
+++ b/src/i18n/es/index.js
@@ -64,6 +64,9 @@ export default {
         markAll: 'Marcar todo',
         noResults: 'Sin resultados',
         system: 'Sistema',
+        warehouse: 'Almacén',
+        company: 'Empresa',
+        type: 'Tipo',
     },
     errors: {
         statusUnauthorized: 'Acceso denegado',
@@ -264,6 +267,7 @@ export default {
             basicData: 'Datos básicos',
             buys: 'Compras',
             notes: 'Notas',
+            dms: 'Gestión documental',
             log: 'Historial',
         },
         list: {
diff --git a/src/pages/Entry/Card/EntryDms.vue b/src/pages/Entry/Card/EntryDms.vue
new file mode 100644
index 000000000..57e6eff53
--- /dev/null
+++ b/src/pages/Entry/Card/EntryDms.vue
@@ -0,0 +1,6 @@
+<script setup>
+import VnDms from 'src/components/common/VnDms.vue';
+</script>
+<template>
+    <VnDms model="Entry" />
+</template>
diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js
index 8d25a8e0c..3ac12d953 100644
--- a/src/router/modules/entry.js
+++ b/src/router/modules/entry.js
@@ -11,7 +11,7 @@ export default {
     redirect: { name: 'EntryMain' },
     menus: {
         main: ['EntryList'],
-        card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryLog'],
+        card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'],
     },
     children: [
         {
@@ -86,6 +86,15 @@ export default {
                     },
                     component: () => import('src/pages/Entry/Card/EntryNotes.vue'),
                 },
+                {
+                    path: 'dms',
+                    name: 'EntryDms',
+                    meta: {
+                        title: 'dms',
+                        icon: 'cloud_upload',
+                    },
+                    component: () => import('src/pages/Entry/Card/EntryDms.vue'),
+                },
                 {
                     path: 'log',
                     name: 'EntryLog',
-- 
2.40.1


From 64b7a07d4199353861e86fbd3e8bf119e2a77fea Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 5 Feb 2024 15:04:13 +0100
Subject: [PATCH 02/11] refs #5509 feat: VnDms FormModel

---
 src/components/FetchData.vue      |  7 ---
 src/components/FormModel.vue      |  9 +++-
 src/components/common/VnDms.vue   | 89 ++++++++++++++++++++++++++-----
 src/pages/Entry/Card/EntryDms.vue |  3 +-
 4 files changed, 86 insertions(+), 22 deletions(-)

diff --git a/src/components/FetchData.vue b/src/components/FetchData.vue
index 4f5d7a57d..5b3dcbea7 100644
--- a/src/components/FetchData.vue
+++ b/src/components/FetchData.vue
@@ -59,11 +59,4 @@ async function fetch(fetchFilter = {}) {
         //
     }
 }
-
-const render = () => {
-    return h('div', []);
-};
 </script>
-<template>
-    <render />
-</template>
diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 594780220..c3ca8fe98 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -59,6 +59,10 @@ const $props = defineProps({
         type: Function,
         default: null,
     },
+    updateType: {
+        type: String,
+        default: 'patch',
+    },
 });
 
 const emit = defineEmits(['onFetch', 'onDataSaved']);
@@ -136,7 +140,10 @@ async function save() {
             response = await axios.post($props.urlCreate, body);
             notify('globals.dataCreated', 'positive');
         } else {
-            response = await axios.patch($props.urlUpdate || $props.url, body);
+            response = await axios[$props.updateType](
+                $props.urlUpdate || $props.url,
+                body
+            );
         }
         emit('onDataSaved', formData.value, response?.data);
         originalData.value = JSON.parse(JSON.stringify(formData.value));
diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue
index cdc54b786..a3a5dab21 100644
--- a/src/components/common/VnDms.vue
+++ b/src/components/common/VnDms.vue
@@ -12,26 +12,58 @@ import VnInput from 'src/components/common/VnInput.vue';
 const route = useRoute();
 const { t } = useI18n();
 
+const props = defineProps({
+    model: {
+        type: String,
+        required: true,
+    },
+});
+
 const warehouses = ref();
 const companies = ref();
 const dmsTypes = ref();
+const allowedContentTypes = ref();
+const dms = ref({});
+
+function onFileChange(files) {
+    dms.value.hasFileAttached = !!files;
+    dms.value.file = files?.name;
+}
+
+function parseDms(data) {
+    const defaultDms = {};
+
+    for (let prop in data) {
+        if (prop.endsWith('Fk')) data[prop.replace('Fk', 'Id')] = data[prop];
+    }
+    console.log(data);
+    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="(data) => (dmsTypes = data)" auto-load />
+    <FetchData
+        url="DmsContainers/allowedContentTypes"
+        @on-fetch="(data) => (allowedContentTypes = data.join(','))"
+        auto-load
+    />
     <FormModel
         :url="`Dms/${route.params.id}`"
-        :url-update="`Claims/updateClaim/${route.params.id}`"
+        update-type="post"
+        :url-update="`${props.model}/${route.params.id}/uploadFile`"
+        @on-fetch="parseDms"
         model="dms"
+        :auto-load="!!route.params.id"
     >
-        <template #form="{ data }">
+        <template #form>
             <div class="q-gutter-y-ms">
                 <VnRow>
-                    <VnInput :label="t('Reference')" v-model="data.reference" />
+                    <VnInput :label="t('Reference')" v-model="dms.reference" />
                     <VnSelectFilter
                         :label="t('globals.company')"
-                        v-model="data.companyFk"
+                        v-model="dms.companyFk"
                         :options="companies"
                         option-value="id"
                         option-label="code"
@@ -41,7 +73,7 @@ const dmsTypes = ref();
                 <VnRow>
                     <VnSelectFilter
                         :label="t('globals.warehouse')"
-                        v-model="data.warehouseFk"
+                        v-model="dms.warehouseFk"
                         :options="warehouses"
                         option-value="id"
                         option-label="name"
@@ -49,20 +81,44 @@ const dmsTypes = ref();
                     />
                     <VnSelectFilter
                         :label="t('globals.type')"
-                        v-model="data.dmsTypeFk"
+                        v-model="dms.dmsTypeFk"
                         :options="dmsTypes"
                         option-value="id"
                         option-label="name"
                         input-debounce="0"
                     />
                 </VnRow>
-                <VnRow>
-                    <QInput
-                        :label="t('globals.description')"
-                        v-model="data.description"
-                        type="textarea"
-                    />
-                </VnRow>
+                <QInput
+                    :label="t('globals.description')"
+                    v-model="dms.description"
+                    type="textarea"
+                />
+                <QFile
+                    :label="t('entry.buys.file')"
+                    v-model="dms.files"
+                    :multiple="false"
+                    accept=".json"
+                    @update:model-value="onFileChange(dms.files)"
+                    class="required"
+                    :display-value="dms.file"
+                >
+                    <template #prepend>
+                        <QIcon name="vn:attach" class="cursor-pointer">
+                            <QTooltip>{{ t('Select a file') }}</QTooltip>
+                        </QIcon>
+                    </template>
+                    <template #append>
+                        <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>
     </FormModel>
@@ -73,3 +129,10 @@ const dmsTypes = ref();
     row-gap: 20px;
 }
 </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>
diff --git a/src/pages/Entry/Card/EntryDms.vue b/src/pages/Entry/Card/EntryDms.vue
index 57e6eff53..696c49a34 100644
--- a/src/pages/Entry/Card/EntryDms.vue
+++ b/src/pages/Entry/Card/EntryDms.vue
@@ -2,5 +2,6 @@
 import VnDms from 'src/components/common/VnDms.vue';
 </script>
 <template>
-    <VnDms model="Entry" />
+    <VnDms model="Clients" />
+    <!-- CHANGE ME-->
 </template>
-- 
2.40.1


From 18b76e5e129f7bb1b4a510640868d2b713947820 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 8 Feb 2024 07:25:23 +0100
Subject: [PATCH 03/11] refs #5509 feat: VnDmsList

---
 src/components/common/VnDms.vue     |  33 ++++-
 src/components/common/VnDmsList.vue | 181 ++++++++++++++++++++++++++++
 src/pages/Entry/Card/EntryDms.vue   |   4 +-
 3 files changed, 215 insertions(+), 3 deletions(-)
 create mode 100644 src/components/common/VnDmsList.vue

diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue
index a3a5dab21..169356152 100644
--- a/src/components/common/VnDms.vue
+++ b/src/components/common/VnDms.vue
@@ -17,12 +17,17 @@ const props = defineProps({
         type: String,
         required: true,
     },
+    defaultDmsCode: {
+        type: String,
+        required: true,
+    },
 });
 
 const warehouses = ref();
 const companies = ref();
 const dmsTypes = ref();
 const allowedContentTypes = ref();
+const config = ref({});
 const dms = ref({});
 
 function onFileChange(files) {
@@ -39,6 +44,25 @@ function parseDms(data) {
     console.log(data);
     dms.value = data;
 }
+
+function mapperDms(data) {
+    const formData = new FormData();
+    const { files } = data;
+    if (files) formData.append(files?.name, files);
+    console.log('data', data);
+    delete data.files;
+
+    const dms = {
+        hasFile: false,
+        hasFileAttached: false,
+        reference: data.id,
+        warehouseId: config.value.warehouseFk,
+        companyId: config.value.companyFk,
+        dmsTypeId: data.dmsTypeFk,
+        description: 'ASD',
+    };
+    return [formData, { params: dms }];
+}
 </script>
 <template>
     <FetchData url="Warehouses" @on-fetch="(data) => (warehouses = data)" auto-load />
@@ -49,6 +73,11 @@ function parseDms(data) {
         @on-fetch="(data) => (allowedContentTypes = data.join(','))"
         auto-load
     />
+    <FetchData
+        url="UserConfigs/getUserConfig"
+        @on-fetch="(data) => (config = data)"
+        auto-load
+    />
     <FormModel
         :url="`Dms/${route.params.id}`"
         update-type="post"
@@ -56,6 +85,7 @@ function parseDms(data) {
         @on-fetch="parseDms"
         model="dms"
         :auto-load="!!route.params.id"
+        :mapper="mapperDms"
     >
         <template #form>
             <div class="q-gutter-y-ms">
@@ -93,11 +123,12 @@ function parseDms(data) {
                     v-model="dms.description"
                     type="textarea"
                 />
+                {{ allowedContentTypes }}
                 <QFile
                     :label="t('entry.buys.file')"
                     v-model="dms.files"
                     :multiple="false"
-                    accept=".json"
+                    :accept="allowedContentTypes"
                     @update:model-value="onFileChange(dms.files)"
                     class="required"
                     :display-value="dms.file"
diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue
new file mode 100644
index 000000000..06078ef17
--- /dev/null
+++ b/src/components/common/VnDmsList.vue
@@ -0,0 +1,181 @@
+<script setup>
+import { ref, computed } from 'vue';
+import { useRoute } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+
+import FetchData from 'components/FetchData.vue';
+import FormModel from 'components/FormModel.vue';
+import VnRow from 'components/ui/VnRow.vue';
+import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
+import VnInput from 'src/components/common/VnInput.vue';
+import { QCheckbox, QBtn } from 'quasar';
+
+const route = useRoute();
+const { t } = useI18n();
+const rows = ref();
+
+const $props = defineProps({
+    model: {
+        type: String,
+        required: true,
+    },
+    defaultDmsCode: {
+        type: String,
+        required: true,
+    },
+    entity: {
+        type: String,
+        default: 'entryFk',
+    },
+});
+
+const dmsFilter = {
+    include: {
+        relation: 'dms',
+        scope: {
+            fields: [
+                'dmsTypeFk',
+                'reference',
+                'hardCopyNumber',
+                'workerFk',
+                'description',
+                'hasFile',
+                'file',
+                'created',
+            ],
+            include: [
+                {
+                    relation: 'dmsType',
+                    scope: {
+                        fields: ['name'],
+                    },
+                },
+                {
+                    relation: 'worker',
+                    scope: {
+                        fields: ['id'],
+                        include: {
+                            relation: 'user',
+                            scope: {
+                                fields: ['name'],
+                            },
+                        },
+                    },
+                },
+            ],
+        },
+    },
+};
+
+const columns = computed(() => [
+    {
+        align: 'left',
+        field: 'id',
+        label: t('id'),
+        name: 'id',
+        component: 'span',
+    },
+    {
+        align: 'left',
+        field: 'type',
+        label: t('type'),
+        name: 'type',
+        component: 'span',
+    },
+    {
+        align: 'left',
+        field: 'order',
+        label: t('order'),
+        name: 'order',
+        component: 'span',
+    },
+    {
+        align: 'left',
+        field: 'reference',
+        label: t('reference'),
+        name: 'reference',
+        component: 'span',
+    },
+    {
+        align: 'left',
+        field: 'description',
+        label: t('description'),
+        name: 'description',
+        component: 'span',
+    },
+    {
+        align: 'left',
+        field: 'hasFile',
+        label: t('hasFile'),
+        name: 'hasFile',
+        component: QCheckbox,
+    },
+    {
+        align: 'left',
+        field: 'file',
+        label: t('file'),
+        name: 'file',
+        component: 'span',
+    },
+    {
+        align: 'center',
+        field: 'options',
+        name: 'options',
+    },
+]);
+
+function setData(data) {
+    const newData = data.map((value) => value.dms);
+    console.log(newData);
+    rows.value = newData;
+}
+</script>
+<template>
+    <FetchData
+        :url="$props.model"
+        :where="{ [$props.entity]: route.params.id }"
+        :filter="dmsFilter"
+        @on-fetch="setData"
+        auto-load
+    />
+    <QTable
+        :columns="columns"
+        :pagination="{ rowsPerPage: 0 }"
+        :rows="rows"
+        class="full-width q-mt-md"
+        hide-bottom
+        row-key="clientFk"
+        selection="multiple"
+        v-model:selected="selected"
+    >
+        <template #body-cell="props">
+            <QTd :props="props">
+                <QTr :props="props" class="cursor-pointer">
+                    <component
+                        v-if="props.col.component"
+                        :is="props.col.component"
+                        v-bind="props.col.props && props.col.props(props)"
+                        @click="props.col.event(props)"
+                    >
+                        {{ props.value }}
+                        <!-- <QBtn -->
+                    </component>
+                </QTr>
+            </QTd>
+        </template>
+        asd
+    </QTable>
+</template>
+<style scoped>
+.q-gutter-y-ms {
+    display: grid;
+    row-gap: 20px;
+}
+</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>
diff --git a/src/pages/Entry/Card/EntryDms.vue b/src/pages/Entry/Card/EntryDms.vue
index 696c49a34..a26811630 100644
--- a/src/pages/Entry/Card/EntryDms.vue
+++ b/src/pages/Entry/Card/EntryDms.vue
@@ -1,7 +1,7 @@
 <script setup>
-import VnDms from 'src/components/common/VnDms.vue';
+import VnDmsList from 'src/components/common/VnDmsList.vue';
 </script>
 <template>
-    <VnDms model="Clients" />
+    <VnDmsList model="EntryDms" default-dms-code="entry" />
     <!-- CHANGE ME-->
 </template>
-- 
2.40.1


From aa4d5bffc36d6c9610de549f4e1d76d591b65b26 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 12 Feb 2024 15:06:20 +0100
Subject: [PATCH 04/11] refs #5509 feat: VnDms & VnDmsList

---
 src/components/CrudModel.vue                  |  17 +-
 src/components/FormModel.vue                  |  24 +--
 src/components/common/VnDms.vue               |  98 +++++++----
 src/components/common/VnDmsList.vue           | 166 +++++++++++++++---
 src/i18n/en/index.js                          |  17 +-
 src/i18n/es/index.js                          |  17 +-
 src/pages/Claim/ClaimList.vue                 |   2 +-
 src/pages/Entry/Card/EntryBuysImport.vue      |   2 +-
 src/pages/Entry/Card/EntryDms.vue             |  17 +-
 src/pages/Entry/Card/EntryNotes.vue           |   2 +-
 src/pages/Entry/EntryLatestBuys.vue           |   4 +-
 src/pages/Order/Card/OrderSummary.vue         |   4 +-
 src/pages/Route/Card/RouteSummary.vue         |   2 +-
 src/pages/Ticket/Card/TicketSummary.vue       |   4 +-
 .../Travel/Card/TravelThermographsForm.vue    |   2 +-
 15 files changed, 258 insertions(+), 120 deletions(-)

diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue
index 9bb05d439..c8fa5809c 100644
--- a/src/components/CrudModel.vue
+++ b/src/components/CrudModel.vue
@@ -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>
diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 0c669902f..c33835438 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -59,9 +59,9 @@ const $props = defineProps({
         type: Function,
         default: null,
     },
-    updateType: {
-        type: String,
-        default: 'patch',
+    saveFn: {
+        type: Function,
+        default: null,
     },
 });
 
@@ -79,8 +79,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);
+    if ($props.formInitialData || !$props.autoLoad) {
+        state.set($props.model, $props.formInitialData ?? {});
     } else {
         await fetch();
     }
@@ -142,19 +142,19 @@ 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[$props.updateType](
-                $props.urlUpdate || $props.url,
+        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) {
+        console.error(err);
         notify('errors.create', 'negative');
     }
     isLoading.value = false;
diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue
index 169356152..6cdca22c5 100644
--- a/src/components/common/VnDms.vue
+++ b/src/components/common/VnDms.vue
@@ -1,25 +1,35 @@
 <script setup>
-import { ref } from 'vue';
+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 FormModel from 'components/FormModel.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({
+const $props = defineProps({
     model: {
         type: String,
         required: true,
     },
     defaultDmsCode: {
         type: String,
-        required: true,
+        default: null,
+    },
+    formInitialData: {
+        type: Object,
+        default: null,
+    },
+    description: {
+        type: Function,
+        default: null,
     },
 });
 
@@ -27,47 +37,67 @@ const warehouses = ref();
 const companies = ref();
 const dmsTypes = ref();
 const allowedContentTypes = ref();
-const config = ref({});
 const dms = ref({});
 
+onMounted(() => defaultData());
 function onFileChange(files) {
     dms.value.hasFileAttached = !!files;
     dms.value.file = files?.name;
 }
 
-function parseDms(data) {
-    const defaultDms = {};
-
-    for (let prop in data) {
-        if (prop.endsWith('Fk')) data[prop.replace('Fk', 'Id')] = data[prop];
-    }
-    console.log(data);
-    dms.value = data;
-}
-
 function mapperDms(data) {
     const formData = new FormData();
     const { files } = data;
     if (files) formData.append(files?.name, files);
-    console.log('data', data);
     delete data.files;
 
     const dms = {
-        hasFile: false,
-        hasFileAttached: false,
-        reference: data.id,
-        warehouseId: config.value.warehouseFk,
-        companyId: config.value.companyFk,
+        hasFile: !!data.hasFile,
+        hasFileAttached: data.hasFileAttached,
+        reference: data.reference,
+        warehouseId: data.warehouseFk,
+        companyId: data.companyFk,
         dmsTypeId: data.dmsTypeFk,
-        description: 'ASD',
+        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,
+        description: $props.description && $props.description(dms.value),
+    });
+}
+
+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="(data) => (dmsTypes = data)" auto-load />
+    <FetchData url="DmsTypes" @on-fetch="setDmsTypes" auto-load />
     <FetchData
         url="DmsContainers/allowedContentTypes"
         @on-fetch="(data) => (allowedContentTypes = data.join(','))"
@@ -75,19 +105,16 @@ function mapperDms(data) {
     />
     <FetchData
         url="UserConfigs/getUserConfig"
-        @on-fetch="(data) => (config = data)"
-        auto-load
+        @on-fetch="addDefaultData"
+        :auto-load="!$props.formInitialData"
     />
-    <FormModel
-        :url="`Dms/${route.params.id}`"
-        update-type="post"
-        :url-update="`${props.model}/${route.params.id}/uploadFile`"
-        @on-fetch="parseDms"
+    <FormModelPopup
+        :title="t('create')"
         model="dms"
-        :auto-load="!!route.params.id"
-        :mapper="mapperDms"
+        :form-initial-data="formInitialData"
+        :save-fn="save"
     >
-        <template #form>
+        <template #form-inputs>
             <div class="q-gutter-y-ms">
                 <VnRow>
                     <VnInput :label="t('Reference')" v-model="dms.reference" />
@@ -123,7 +150,6 @@ function mapperDms(data) {
                     v-model="dms.description"
                     type="textarea"
                 />
-                {{ allowedContentTypes }}
                 <QFile
                     :label="t('entry.buys.file')"
                     v-model="dms.files"
@@ -152,7 +178,7 @@ function mapperDms(data) {
                 />
             </div>
         </template>
-    </FormModel>
+    </FormModelPopup>
 </template>
 <style scoped>
 .q-gutter-y-ms {
@@ -164,6 +190,6 @@ function mapperDms(data) {
 en:
     contentTypesInfo: Allowed file types {allowedContentTypes}
 es:
-    contentTypesInfo: Tipos de archivo permitidos {allowedContentTypes}
     Generate identifier for original file: Generar identificador para archivo original
+    contentTypesInfo: Tipos de archivo permitidos {allowedContentTypes}
 </i18n>
diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue
index 06078ef17..f746fa041 100644
--- a/src/components/common/VnDmsList.vue
+++ b/src/components/common/VnDmsList.vue
@@ -1,31 +1,43 @@
 <script setup>
 import { ref, computed } from 'vue';
-import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
+import { useRoute } from 'vue-router';
 
 import FetchData from 'components/FetchData.vue';
-import FormModel from 'components/FormModel.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 { QCheckbox, QBtn } from 'quasar';
+import VnDms from 'src/components/common/VnDms.vue';
+import { downloadFile } from 'src/composables/downloadFile';
+import VnConfirm from 'components/ui/VnConfirm.vue';
+import axios from 'axios';
+import { QCheckbox, QBtn, QInput } from 'quasar';
+import { useQuasar } from 'quasar';
 
 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,
     },
-    entity: {
+    filter: {
         type: String,
-        default: 'entryFk',
+        required: true,
+    },
+    description: {
+        type: Function,
+        required: true,
     },
 });
 
@@ -42,6 +54,8 @@ const dmsFilter = {
                 'hasFile',
                 'file',
                 'created',
+                'companyFk',
+                'warehouseFk',
             ],
             include: [
                 {
@@ -65,60 +79,69 @@ const dmsFilter = {
             ],
         },
     },
+    order: ['dmsFk DESC'],
 };
 
 const columns = computed(() => [
     {
         align: 'left',
         field: 'id',
-        label: t('id'),
+        label: t('globals.id'),
         name: 'id',
         component: 'span',
     },
     {
         align: 'left',
         field: 'type',
-        label: t('type'),
+        label: t('globals.type'),
         name: 'type',
-        component: 'span',
+        component: QInput,
+        props: (prop) => ({
+            readonly: true,
+            borderless: true,
+            'model-value': prop.row.dmsType.name,
+        }),
     },
     {
         align: 'left',
         field: 'order',
-        label: t('order'),
+        label: t('globals.order'),
         name: 'order',
         component: 'span',
     },
     {
         align: 'left',
         field: 'reference',
-        label: t('reference'),
+        label: t('globals.reference'),
         name: 'reference',
         component: 'span',
     },
     {
         align: 'left',
         field: 'description',
-        label: t('description'),
+        label: t('globals.description'),
         name: 'description',
         component: 'span',
     },
     {
         align: 'left',
         field: 'hasFile',
-        label: t('hasFile'),
+        label: t('globals.original'),
         name: 'hasFile',
         component: QCheckbox,
+        props: (prop) => ({
+            disable: true,
+            'model-value': Boolean(prop.value),
+        }),
     },
     {
         align: 'left',
         field: 'file',
-        label: t('file'),
+        label: t('globals.file'),
         name: 'file',
         component: 'span',
     },
     {
-        align: 'center',
         field: 'options',
         name: 'options',
     },
@@ -126,15 +149,46 @@ const columns = computed(() => [
 
 function setData(data) {
     const newData = data.map((value) => value.dms);
-    console.log(newData);
     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"
-        :where="{ [$props.entity]: route.params.id }"
         :filter="dmsFilter"
+        :where="{ [$props.filter]: route.params.id }"
         @on-fetch="setData"
         auto-load
     />
@@ -145,26 +199,86 @@ function setData(data) {
         class="full-width q-mt-md"
         hide-bottom
         row-key="clientFk"
-        selection="multiple"
-        v-model:selected="selected"
+        :grid="$q.screen.lt.md"
     >
         <template #body-cell="props">
             <QTd :props="props">
-                <QTr :props="props" class="cursor-pointer">
+                <QTr :props="props">
                     <component
                         v-if="props.col.component"
                         :is="props.col.component"
                         v-bind="props.col.props && props.col.props(props)"
-                        @click="props.col.event(props)"
                     >
-                        {{ props.value }}
-                        <!-- <QBtn -->
+                        <span v-if="props.col.component == 'span'">{{
+                            props.value
+                        }}</span>
                     </component>
                 </QTr>
+
+                <div class="flex justify-center" v-if="props.col.name == 'options'">
+                    <QBtn
+                        icon="cloud_download"
+                        flat
+                        color="primary"
+                        @click="downloadFile(props.row.id)"
+                    />
+                    <QBtn
+                        icon="edit"
+                        flat
+                        color="primary"
+                        @click="showFormDialog(props.row)"
+                    />
+                    <QBtn
+                        icon="delete"
+                        flat
+                        color="primary"
+                        @click="deleteDms(props.row.id)"
+                    />
+                </div>
             </QTd>
         </template>
-        asd
+        <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()"
+                >
+                    <QCardSection>
+                        <QCheckbox v-model="props.selected" dense />
+                    </QCardSection>
+                    <QSeparator />
+                    <QList dense>
+                        <QItem v-for="col in props.cols" :key="col.name">
+                            <QItemSection>
+                                <component
+                                    v-if="col.component"
+                                    :is="col.component"
+                                    v-bind="col.props && col.props(props)"
+                                >
+                                    <span v-if="col.component == 'span'">{{
+                                        `${col.label}:${col.value}`
+                                    }}</span>
+                                </component>
+                            </QItemSection>
+                        </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 {
diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js
index bd13f7b1d..b8b979961 100644
--- a/src/i18n/en/index.js
+++ b/src/i18n/en/index.js
@@ -64,7 +64,7 @@ export default {
         markAll: 'Mark all',
         requiredField: 'Required field',
         class: 'clase',
-        type: 'type',
+        type: 'Type',
         reason: 'reason',
         noResults: 'No results',
         system: 'System',
@@ -72,6 +72,13 @@ export default {
         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',
     },
     errors: {
         statusUnauthorized: 'Access denied',
@@ -347,7 +354,6 @@ export default {
             reference: 'Reference',
             observations: 'Observations',
             item: 'Item',
-            description: 'Description',
             size: 'Size',
             packing: 'Packing',
             grouping: 'Grouping',
@@ -362,7 +368,6 @@ export default {
         },
         notes: {
             observationType: 'Observation type',
-            description: 'Description',
         },
         descriptor: {
             agency: 'Agency',
@@ -375,7 +380,6 @@ export default {
             packing: 'Packing',
             grouping: 'Grouping',
             quantity: 'Quantity',
-            description: 'Description',
             size: 'Size',
             tags: 'Tags',
             type: 'Type',
@@ -461,7 +465,6 @@ export default {
             visible: 'Visible',
             available: 'Available',
             quantity: 'Quantity',
-            description: 'Description',
             price: 'Price',
             discount: 'Discount',
             packing: 'Packing',
@@ -534,7 +537,6 @@ export default {
             landed: 'Landed',
             quantity: 'Quantity',
             claimed: 'Claimed',
-            description: 'Description',
             price: 'Price',
             discount: 'Discount',
             total: 'Total',
@@ -795,7 +797,6 @@ export default {
             orderTicketList: 'Order Ticket List',
             details: 'Details',
             item: 'Item',
-            description: 'Description',
             quantity: 'Quantity',
             price: 'Price',
             amount: 'Amount',
@@ -1140,7 +1141,6 @@ export default {
             warehouse: 'Warehouse',
             travelFileDescription: 'Travel id { travelId }',
             file: 'File',
-            description: 'Description',
         },
     },
     item: {
@@ -1174,7 +1174,6 @@ export default {
             clone: 'Clone',
             openCard: 'View',
             openSummary: 'Summary',
-            viewDescription: 'Description',
         },
         cardDescriptor: {
             mainList: 'Main list',
diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js
index a171e8e2c..1ac6e535c 100644
--- a/src/i18n/es/index.js
+++ b/src/i18n/es/index.js
@@ -64,7 +64,7 @@ export default {
         markAll: 'Marcar todo',
         requiredField: 'Campo obligatorio',
         class: 'clase',
-        type: 'tipo',
+        type: 'Tipo',
         reason: 'motivo',
         noResults: 'Sin resultados',
         system: 'Sistema',
@@ -72,6 +72,13 @@ export default {
         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',
     },
     errors: {
         statusUnauthorized: 'Acceso denegado',
@@ -346,7 +353,6 @@ export default {
             reference: 'Referencia',
             observations: 'Observaciónes',
             item: 'Artículo',
-            description: 'Descripción',
             size: 'Medida',
             packing: 'Packing',
             grouping: 'Grouping',
@@ -361,7 +367,6 @@ export default {
         },
         notes: {
             observationType: 'Tipo de observación',
-            description: 'Descripción',
         },
         descriptor: {
             agency: 'Agencia',
@@ -374,7 +379,6 @@ export default {
             packing: 'Packing',
             grouping: 'Grouping',
             quantity: 'Cantidad',
-            description: 'Descripción',
             size: 'Medida',
             tags: 'Etiquetas',
             type: 'Tipo',
@@ -460,7 +464,6 @@ export default {
             visible: 'Visible',
             available: 'Disponible',
             quantity: 'Cantidad',
-            description: 'Descripción',
             price: 'Precio',
             discount: 'Descuento',
             packing: 'Encajado',
@@ -533,7 +536,6 @@ export default {
             landed: 'Entregado',
             quantity: 'Cantidad',
             claimed: 'Reclamado',
-            description: 'Descripción',
             price: 'Precio',
             discount: 'Descuento',
             total: 'Total',
@@ -703,7 +705,6 @@ export default {
             orderTicketList: 'Tickets del pedido',
             details: 'Detalles',
             item: 'Item',
-            description: 'Descripción',
             quantity: 'Cantidad',
             price: 'Precio',
             amount: 'Monto',
@@ -1140,7 +1141,6 @@ export default {
             warehouse: 'Almacén',
             travelFileDescription: 'Id envío { travelId }',
             file: 'Fichero',
-            description: 'Descripción',
         },
     },
     item: {
@@ -1174,7 +1174,6 @@ export default {
             clone: 'Clonar',
             openCard: 'Ficha',
             openSummary: 'Detalles',
-            viewDescription: 'Descripción',
         },
         cardDescriptor: {
             mainList: 'Listado principal',
diff --git a/src/pages/Claim/ClaimList.vue b/src/pages/Claim/ClaimList.vue
index e9462e7a9..acb7ec3fd 100644
--- a/src/pages/Claim/ClaimList.vue
+++ b/src/pages/Claim/ClaimList.vue
@@ -116,7 +116,7 @@ function navigate(id) {
                                 outline
                             />
                             <QBtn
-                                :label="t('components.smartCard.viewDescription')"
+                                :label="t('globals.description')"
                                 @click.stop
                                 class="bg-vn-dark"
                                 outline
diff --git a/src/pages/Entry/Card/EntryBuysImport.vue b/src/pages/Entry/Card/EntryBuysImport.vue
index 21f0beada..5783826ec 100644
--- a/src/pages/Entry/Card/EntryBuysImport.vue
+++ b/src/pages/Entry/Card/EntryBuysImport.vue
@@ -44,7 +44,7 @@ const columns = computed(() => [
         align: 'left',
     },
     {
-        label: t('entry.buys.description'),
+        label: t('globals.description'),
         name: 'description',
         field: 'description',
         align: 'left',
diff --git a/src/pages/Entry/Card/EntryDms.vue b/src/pages/Entry/Card/EntryDms.vue
index a26811630..5e4d66c0c 100644
--- a/src/pages/Entry/Card/EntryDms.vue
+++ b/src/pages/Entry/Card/EntryDms.vue
@@ -2,6 +2,19 @@
 import VnDmsList from 'src/components/common/VnDmsList.vue';
 </script>
 <template>
-    <VnDmsList model="EntryDms" default-dms-code="entry" />
-    <!-- CHANGE ME-->
+    <VnDmsList
+        model="EntryDms"
+        update-model="EntryDms"
+        default-dms-code="entry"
+        filter="entryFk"
+        :description="
+            (data) => t('description', { reference: data.reference, id: data.id })
+        "
+    />
 </template>
+<i18n>
+    en:
+        description: Reference {reference} id {id}
+    es:
+        description: Referencia {reference} id {id}
+</i18n>
diff --git a/src/pages/Entry/Card/EntryNotes.vue b/src/pages/Entry/Card/EntryNotes.vue
index f56e59253..0d2e5e51a 100644
--- a/src/pages/Entry/Card/EntryNotes.vue
+++ b/src/pages/Entry/Card/EntryNotes.vue
@@ -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')"
                         />
diff --git a/src/pages/Entry/EntryLatestBuys.vue b/src/pages/Entry/EntryLatestBuys.vue
index f4a423f3b..09a6a2f27 100644
--- a/src/pages/Entry/EntryLatestBuys.vue
+++ b/src/pages/Entry/EntryLatestBuys.vue
@@ -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') },
diff --git a/src/pages/Order/Card/OrderSummary.vue b/src/pages/Order/Card/OrderSummary.vue
index 9b26891a1..f9704a480 100644
--- a/src/pages/Order/Card/OrderSummary.vue
+++ b/src/pages/Order/Card/OrderSummary.vue
@@ -31,7 +31,7 @@ const detailsColumns = ref([
     },
     {
         name: 'description',
-        label: t('order.summary.description'),
+        label: t('globals.description'),
         field: (row) => row?.item?.name,
     },
     {
@@ -167,7 +167,7 @@ const detailsColumns = ref([
                         <template #header="props">
                             <QTr :props="props">
                                 <QTh auto-width>{{ t('order.summary.item') }}</QTh>
-                                <QTh>{{ t('order.summary.description') }}</QTh>
+                                <QTh>{{ t('globals.description') }}</QTh>
                                 <QTh auto-width>{{ t('order.summary.quantity') }}</QTh>
                                 <QTh auto-width>{{ t('order.summary.price') }}</QTh>
                                 <QTh auto-width>{{ t('order.summary.amount') }}</QTh>
diff --git a/src/pages/Route/Card/RouteSummary.vue b/src/pages/Route/Card/RouteSummary.vue
index a10ca088e..df4495d3a 100644
--- a/src/pages/Route/Card/RouteSummary.vue
+++ b/src/pages/Route/Card/RouteSummary.vue
@@ -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) }}
diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue
index fe7dcee9a..f3e01d06b 100644
--- a/src/pages/Ticket/Card/TicketSummary.vue
+++ b/src/pages/Ticket/Card/TicketSummary.vue
@@ -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>
diff --git a/src/pages/Travel/Card/TravelThermographsForm.vue b/src/pages/Travel/Card/TravelThermographsForm.vue
index 6758cb6ff..4462846cb 100644
--- a/src/pages/Travel/Card/TravelThermographsForm.vue
+++ b/src/pages/Travel/Card/TravelThermographsForm.vue
@@ -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
-- 
2.40.1


From 43154084529399c6e0c21132fbfb97213396dbd6 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 13 Feb 2024 15:01:24 +0100
Subject: [PATCH 05/11] refs #5509 feat: VnDms description

---
 src/components/common/VnDms.vue               | 26 +++--
 src/components/common/VnDmsList.vue           | 99 +++++++++++--------
 src/pages/Entry/Card/EntryDms.vue             |  9 --
 .../integration/entry/entryDms.spec.js        | 13 +++
 4 files changed, 88 insertions(+), 59 deletions(-)
 create mode 100644 test/cypress/integration/entry/entryDms.spec.js

diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue
index 6cdca22c5..99056556d 100644
--- a/src/components/common/VnDms.vue
+++ b/src/components/common/VnDms.vue
@@ -27,19 +27,20 @@ const $props = defineProps({
         type: Object,
         default: null,
     },
-    description: {
-        type: Function,
-        default: null,
-    },
 });
 
 const warehouses = ref();
 const companies = ref();
 const dmsTypes = ref();
 const allowedContentTypes = ref();
+const inputFileRef = ref();
 const dms = ref({});
 
-onMounted(() => defaultData());
+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;
@@ -78,7 +79,6 @@ function defaultData() {
     if ($props.formInitialData) return (dms.value = $props.formInitialData);
     return addDefaultData({
         reference: route.params.id,
-        description: $props.description && $props.description(dms.value),
     });
 }
 
@@ -151,6 +151,7 @@ function addDefaultData(data) {
                     type="textarea"
                 />
                 <QFile
+                    ref="inputFileRef"
                     :label="t('entry.buys.file')"
                     v-model="dms.files"
                     :multiple="false"
@@ -159,12 +160,14 @@ function addDefaultData(data) {
                     class="required"
                     :display-value="dms.file"
                 >
-                    <template #prepend>
-                        <QIcon name="vn:attach" class="cursor-pointer">
+                    <template #append>
+                        <QIcon
+                            name="vn:attach"
+                            class="cursor-pointer"
+                            @click="inputFileRef.pickFiles()"
+                        >
                             <QTooltip>{{ t('Select a file') }}</QTooltip>
                         </QIcon>
-                    </template>
-                    <template #append>
                         <QIcon name="info" class="cursor-pointer">
                             <QTooltip>{{
                                 t('contentTypesInfo', { allowedContentTypes })
@@ -189,7 +192,10 @@ function addDefaultData(data) {
 <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>
diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue
index f746fa041..b7e683da9 100644
--- a/src/components/common/VnDmsList.vue
+++ b/src/components/common/VnDmsList.vue
@@ -2,14 +2,13 @@
 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 { downloadFile } from 'src/composables/downloadFile';
 import VnConfirm from 'components/ui/VnConfirm.vue';
-import axios from 'axios';
-import { QCheckbox, QBtn, QInput } from 'quasar';
-import { useQuasar } from 'quasar';
+import { downloadFile } from 'src/composables/downloadFile';
 
 const route = useRoute();
 const quasar = useQuasar();
@@ -35,10 +34,6 @@ const $props = defineProps({
         type: String,
         required: true,
     },
-    description: {
-        type: Function,
-        required: true,
-    },
 });
 
 const dmsFilter = {
@@ -144,6 +139,35 @@ const columns = computed(() => [
     {
         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),
+            },
+        ],
     },
 ]);
 
@@ -199,7 +223,7 @@ function parseDms(data) {
         class="full-width q-mt-md"
         hide-bottom
         row-key="clientFk"
-        :grid="$q.screen.lt.md"
+        :grid="$q.screen.lt.sm"
     >
         <template #body-cell="props">
             <QTd :props="props">
@@ -216,24 +240,13 @@ function parseDms(data) {
                 </QTr>
 
                 <div class="flex justify-center" v-if="props.col.name == 'options'">
-                    <QBtn
-                        icon="cloud_download"
-                        flat
-                        color="primary"
-                        @click="downloadFile(props.row.id)"
-                    />
-                    <QBtn
-                        icon="edit"
-                        flat
-                        color="primary"
-                        @click="showFormDialog(props.row)"
-                    />
-                    <QBtn
-                        icon="delete"
-                        flat
-                        color="primary"
-                        @click="deleteDms(props.row.id)"
-                    />
+                    <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>
@@ -244,23 +257,26 @@ function parseDms(data) {
                     flat
                     @keyup.ctrl.enter.stop="claimDevelopmentForm?.saveChanges()"
                 >
-                    <QCardSection>
-                        <QCheckbox v-model="props.selected" dense />
-                    </QCardSection>
                     <QSeparator />
                     <QList dense>
                         <QItem v-for="col in props.cols" :key="col.name">
-                            <QItemSection>
-                                <component
-                                    v-if="col.component"
-                                    :is="col.component"
-                                    v-bind="col.props && col.props(props)"
+                            <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"
                                 >
-                                    <span v-if="col.component == 'span'">{{
-                                        `${col.label}:${col.value}`
-                                    }}</span>
-                                </component>
-                            </QItemSection>
+                                    <component
+                                        :is="button.component"
+                                        v-bind="button.props(col)"
+                                        @click="button.click(col)"
+                                    />
+                                </div>
+                            </div>
                         </QItem>
                     </QList>
                 </QCard>
@@ -285,6 +301,9 @@ function parseDms(data) {
     display: grid;
     row-gap: 20px;
 }
+.labelColor {
+    color: var(--vn-label);
+}
 </style>
 <i18n>
 en:
diff --git a/src/pages/Entry/Card/EntryDms.vue b/src/pages/Entry/Card/EntryDms.vue
index 5e4d66c0c..bab1ea6c2 100644
--- a/src/pages/Entry/Card/EntryDms.vue
+++ b/src/pages/Entry/Card/EntryDms.vue
@@ -7,14 +7,5 @@ import VnDmsList from 'src/components/common/VnDmsList.vue';
         update-model="EntryDms"
         default-dms-code="entry"
         filter="entryFk"
-        :description="
-            (data) => t('description', { reference: data.reference, id: data.id })
-        "
     />
 </template>
-<i18n>
-    en:
-        description: Reference {reference} id {id}
-    es:
-        description: Referencia {reference} id {id}
-</i18n>
diff --git a/test/cypress/integration/entry/entryDms.spec.js b/test/cypress/integration/entry/entryDms.spec.js
new file mode 100644
index 000000000..d9f1d77c0
--- /dev/null
+++ b/test/cypress/integration/entry/entryDms.spec.js
@@ -0,0 +1,13 @@
+describe('WagonTypeCreate', () => {
+    const entryId = 1;
+    beforeEach(() => {
+        cy.viewport(1920, 1080);
+        cy.login('developer');
+        cy.visit(`/#/entry/${entryId}/dms`);
+
+    });
+
+    it('should create and delete a new wagon type', () => {
+        cy.addCard()
+    });
+});
-- 
2.40.1


From b3e554d99eef52524bc7e8acc902e970d8278b93 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 15 Feb 2024 15:00:30 +0100
Subject: [PATCH 06/11] refs #5509 feat: add e2e

---
 .../integration/entry/entryDms.spec.js        | 32 +++++++++++++++++--
 test/cypress/support/commands.js              | 11 +++++--
 2 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/test/cypress/integration/entry/entryDms.spec.js b/test/cypress/integration/entry/entryDms.spec.js
index d9f1d77c0..79a9c5162 100644
--- a/test/cypress/integration/entry/entryDms.spec.js
+++ b/test/cypress/integration/entry/entryDms.spec.js
@@ -1,5 +1,6 @@
 describe('WagonTypeCreate', () => {
     const entryId = 1;
+
     beforeEach(() => {
         cy.viewport(1920, 1080);
         cy.login('developer');
@@ -7,7 +8,34 @@ describe('WagonTypeCreate', () => {
 
     });
 
-    it('should create and delete a new wagon type', () => {
-        cy.addCard()
+    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)
+        // });
     });
 });
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 6d627e631..a8b4a86f0 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -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) => {
@@ -57,6 +57,12 @@ Cypress.Commands.add('getValue', (selector) => {
                     '> .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > input'
             );
         }
+        // Si es un QSelect
+        if ($el.find('span').length) {
+            return cy.get(
+                selector + ' span'
+            );
+        }
         // 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})`).invoke('text').should('have.value', value)
         }
     });
 });
-- 
2.40.1


From 33eef88825c33bbce5661a165a7c8d94364a9597 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 21 Feb 2024 14:00:52 +0100
Subject: [PATCH 07/11] refs #5509 fix: e2e

---
 test/cypress/integration/claim/claimDevelopment.spec.js     | 4 ++--
 .../integration/invoiceIn/invoiceInIntrastat.spec.js        | 2 +-
 test/cypress/integration/invoiceIn/invoiceInVat.spec.js     | 2 +-
 test/cypress/support/commands.js                            | 6 +++---
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/test/cypress/integration/claim/claimDevelopment.spec.js b/test/cypress/integration/claim/claimDevelopment.spec.js
index 88ccbfab8..26c7ee196 100755
--- a/test/cypress/integration/claim/claimDevelopment.spec.js
+++ b/test/cypress/integration/claim/claimDevelopment.spec.js
@@ -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');
diff --git a/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js b/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
index 5024b2f1c..306c0b8c0 100644
--- a/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
@@ -18,7 +18,7 @@ describe('InvoiceInIntrastat', () => {
         cy.visit(`/#/invoice-in/1/intrastat`);
 
         cy.getValue(firstLineCode).should(
-            'have.value',
+            'equal',
             'Plantas vivas: Esqueje/injerto, Vid'
         );
     });
diff --git a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
index 26c7750ad..811374b98 100644
--- a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
@@ -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', () => {
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index a8b4a86f0..f075d500f 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -55,13 +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');
@@ -138,7 +138,7 @@ Cypress.Commands.add('validateRow', (rowSelector, expectedValues) => {
                 cy.getValue(`:nth-child(${index + 1})`).should(`${prefix}be.checked`);
                 continue;
             }
-            cy.getValue(`:nth-child(${index + 1})`).invoke('text').should('have.value', value)
+            cy.getValue(`:nth-child(${index + 1})`).should('equal', value)
         }
     });
 });
-- 
2.40.1


From 00bed4fd619652d44bcdd4df8ff0ee4f73e62259 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 22 Feb 2024 10:20:44 +0100
Subject: [PATCH 08/11] refs #5509 fix(FormModel): autoLoad && formInitalData

---
 src/components/FormModel.vue                    | 5 ++---
 src/pages/InvoiceIn/Card/InvoiceInBasicData.vue | 7 ++++++-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index c33835438..504a7acd6 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -79,9 +79,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();
     }
 
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index 2a29a3d0e..306220dd3 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -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">
-- 
2.40.1


From de184e9cf829a60d328946c2a669624096d9ab1e Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 22 Feb 2024 10:57:11 +0100
Subject: [PATCH 09/11] refs #5509 feat(DMS): change icon

---
 src/router/modules/entry.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js
index 339feaa0c..2f6c8cb4c 100644
--- a/src/router/modules/entry.js
+++ b/src/router/modules/entry.js
@@ -100,7 +100,7 @@ export default {
                     name: 'EntryDms',
                     meta: {
                         title: 'dms',
-                        icon: 'cloud_upload',
+                        icon: 'smb_share',
                     },
                     component: () => import('src/pages/Entry/Card/EntryDms.vue'),
                 },
-- 
2.40.1


From 4988df882c653d54f814c7218c31840b6b134e8f Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 26 Feb 2024 15:06:49 +0100
Subject: [PATCH 10/11] refs #5509 fix: transaltions

---
 src/components/EditPictureForm.vue              | 2 +-
 src/components/common/VnDms.vue                 | 6 +++---
 src/i18n/en/index.js                            | 2 ++
 src/i18n/es/index.js                            | 2 ++
 src/pages/Entry/Card/EntryBuysImport.vue        | 4 ++--
 src/pages/InvoiceIn/Card/InvoiceInBasicData.vue | 5 ++---
 6 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/src/components/EditPictureForm.vue b/src/components/EditPictureForm.vue
index 9f69896b5..3d7f3615b 100644
--- a/src/components/EditPictureForm.vue
+++ b/src/components/EditPictureForm.vue
@@ -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>{{
diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue
index 99056556d..d2651f5d8 100644
--- a/src/components/common/VnDms.vue
+++ b/src/components/common/VnDms.vue
@@ -109,7 +109,7 @@ function addDefaultData(data) {
         :auto-load="!$props.formInitialData"
     />
     <FormModelPopup
-        :title="t('create')"
+        :title="formInitialData ? t('globals.edit') : t('globals.create')"
         model="dms"
         :form-initial-data="formInitialData"
         :save-fn="save"
@@ -117,7 +117,7 @@ function addDefaultData(data) {
         <template #form-inputs>
             <div class="q-gutter-y-ms">
                 <VnRow>
-                    <VnInput :label="t('Reference')" v-model="dms.reference" />
+                    <VnInput :label="t('globals.reference')" v-model="dms.reference" />
                     <VnSelectFilter
                         :label="t('globals.company')"
                         v-model="dms.companyFk"
@@ -166,7 +166,7 @@ function addDefaultData(data) {
                             class="cursor-pointer"
                             @click="inputFileRef.pickFiles()"
                         >
-                            <QTooltip>{{ t('Select a file') }}</QTooltip>
+                            <QTooltip>{{ t('globals.selectFile') }}</QTooltip>
                         </QIcon>
                         <QIcon name="info" class="cursor-pointer">
                             <QTooltip>{{
diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js
index 98dabd4f8..ee518418b 100644
--- a/src/i18n/en/index.js
+++ b/src/i18n/en/index.js
@@ -24,6 +24,7 @@ export default {
         dataCreated: 'Data created',
         add: 'Add',
         create: 'Create',
+        edit: 'Edit',
         save: 'Save',
         remove: 'Remove',
         reset: 'Reset',
@@ -79,6 +80,7 @@ export default {
         order: 'Order',
         original: 'Original',
         file: 'File',
+        selectFile: 'Select a file',
     },
     errors: {
         statusUnauthorized: 'Access denied',
diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js
index 36d4662b4..0f65181bd 100644
--- a/src/i18n/es/index.js
+++ b/src/i18n/es/index.js
@@ -24,6 +24,7 @@ export default {
         dataCreated: 'Datos creados',
         add: 'Añadir',
         create: 'Crear',
+        edit: 'Modificar',
         save: 'Guardar',
         remove: 'Eliminar',
         reset: 'Restaurar',
@@ -79,6 +80,7 @@ export default {
         order: 'Orden',
         original: 'Original',
         file: 'Fichero',
+        selectFile: 'Seleccione un fichero',
     },
     errors: {
         statusUnauthorized: 'Acceso denegado',
diff --git a/src/pages/Entry/Card/EntryBuysImport.vue b/src/pages/Entry/Card/EntryBuysImport.vue
index 5783826ec..3e0ac1410 100644
--- a/src/pages/Entry/Card/EntryBuysImport.vue
+++ b/src/pages/Entry/Card/EntryBuysImport.vue
@@ -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>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index 306220dd3..f557c8ef4 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -514,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">
@@ -623,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">
@@ -692,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
-- 
2.40.1


From c8a4854df9b3e890e8b33f817893586fef2ecadf Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 27 Feb 2024 08:22:38 +0100
Subject: [PATCH 11/11] refs #5509 fix(vnDms): fix issues

---
 src/components/FormModel.vue        | 2 +-
 src/components/common/VnDmsList.vue | 8 +++++---
 src/i18n/en/index.js                | 2 +-
 src/i18n/es/index.js                | 2 +-
 4 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 504a7acd6..912ce8ea7 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -154,7 +154,7 @@ async function save() {
         hasChanges.value = false;
     } catch (err) {
         console.error(err);
-        notify('errors.create', 'negative');
+        notify('errors.writeRequest', 'negative');
     }
     isLoading.value = false;
 }
diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue
index b7e683da9..5057c0790 100644
--- a/src/components/common/VnDmsList.vue
+++ b/src/components/common/VnDmsList.vue
@@ -233,9 +233,11 @@ function parseDms(data) {
                         :is="props.col.component"
                         v-bind="props.col.props && props.col.props(props)"
                     >
-                        <span v-if="props.col.component == 'span'">{{
-                            props.value
-                        }}</span>
+                        <span
+                            v-if="props.col.component == 'span'"
+                            style="white-space: wrap"
+                            >{{ props.value }}</span
+                        >
                     </component>
                 </QTr>
 
diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js
index ee518418b..46237c2b9 100644
--- a/src/i18n/en/index.js
+++ b/src/i18n/en/index.js
@@ -88,7 +88,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',
diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js
index 0f65181bd..fe82407ad 100644
--- a/src/i18n/es/index.js
+++ b/src/i18n/es/index.js
@@ -88,7 +88,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',
-- 
2.40.1