From 4ed1021a67c3c714807ee3fbf233d073e727769c Mon Sep 17 00:00:00 2001
From: pablone <pablone@verdnatura.es>
Date: Fri, 21 Mar 2025 13:19:43 +0100
Subject: [PATCH 1/8] feat: refs #8638 add AWB field to travel and entry forms,
 update translations and styles

---
 src/components/VnTable/VnTable.vue            |   2 +-
 src/components/common/VnDmsInput.vue          | 166 ++++++++++++++++++
 src/css/app.scss                              |   1 -
 src/i18n/locale/en.yml                        |   1 +
 src/i18n/locale/es.yml                        |   1 +
 src/pages/Entry/Card/EntryBasicData.vue       |  47 +++--
 src/pages/Entry/Card/EntryBuys.vue            |  64 ++++++-
 src/pages/Entry/Card/EntryDescriptor.vue      |   4 +-
 src/pages/Entry/Card/EntrySummary.vue         |   6 +-
 src/pages/Entry/EntryStockBought.vue          |  15 +-
 src/pages/Entry/locale/es.yml                 |  11 +-
 .../InvoiceIn/Card/InvoiceInBasicData.vue     | 122 +------------
 src/pages/Travel/Card/TravelBasicData.vue     |   7 +-
 src/pages/Travel/Card/TravelFilter.js         |   1 +
 14 files changed, 290 insertions(+), 158 deletions(-)
 create mode 100644 src/components/common/VnDmsInput.vue

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 6a547d95d..9ad032ee5 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -1154,7 +1154,7 @@ es:
 
 .grid-create {
     display: grid;
-    grid-template-columns: 1fr 1fr;
+    grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
     max-width: 100%;
     grid-gap: 20px;
     margin: 0 auto;
diff --git a/src/components/common/VnDmsInput.vue b/src/components/common/VnDmsInput.vue
new file mode 100644
index 000000000..25d625d5d
--- /dev/null
+++ b/src/components/common/VnDmsInput.vue
@@ -0,0 +1,166 @@
+<script setup>
+import VnConfirm from '../ui/VnConfirm.vue';
+import VnInput from './VnInput.vue';
+import VnDms from './VnDms.vue';
+import axios from 'axios';
+import { useQuasar } from 'quasar';
+import { ref } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { downloadFile } from 'src/composables/downloadFile';
+
+const { t } = useI18n();
+const quasar = useQuasar();
+const documentDialogRef = ref({});
+const editDownloadDisabled = ref(false);
+const $props = defineProps({
+    defaultDmsCode: {
+        type: String,
+        default: 'InvoiceIn',
+    },
+    disable: {
+        type: Boolean,
+        default: true,
+    },
+    data: {
+        type: Object,
+        default: null,
+    },
+    formRef: {
+        type: Object,
+        default: null,
+    },
+});
+
+function deleteFile(dmsFk) {
+    quasar
+        .dialog({
+            component: VnConfirm,
+            componentProps: {
+                title: t('globals.confirmDeletion'),
+                message: t('globals.confirmDeletionMessage'),
+            },
+        })
+        .onOk(async () => {
+            await axios.post(`dms/${dmsFk}/removeFile`);
+            $props.formRef.formData.dmsFk = null;
+            $props.formRef.formData.dms = undefined;
+            $props.formRef.hasChanges = true;
+            $props.formRef.save();
+        });
+}
+</script>
+<template>
+    <div class="row no-wrap">
+        <VnInput
+            :label="t('Document')"
+            v-model="data.dmsFk"
+            clearable
+            clear-icon="close"
+            class="full-width"
+            :disable="disable"
+        />
+        <div
+            v-if="data.dmsFk"
+            class="row no-wrap q-pa-xs q-gutter-x-xs"
+            data-cy="dms-buttons"
+        >
+            <QBtn
+                :disable="editDownloadDisabled"
+                @click="downloadFile(data.dmsFk)"
+                icon="cloud_download"
+                color="primary"
+                flat
+                :class="{
+                    'no-pointer-events': editDownloadDisabled,
+                }"
+                padding="xs"
+                round
+            >
+                <QTooltip>{{ t('Download file') }}</QTooltip>
+            </QBtn>
+            <QBtn
+                :disable="editDownloadDisabled"
+                @click="
+                    () => {
+                        documentDialogRef.show = true;
+                        documentDialogRef.dms = data.dms;
+                    }
+                "
+                icon="edit"
+                color="primary"
+                flat
+                :class="{
+                    'no-pointer-events': editDownloadDisabled,
+                }"
+                padding="xs"
+                round
+            >
+                <QTooltip>{{ t('Edit document') }}</QTooltip>
+            </QBtn>
+            <QBtn
+                :disable="editDownloadDisabled"
+                @click="deleteFile(data.dmsFk)"
+                icon="delete"
+                color="primary"
+                flat
+                round
+                :class="{
+                    'no-pointer-events': editDownloadDisabled,
+                }"
+                padding="xs"
+            >
+                <QTooltip>{{ t('Delete file') }}</QTooltip>
+            </QBtn>
+        </div>
+        <QBtn
+            v-else
+            icon="add_circle"
+            color="primary"
+            flat
+            round
+            v-shortcut="'+'"
+            padding="xs"
+            @click="
+                () => {
+                    documentDialogRef.show = true;
+                    delete documentDialogRef.dms;
+                }
+            "
+            data-cy="dms-create"
+        >
+            <QTooltip>{{ t('Create document') }}</QTooltip>
+        </QBtn>
+    </div>
+    <QDialog v-model="documentDialogRef.show">
+        <VnDms
+            model="dms"
+            :default-dms-code="defaultDmsCode"
+            :form-initial-data="documentDialogRef.dms"
+            :url="
+                documentDialogRef.dms
+                    ? `Dms/${documentDialogRef.dms.id}/updateFile`
+                    : 'Dms/uploadFile'
+            "
+            :description="documentDialogRef.supplierName"
+            @on-data-saved="
+                (_, { data }) => {
+                    let dmsData = data;
+                    if (Array.isArray(data)) dmsData = data[0];
+                    formRef.formData.dmsFk = dmsData.id;
+                    formRef.formData.dms = dmsData;
+                    formRef.hasChanges = true;
+                    formRef.save();
+                }
+            "
+        />
+    </QDialog>
+</template>
+<i18n>
+es:
+    Document: Documento
+    Download file: Descargar archivo
+    Edit document: Editar documento
+    Delete file: Eliminar archivo
+    Create document: Crear documento
+
+</i18n>
diff --git a/src/css/app.scss b/src/css/app.scss
index 5befd150b..b299973d1 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -325,7 +325,6 @@ input::-webkit-inner-spin-button {
         min-height: auto !important;
         display: flex;
         align-items: flex-end;
-        padding-bottom: 2px;
         .q-field__native.row {
             min-height: auto !important;
         }
diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index c1286267c..594722b96 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -816,6 +816,7 @@ travel:
     search: Search travel
     searchInfo: You can search by travel id or name
     id: Id
+    awbFk: AWB
     travelList:
         tableVisibleColumns:
             ref: Reference
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 681781d11..a0eb3835d 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -899,6 +899,7 @@ travel:
     search: Buscar envío
     searchInfo: Buscar envío por id o nombre
     id: Id
+    awbFk: Guía aérea
     travelList:
         tableVisibleColumns:
             ref: Referencia
diff --git a/src/pages/Entry/Card/EntryBasicData.vue b/src/pages/Entry/Card/EntryBasicData.vue
index 34e4a0f9c..f6d15a977 100644
--- a/src/pages/Entry/Card/EntryBasicData.vue
+++ b/src/pages/Entry/Card/EntryBasicData.vue
@@ -14,6 +14,8 @@ import VnInputNumber from 'src/components/common/VnInputNumber.vue';
 import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
 import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
 import VnCheckbox from 'src/components/common/VnCheckbox.vue';
+import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
+import VnDmsInput from 'src/components/common/VnDmsInput.vue';
 
 const route = useRoute();
 const { t } = useI18n();
@@ -24,6 +26,7 @@ const user = state.getUser().fn();
 
 const companiesOptions = ref([]);
 const currenciesOptions = ref([]);
+const entryRef = ref({});
 
 onMounted(() => {
     checkEntryLock(route.params.id, user.id);
@@ -48,10 +51,11 @@ onMounted(() => {
         auto-load
     />
     <FormModel
-        :url-update="`Entries/${route.params.id}`"
+        ref="entryRef"
         model="Entry"
-        auto-load
+        :url-update="`Entries/${route.params.id}`"
         :clear-store-on-unmount="false"
+        auto-load
     >
         <template #form="{ data }">
             <VnRow class="q-py-sm">
@@ -67,11 +71,18 @@ onMounted(() => {
                 />
             </VnRow>
             <VnRow class="q-py-sm">
-                <VnInput v-model="data.reference" :label="t('globals.reference')" />
-                <VnInputNumber
-                    v-model="data.invoiceAmount"
-                    :label="t('entry.summary.invoiceAmount')"
-                    :positive="false"
+                <VnInput
+                    v-model="data.reference"
+                    :label="t('entry.list.tableVisibleColumns.reference')"
+                />
+                <VnSelect
+                    v-model="data.typeFk"
+                    url="entryTypes"
+                    :fields="['code', 'description']"
+                    option-value="code"
+                    optionLabel="description"
+                    sortBy="description"
+                    :label="t('entry.list.tableVisibleColumns.entryTypeDescription')"
                 />
             </VnRow>
             <VnRow class="q-py-sm">
@@ -113,7 +124,6 @@ onMounted(() => {
                     name="initialTemperature"
                     :label="t('entry.basicData.initialTemperature')"
                     :step="0.5"
-                    :decimal-places="2"
                     :positive="false"
                 />
                 <VnInputNumber
@@ -121,20 +131,21 @@ onMounted(() => {
                     name="finalTemperature"
                     :label="t('entry.basicData.finalTemperature')"
                     :step="0.5"
-                    :decimal-places="2"
                     :positive="false"
                 />
-                <VnSelect
-                    v-model="data.typeFk"
-                    url="entryTypes"
-                    :fields="['code', 'description']"
-                    option-value="code"
-                    optionLabel="description"
-                    sortBy="description"
-                />
             </VnRow>
             <VnRow class="q-py-sm">
-                <QInput
+                <VnInputNumber
+                    v-model="data.invoiceAmount"
+                    :label="t('entry.list.tableVisibleColumns.invoiceAmount')"
+                    :positive="false"
+                    @update:model-value="data.buyerFk = user.id"
+                />
+                <VnSelectWorker v-model="data.buyerFk" hide-selected />
+                <VnDmsInput :data="data" :formRef="entryRef" :disable="false" />
+            </VnRow>
+            <VnRow class="q-py-sm">
+                <VnInputNumber
                     :label="t('entry.basicData.observation')"
                     type="textarea"
                     v-model="data.observation"
diff --git a/src/pages/Entry/Card/EntryBuys.vue b/src/pages/Entry/Card/EntryBuys.vue
index 3990fde19..85da5cf1d 100644
--- a/src/pages/Entry/Card/EntryBuys.vue
+++ b/src/pages/Entry/Card/EntryBuys.vue
@@ -18,6 +18,7 @@ import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
 import { checkEntryLock } from 'src/composables/checkEntryLock';
 import VnRow from 'src/components/ui/VnRow.vue';
 import VnInput from 'src/components/common/VnInput.vue';
+import VnInputNumber from 'src/components/common/VnInputNumber.vue';
 
 const $props = defineProps({
     id: {
@@ -44,6 +45,8 @@ const entityId = ref($props.id ?? route.params.id);
 const entryBuysRef = ref();
 const footerFetchDataRef = ref();
 const footer = ref({});
+const dialogRef = ref(false);
+const newEntryRef = ref(null);
 const columns = [
     {
         align: 'center',
@@ -250,6 +253,7 @@ const columns = [
         component: 'number',
         attrs: {
             positive: false,
+            decimalPlaces: 3,
         },
         cellEvent: {
             'update:modelValue': async (value, oldValue, row) => {
@@ -497,6 +501,23 @@ async function setBuyUltimate(itemFk, data) {
     });
 }
 
+async function transferBuys(rows, newEntry) {
+    if (!newEntry) return;
+
+    const promises = rows.map((row) => {
+        return axios.patch('Buys', { id: row.id, entryFk: newEntry });
+    });
+
+    await Promise.all(promises);
+
+    await axios.post(`Entries/${newEntry}/recalcEntryPrices`);
+    await axios.post(`Entries/${entityId.value}/recalcEntryPrices`);
+
+    entryBuysRef.value.reload();
+    newEntryRef.value = null;
+    dialogRef.value = false;
+}
+
 onMounted(() => {
     stateStore.rightDrawer = false;
     if ($props.editableMode) checkEntryLock(entityId.value, user.id);
@@ -571,6 +592,45 @@ onMounted(() => {
                     </QItem>
                 </QList>
             </QBtnDropdown>
+            <QBtn
+                icon="move_group"
+                color="primary"
+                :title="t('Transfer buys')"
+                flat
+                @click="dialogRef = true"
+                :disable="!selectedRows.length"
+            />
+            <QDialog v-model="dialogRef">
+                <QCard>
+                    <QCardSection>
+                        <span>{{ t('Transfer buys') }}</span>
+                    </QCardSection>
+                    <QCardSection>
+                        <VnInputNumber
+                            v-model="newEntryRef"
+                            :label="t('Entry')"
+                            type="number"
+                            data-cy="transfer-buy-entry"
+                        />
+                    </QCardSection>
+                    <QCardSection>
+                        <QCardActions>
+                            <QBtn
+                                label="Cancel"
+                                flat
+                                color="primary"
+                                @click="dialogRef = false"
+                            />
+                            <QBtn
+                                label="Transfer"
+                                flat
+                                color="primary"
+                                @click="transferBuys(selectedRows, newEntryRef)"
+                            />
+                        </QCardActions>
+                    </QCardSection>
+                </QCard>
+            </QDialog>
         </QBtnGroup>
     </Teleport>
     <FetchData
@@ -620,7 +680,7 @@ onMounted(() => {
             },
             columnGridStyle: {
                 'max-width': '50%',
-                'margin-right': '30px',
+                'margin-right': '5%',
                 flex: 1,
             },
             previousStyle: {
@@ -816,6 +876,8 @@ es:
     Create buy: Crear compra
     Invert quantity value: Invertir valor de cantidad
     Check buy amount: Marcar como correcta la cantidad de compra
+    Transfer buys: Transferir compras
+    Entry: Entrada
 </i18n>
 <style lang="scss" scoped>
 .centered-container {
diff --git a/src/pages/Entry/Card/EntryDescriptor.vue b/src/pages/Entry/Card/EntryDescriptor.vue
index 313ed3d72..784f6e8a3 100644
--- a/src/pages/Entry/Card/EntryDescriptor.vue
+++ b/src/pages/Entry/Card/EntryDescriptor.vue
@@ -92,7 +92,7 @@ const getEntryRedirectionFilter = (entry) => {
 };
 
 function showEntryReport() {
-    openReport(`Entries/${entityId.value}/entry-order-pdf`);
+    openReport(`Entries/${entityId.value}/entry-order-pdf`, {}, true);
 }
 
 function showNotification(type, message) {
@@ -147,7 +147,7 @@ async function deleteEntry() {
 <template>
     <CardDescriptor
         :url="`Entries/${entityId}`"
-        :filter="entryFilter"
+        :user-filter="entryFilter"
         title="supplier.nickname"
         data-key="Entry"
         width="lg-width"
diff --git a/src/pages/Entry/Card/EntrySummary.vue b/src/pages/Entry/Card/EntrySummary.vue
index 53967e66f..37a28968c 100644
--- a/src/pages/Entry/Card/EntrySummary.vue
+++ b/src/pages/Entry/Card/EntrySummary.vue
@@ -84,7 +84,10 @@ onMounted(async () => {
                             :label="t('globals.company')"
                             :value="entry?.company?.code"
                         />
-                        <VnLv :label="t('globals.reference')" :value="entry?.reference" />
+                        <VnLv
+                            :label="t('entry.list.tableVisibleColumns.reference')"
+                            :value="entry?.reference"
+                        />
                         <VnLv
                             :label="t('entry.summary.invoiceNumber')"
                             :value="entry?.invoiceNumber"
@@ -159,6 +162,7 @@ onMounted(async () => {
                         />
                     </div>
                     <div class="card-content">
+                        <VnLv :label="t('travel.awbFk')" :value="entry.travel.awbFk" />
                         <VnCheckbox
                             :label="t('entry.summary.travelDelivered')"
                             v-model="entry.travel.isDelivered"
diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue
index 5da51d5a6..6168f0737 100644
--- a/src/pages/Entry/EntryStockBought.vue
+++ b/src/pages/Entry/EntryStockBought.vue
@@ -162,8 +162,8 @@ async function beforeSave(data, getChanges) {
     }
 
     await Promise.all(patchPromises);
-    const filteredChanges = changes.filter((change) => change?.isReal !== false);
-    data.creates = filteredChanges;
+    data.creates = [];
+    return data;
 }
 </script>
 <template>
@@ -203,7 +203,7 @@ async function beforeSave(data, getChanges) {
             </VnRow>
         </template>
     </VnSubToolbar>
-    <QDialog v-model="travelDialogRef" :maximized="true" :class="['vn-row', 'wrap']">
+    <QDialog v-model="travelDialogRef" :class="['vn-row', 'wrap']">
         <FormModelPopup
             :url-update="`Travels/${travel?.id}`"
             model="travel"
@@ -252,12 +252,15 @@ async function beforeSave(data, getChanges) {
                     </span>
                 </template>
                 <template #column-footer-reserve>
-                    <span>
+                    <span class="q-pr-xs">
                         {{ round(footer.reserve) }}
                     </span>
                 </template>
                 <template #column-footer-bought>
-                    <span :style="boughtStyle(footer?.bought, footer?.reserve)">
+                    <span
+                        :style="boughtStyle(footer?.bought, footer?.reserve)"
+                        class="q-pr-xs"
+                    >
                         {{ round(footer.bought) }}
                     </span>
                 </template>
@@ -275,7 +278,7 @@ async function beforeSave(data, getChanges) {
 }
 .column {
     min-width: 35%;
-    margin-top: 5%;
+    margin-top: 1%;
 }
 .text-negative {
     color: $negative !important;
diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml
index 10d863ea2..2c80299bc 100644
--- a/src/pages/Entry/locale/es.yml
+++ b/src/pages/Entry/locale/es.yml
@@ -25,7 +25,7 @@ entry:
             entryTypeDescription: Tipo entrada
             invoiceAmount: Importe
             dated: Fecha
-        inventoryEntry: Es inventario
+            inventoryEntry: Es inventario
     summary:
         commission: Comisión
         currency: Moneda
@@ -33,7 +33,8 @@ entry:
         invoiceAmount: Importe
         ordered: Pedida
         booked: Contabilizada
-        excludedFromAvailable: Excluido
+        excludedFromAvailable: Excluir del disponible
+        isConfirmed: Lista para etiquetar
         travelReference: Referencia
         travelAgency: Agencia
         travelShipped: F. envio
@@ -56,7 +57,7 @@ entry:
         observation: Observación
         commission: Comisión
         booked: Contabilizada
-        excludedFromAvailable: Excluido
+        excludedFromAvailable: Excluir del disponible
         initialTemperature: Ini °C
         finalTemperature: Fin °C
     buys:
@@ -119,9 +120,9 @@ entry:
         supplierName: Proveedor
 entryFilter:
     params:
-        isExcludedFromAvailable: Excluido
+        isExcludedFromAvailable: Excluir del disponible
         isOrdered: Pedida
-        isConfirmed: Confirmado
+        isConfirmed: Lista para etiquetar
         isReceived: Recibida
         isRaid: Raid
         landed: Fecha
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index 905ddebb2..0995b75b9 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -2,24 +2,18 @@
 import { ref, computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import { useQuasar } from 'quasar';
-import { downloadFile } from 'src/composables/downloadFile';
 import FormModel from 'components/FormModel.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import FetchData from 'src/components/FetchData.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import VnInputDate from 'src/components/common/VnInputDate.vue';
 import VnInput from 'src/components/common/VnInput.vue';
-import VnDms from 'src/components/common/VnDms.vue';
-import VnConfirm from 'src/components/ui/VnConfirm.vue';
-import axios from 'axios';
 import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
+import VnDmsInput from 'src/components/common/VnDmsInput.vue';
 
 const { t } = useI18n();
 
 const route = useRoute();
-const quasar = useQuasar();
-const editDownloadDisabled = ref(false);
 const userConfig = ref(null);
 const invoiceId = computed(() => +route.params.id);
 
@@ -37,24 +31,6 @@ const allowedContentTypes = ref([]);
 const sageWithholdings = ref([]);
 const documentDialogRef = ref({});
 const invoiceInRef = ref({});
-
-function deleteFile(dmsFk) {
-    quasar
-        .dialog({
-            component: VnConfirm,
-            componentProps: {
-                title: t('globals.confirmDeletion'),
-                message: t('globals.confirmDeletionMessage'),
-            },
-        })
-        .onOk(async () => {
-            await axios.post(`dms/${dmsFk}/removeFile`);
-            invoiceInRef.value.formData.dmsFk = null;
-            invoiceInRef.value.formData.dms = undefined;
-            invoiceInRef.value.hasChanges = true;
-            invoiceInRef.value.save();
-        });
-}
 </script>
 <template>
     <FetchData
@@ -157,78 +133,7 @@ function deleteFile(dmsFk) {
                         </QItem>
                     </template>
                 </VnSelect>
-
-                <div class="row no-wrap">
-                    <VnInput
-                        :label="t('Document')"
-                        v-model="data.dmsFk"
-                        clearable
-                        clear-icon="close"
-                        class="full-width"
-                        :disable="true"
-                    />
-                    <div
-                        v-if="data.dmsFk"
-                        class="row no-wrap q-pa-xs q-gutter-x-xs"
-                        data-cy="dms-buttons"
-                    >
-                        <QBtn
-                            :class="{
-                                'no-pointer-events': editDownloadDisabled,
-                            }"
-                            :disable="editDownloadDisabled"
-                            icon="cloud_download"
-                            :title="t('Download file')"
-                            padding="xs"
-                            round
-                            @click="downloadFile(data.dmsFk)"
-                        />
-                        <QBtn
-                            :class="{
-                                'no-pointer-events': editDownloadDisabled,
-                            }"
-                            :disable="editDownloadDisabled"
-                            icon="edit"
-                            round
-                            padding="xs"
-                            @click="
-                                () => {
-                                    documentDialogRef.show = true;
-                                    documentDialogRef.dms = data.dms;
-                                }
-                            "
-                        >
-                            <QTooltip>{{ t('Edit document') }}</QTooltip>
-                        </QBtn>
-                        <QBtn
-                            :class="{
-                                'no-pointer-events': editDownloadDisabled,
-                            }"
-                            :disable="editDownloadDisabled"
-                            icon="delete"
-                            :title="t('Delete file')"
-                            padding="xs"
-                            round
-                            @click="deleteFile(data.dmsFk)"
-                        />
-                    </div>
-                    <QBtn
-                        v-else
-                        icon="add_circle"
-                        round
-                        v-shortcut="'+'"
-                        padding="xs"
-                        @click="
-                            () => {
-                                documentDialogRef.show = true;
-                                delete documentDialogRef.dms;
-                            }
-                        "
-                        data-cy="dms-create"
-                    >
-                        <QTooltip>{{ t('Create document') }}</QTooltip>
-                    </QBtn>
-                </div>
+                <VnDmsInput :data="data" :formRef="invoiceInRef" />
             </VnRow>
             <VnRow>
                 <VnSelect
@@ -264,29 +169,6 @@ function deleteFile(dmsFk) {
             </VnRow>
         </template>
     </FormModel>
-    <QDialog v-model="documentDialogRef.show">
-        <VnDms
-            model="dms"
-            default-dms-code="invoiceIn"
-            :form-initial-data="documentDialogRef.dms"
-            :url="
-                documentDialogRef.dms
-                    ? `Dms/${documentDialogRef.dms.id}/updateFile`
-                    : 'Dms/uploadFile'
-            "
-            :description="documentDialogRef.supplierName"
-            @on-data-saved="
-                (_, { data }) => {
-                    let dmsData = data;
-                    if (Array.isArray(data)) dmsData = data[0];
-                    invoiceInRef.formData.dmsFk = dmsData.id;
-                    invoiceInRef.formData.dms = dmsData;
-                    invoiceInRef.hasChanges = true;
-                    invoiceInRef.save();
-                }
-            "
-        />
-    </QDialog>
 </template>
 <style lang="scss" scoped>
 @media (max-width: $breakpoint-xs) {
diff --git a/src/pages/Travel/Card/TravelBasicData.vue b/src/pages/Travel/Card/TravelBasicData.vue
index b1adc8126..a6ef8ad19 100644
--- a/src/pages/Travel/Card/TravelBasicData.vue
+++ b/src/pages/Travel/Card/TravelBasicData.vue
@@ -36,7 +36,7 @@ const warehousesOptionsIn = ref([]);
         auto-load
         :filter="{ where: { isDestiny: TRUE } }"
     />
-    <FormModel :url-update="`Travels/${route.params.id}`" model="Travel" auto-load>
+    <FormModel :url-update="`Travels/${route.params.id}`" model="Travel">
         <template #form="{ data }">
             <VnRow>
                 <VnInput v-model="data.ref" :label="t('globals.reference')" />
@@ -57,8 +57,8 @@ const warehousesOptionsIn = ref([]);
             <VnRow>
                 <VnInputDate
                     v-model="data.availabled"
-                    :label="t('travel.summary.availabled')" 
-                    />
+                    :label="t('travel.summary.availabled')"
+                />
                 <VnInputTime
                     v-model="data.availabled"
                     :label="t('travel.summary.availabledHour')"
@@ -96,6 +96,7 @@ const warehousesOptionsIn = ref([]);
                         </QIcon>
                     </template>
                 </VnInput>
+                <VnInput v-model="data.awbFk" :label="t('travel.awbFk')" />
             </VnRow>
             <VnRow>
                 <QCheckbox v-model="data.isRaid" :label="t('travel.basicData.isRaid')" />
diff --git a/src/pages/Travel/Card/TravelFilter.js b/src/pages/Travel/Card/TravelFilter.js
index 05436834f..0799e449c 100644
--- a/src/pages/Travel/Card/TravelFilter.js
+++ b/src/pages/Travel/Card/TravelFilter.js
@@ -12,6 +12,7 @@ export default {
         'isRaid',
         'daysInForward',
         'availabled',
+        'awbFk',
     ],
     include: [
         {

From a39f648da045428d1eec2b371d9fc54c9b511fcb Mon Sep 17 00:00:00 2001
From: pablone <pablone@verdnatura.es>
Date: Fri, 21 Mar 2025 13:25:17 +0100
Subject: [PATCH 2/8] fix: refs #8638 update comment formatting in VnTable.vue

---
 src/components/VnTable/VnTable.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 9ad032ee5..8f64dc857 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -895,7 +895,7 @@ const rowCtrlClickFunction = computed(() => {
                                         {{ row[splittedColumns.title.name] }}
                                     </span>
                                 </QCardSection>
-                                <!-- Fields -->
+                                <!-- Fields  -->
                                 <QCardSection
                                     class="q-pl-sm q-py-xs"
                                     :class="$props.cardClass"

From eb6046f3382b9500563fd3676669931247babb25 Mon Sep 17 00:00:00 2001
From: pablone <pablone@verdnatura.es>
Date: Fri, 21 Mar 2025 13:28:22 +0100
Subject: [PATCH 3/8] fix: refs #8638 restore invoiceInBasicData

---
 .../InvoiceIn/Card/InvoiceInBasicData.vue     | 122 +++++++++++++++++-
 1 file changed, 120 insertions(+), 2 deletions(-)

diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index 0995b75b9..905ddebb2 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -2,18 +2,24 @@
 import { ref, computed } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
+import { useQuasar } from 'quasar';
+import { downloadFile } from 'src/composables/downloadFile';
 import FormModel from 'components/FormModel.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import FetchData from 'src/components/FetchData.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import VnInputDate from 'src/components/common/VnInputDate.vue';
 import VnInput from 'src/components/common/VnInput.vue';
+import VnDms from 'src/components/common/VnDms.vue';
+import VnConfirm from 'src/components/ui/VnConfirm.vue';
+import axios from 'axios';
 import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
-import VnDmsInput from 'src/components/common/VnDmsInput.vue';
 
 const { t } = useI18n();
 
 const route = useRoute();
+const quasar = useQuasar();
+const editDownloadDisabled = ref(false);
 const userConfig = ref(null);
 const invoiceId = computed(() => +route.params.id);
 
@@ -31,6 +37,24 @@ const allowedContentTypes = ref([]);
 const sageWithholdings = ref([]);
 const documentDialogRef = ref({});
 const invoiceInRef = ref({});
+
+function deleteFile(dmsFk) {
+    quasar
+        .dialog({
+            component: VnConfirm,
+            componentProps: {
+                title: t('globals.confirmDeletion'),
+                message: t('globals.confirmDeletionMessage'),
+            },
+        })
+        .onOk(async () => {
+            await axios.post(`dms/${dmsFk}/removeFile`);
+            invoiceInRef.value.formData.dmsFk = null;
+            invoiceInRef.value.formData.dms = undefined;
+            invoiceInRef.value.hasChanges = true;
+            invoiceInRef.value.save();
+        });
+}
 </script>
 <template>
     <FetchData
@@ -133,7 +157,78 @@ const invoiceInRef = ref({});
                         </QItem>
                     </template>
                 </VnSelect>
-                <VnDmsInput :data="data" :formRef="invoiceInRef" />
+
+                <div class="row no-wrap">
+                    <VnInput
+                        :label="t('Document')"
+                        v-model="data.dmsFk"
+                        clearable
+                        clear-icon="close"
+                        class="full-width"
+                        :disable="true"
+                    />
+                    <div
+                        v-if="data.dmsFk"
+                        class="row no-wrap q-pa-xs q-gutter-x-xs"
+                        data-cy="dms-buttons"
+                    >
+                        <QBtn
+                            :class="{
+                                'no-pointer-events': editDownloadDisabled,
+                            }"
+                            :disable="editDownloadDisabled"
+                            icon="cloud_download"
+                            :title="t('Download file')"
+                            padding="xs"
+                            round
+                            @click="downloadFile(data.dmsFk)"
+                        />
+                        <QBtn
+                            :class="{
+                                'no-pointer-events': editDownloadDisabled,
+                            }"
+                            :disable="editDownloadDisabled"
+                            icon="edit"
+                            round
+                            padding="xs"
+                            @click="
+                                () => {
+                                    documentDialogRef.show = true;
+                                    documentDialogRef.dms = data.dms;
+                                }
+                            "
+                        >
+                            <QTooltip>{{ t('Edit document') }}</QTooltip>
+                        </QBtn>
+                        <QBtn
+                            :class="{
+                                'no-pointer-events': editDownloadDisabled,
+                            }"
+                            :disable="editDownloadDisabled"
+                            icon="delete"
+                            :title="t('Delete file')"
+                            padding="xs"
+                            round
+                            @click="deleteFile(data.dmsFk)"
+                        />
+                    </div>
+                    <QBtn
+                        v-else
+                        icon="add_circle"
+                        round
+                        v-shortcut="'+'"
+                        padding="xs"
+                        @click="
+                            () => {
+                                documentDialogRef.show = true;
+                                delete documentDialogRef.dms;
+                            }
+                        "
+                        data-cy="dms-create"
+                    >
+                        <QTooltip>{{ t('Create document') }}</QTooltip>
+                    </QBtn>
+                </div>
             </VnRow>
             <VnRow>
                 <VnSelect
@@ -169,6 +264,29 @@ const invoiceInRef = ref({});
             </VnRow>
         </template>
     </FormModel>
+    <QDialog v-model="documentDialogRef.show">
+        <VnDms
+            model="dms"
+            default-dms-code="invoiceIn"
+            :form-initial-data="documentDialogRef.dms"
+            :url="
+                documentDialogRef.dms
+                    ? `Dms/${documentDialogRef.dms.id}/updateFile`
+                    : 'Dms/uploadFile'
+            "
+            :description="documentDialogRef.supplierName"
+            @on-data-saved="
+                (_, { data }) => {
+                    let dmsData = data;
+                    if (Array.isArray(data)) dmsData = data[0];
+                    invoiceInRef.formData.dmsFk = dmsData.id;
+                    invoiceInRef.formData.dms = dmsData;
+                    invoiceInRef.hasChanges = true;
+                    invoiceInRef.save();
+                }
+            "
+        />
+    </QDialog>
 </template>
 <style lang="scss" scoped>
 @media (max-width: $breakpoint-xs) {

From c5e1ebec82478f5298fa707f17bcaecdfeda46e2 Mon Sep 17 00:00:00 2001
From: pablone <pablone@verdnatura.es>
Date: Fri, 21 Mar 2025 13:51:05 +0100
Subject: [PATCH 4/8] fix: refs #8638 update null check for maxlength
 validation in VnInput.vue

---
 src/components/common/VnInput.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue
index 9821992cb..474d68116 100644
--- a/src/components/common/VnInput.vue
+++ b/src/components/common/VnInput.vue
@@ -84,7 +84,7 @@ const mixinRules = [
     ...($attrs.rules ?? []),
     (val) => {
         const maxlength = $props.maxlength;
-        if (maxlength && +val.length > maxlength)
+        if (maxlength && +val?.length > maxlength)
             return t(`maxLength`, { value: maxlength });
         const { min, max } = vnInputRef.value.$attrs;
         if (!min) return null;

From bfa375bacd0a8c5efff6831e555d9a58dcfe7270 Mon Sep 17 00:00:00 2001
From: pablone <pablone@verdnatura.es>
Date: Mon, 24 Mar 2025 08:22:13 +0100
Subject: [PATCH 5/8] feat: refs #8638 add data attributes for transfer buys
 functionality in EntryBuys.vue and corresponding tests

---
 src/pages/Entry/Card/EntryBuys.vue                         | 4 +++-
 test/cypress/integration/entry/entryCard/entryBuys.spec.js | 5 +++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/pages/Entry/Card/EntryBuys.vue b/src/pages/Entry/Card/EntryBuys.vue
index 85da5cf1d..67f97e09d 100644
--- a/src/pages/Entry/Card/EntryBuys.vue
+++ b/src/pages/Entry/Card/EntryBuys.vue
@@ -596,6 +596,7 @@ onMounted(() => {
                 icon="move_group"
                 color="primary"
                 :title="t('Transfer buys')"
+                data-cy="transferBuys"
                 flat
                 @click="dialogRef = true"
                 :disable="!selectedRows.length"
@@ -610,7 +611,7 @@ onMounted(() => {
                             v-model="newEntryRef"
                             :label="t('Entry')"
                             type="number"
-                            data-cy="transfer-buy-entry"
+                            data-cy="entryDestinyInput"
                         />
                     </QCardSection>
                     <QCardSection>
@@ -623,6 +624,7 @@ onMounted(() => {
                             />
                             <QBtn
                                 label="Transfer"
+                                data-cy="transferBuysBtn"
                                 flat
                                 color="primary"
                                 @click="transferBuys(selectedRows, newEntryRef)"
diff --git a/test/cypress/integration/entry/entryCard/entryBuys.spec.js b/test/cypress/integration/entry/entryCard/entryBuys.spec.js
index f8f5e6b80..b5e185a8e 100644
--- a/test/cypress/integration/entry/entryCard/entryBuys.spec.js
+++ b/test/cypress/integration/entry/entryCard/entryBuys.spec.js
@@ -80,6 +80,11 @@ describe('EntryBuys', () => {
         checkColor('amount', COLORS.positive);
         cy.saveCard();
 
+        cy.get('tbody > tr [tabindex="0"][role="checkbox"]').click();
+        cy.dataCy('transferBuys').should('be.enabled').click();
+        cy.dataCy('entryDestinyInput').should('be.visible').type('100');
+        cy.dataCy('transferBuysBtn').click();
+
         cy.deleteEntry();
     });
 

From 2bdebc1e0d2a0f14fab2f5f4fa2c43782a783de9 Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Mon, 24 Mar 2025 09:27:35 +0100
Subject: [PATCH 6/8] test: waitSpinner() when load dialog

---
 test/cypress/integration/ticket/ticketList.spec.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/cypress/integration/ticket/ticketList.spec.js b/test/cypress/integration/ticket/ticketList.spec.js
index a3d8fe908..5613a5854 100644
--- a/test/cypress/integration/ticket/ticketList.spec.js
+++ b/test/cypress/integration/ticket/ticketList.spec.js
@@ -35,7 +35,7 @@ describe('TicketList', () => {
         cy.get('.summaryBody').should('exist');
     });
 
-    it.skip('filter client and create ticket', () => {
+    it('filter client and create ticket', () => {
         cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar');
         searchResults();
         cy.wait('@ticketSearchbar');
@@ -44,6 +44,7 @@ describe('TicketList', () => {
         cy.dataCy('Customer ID_input').type('1101{enter}');
 
         cy.get('[data-cy="vnTableCreateBtn"] > .q-btn__content > .q-icon').click();
+        cy.waitSpinner();
         cy.dataCy('Customer_select').should('have.value', 'Bruce Wayne');
         cy.dataCy('Address_select').click();
 

From 798371682c6eede4de615913b50227f33b8db78e Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Mon, 24 Mar 2025 12:39:40 +0100
Subject: [PATCH 7/8] feat: refs #6919 enhance filter in AccountSummary
 component to include entity ID

---
 src/pages/Account/Card/AccountSummary.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/Account/Card/AccountSummary.vue b/src/pages/Account/Card/AccountSummary.vue
index f7a16e8c3..0b108807e 100644
--- a/src/pages/Account/Card/AccountSummary.vue
+++ b/src/pages/Account/Card/AccountSummary.vue
@@ -17,7 +17,7 @@ const entityId = computed(() => $props.id || route.params.id);
         data-key="Account"
         ref="AccountSummary"
         url="VnUsers/preview"
-        :filter="filter"
+        :filter="{ ...filter, where: { id: entityId } }"
     >
         <template #header="{ entity }">{{ entity.id }} - {{ entity.nickname }}</template>
         <template #menu>

From e1ef6f87f3f4c334d3e7f65cb6fc8617bf67dc24 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 24 Mar 2025 14:01:43 +0100
Subject: [PATCH 8/8] feat: implement onBeforeSave function to handle form data
 updates

---
 src/pages/Claim/Card/ClaimBasicData.vue | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/pages/Claim/Card/ClaimBasicData.vue b/src/pages/Claim/Card/ClaimBasicData.vue
index 43941d1dc..7e7d42ae8 100644
--- a/src/pages/Claim/Card/ClaimBasicData.vue
+++ b/src/pages/Claim/Card/ClaimBasicData.vue
@@ -2,6 +2,7 @@
 import { ref } from 'vue';
 import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
+import { getDifferences, getUpdatedValues } from 'src/filters';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
 import FetchData from 'components/FetchData.vue';
@@ -9,12 +10,18 @@ import FormModel from 'components/FormModel.vue';
 import VnRow from 'components/ui/VnRow.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import VnInputDate from 'components/common/VnInputDate.vue';
-
 import VnAvatar from 'src/components/ui/VnAvatar.vue';
 
 const route = useRoute();
 const { t } = useI18n();
 const workersOptions = ref([]);
+
+function onBeforeSave(formData, originalData) {
+    return getUpdatedValues(
+        Object.keys(getDifferences(formData, originalData)),
+        formData,
+    );
+}
 </script>
 <template>
     <FetchData
@@ -27,6 +34,7 @@ const workersOptions = ref([]);
     <FormModel
         model="Claim"
         :url-update="`Claims/updateClaim/${route.params.id}`"
+        :mapper="onBeforeSave"
         auto-load
     >
         <template #form="{ data, validate }">