From 168201c755f50cefb633598e5488a88bf48068d9 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 15 Jul 2024 12:25:54 +0200
Subject: [PATCH 01/87] refs #7283 itemList table

---
 src/pages/Item/ItemList.vue | 477 +++++-------------------------------
 1 file changed, 68 insertions(+), 409 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index f1e3629cd..334ef2604 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -3,114 +3,48 @@ import { onMounted, ref, computed, reactive, onUnmounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRouter } from 'vue-router';
 
-import FetchData from 'components/FetchData.vue';
-import FetchedTags from 'components/ui/FetchedTags.vue';
-import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
-import VnInput from 'src/components/common/VnInput.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
-import ItemDescriptorProxy from '../Item/Card/ItemDescriptorProxy.vue';
-import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
-import ItemSummary from '../Item/Card/ItemSummary.vue';
-import VnPaginate from 'components/ui/VnPaginate.vue';
-import ItemListFilter from './ItemListFilter.vue';
-
+import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { toDateFormat } from 'src/filters/date.js';
 import { dashIfEmpty } from 'src/filters';
-import { useSummaryDialog } from 'src/composables/useSummaryDialog';
-import { useVnConfirm } from 'composables/useVnConfirm';
 import axios from 'axios';
-import RightMenu from 'src/components/common/RightMenu.vue';
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
-import VnImg from 'src/components/ui/VnImg.vue';
 
 const router = useRouter();
 const stateStore = useStateStore();
 const { t } = useI18n();
-const { viewSummary } = useSummaryDialog();
-const { openConfirmationModal } = useVnConfirm();
+const tableRef = ref();
 
-const paginateRef = ref(null);
-const itemTypesOptions = ref([]);
-const originsOptions = ref([]);
-const buyersOptions = ref([]);
-const intrastatOptions = ref([]);
-const itemCategoriesOptions = ref([]);
-const visibleColumns = ref([]);
-const allColumnNames = ref([]);
-
-const exprBuilder = (param, value) => {
-    switch (param) {
-        case 'category':
-            return { 'ic.name': value };
-        case 'buyerFk':
-            return { 'it.workerFk': value };
-        case 'grouping':
-            return { 'b.grouping': value };
-        case 'packing':
-            return { 'b.packing': value };
-        case 'origin':
-            return { 'ori.code': value };
-        case 'typeFk':
-            return { 'i.typeFk': value };
-        case 'intrastat':
-            return { 'intr.description': value };
-        case 'name':
-            return { 'i.name': { like: `%${value}%` } };
-        case 'producer':
-            return { 'pr.name': { like: `%${value}%` } };
-        case 'id':
-        case 'size':
-        case 'subname':
-        case 'isActive':
-        case 'weightByPiece':
-        case 'stemMultiplier':
-        case 'stems':
-            return { [`i.${param}`]: value };
-    }
+const itemFilter = {
+    include: [
+        {
+            relation: 'trainingCourseType',
+            scope: {
+                fields: ['id', 'name'],
+            },
+        },
+        {
+            relation: 'trainingCenter',
+            scope: {
+                fields: ['id', 'name'],
+            },
+        },
+    ],
 };
-
-const params = reactive({ isFloramondo: false, isActive: true });
-
-const applyColumnFilter = async (col) => {
-    try {
-        const paramKey = col.columnFilter?.filterParamKey || col.field;
-        params[paramKey] = col.columnFilter.filterValue;
-        await paginateRef.value.addFilter(null, params);
-    } catch (err) {
-        console.error('Error applying column filter', err);
-    }
-};
-
-const getInputEvents = (col) => {
-    return col.columnFilter.type === 'select'
-        ? { 'update:modelValue': () => applyColumnFilter(col) }
-        : {
-              'keyup.enter': () => applyColumnFilter(col),
-          };
-};
-
 const columns = computed(() => [
     {
         label: '',
         name: 'picture',
         align: 'left',
-        columnFilter: null,
     },
     {
         label: t('item.list.id'),
         name: 'id',
         field: 'id',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
+        isId: true,
+        chip: {
+            condition: () => true,
         },
     },
     {
@@ -118,101 +52,41 @@ const columns = computed(() => [
         field: 'grouping',
         name: 'grouping',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
-        format: (val) => dashIfEmpty(val),
     },
     {
         label: t('item.list.packing'),
         field: 'packing',
         name: 'packing',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
-        format: (val) => dashIfEmpty(val),
     },
     {
         label: t('globals.description'),
         field: 'name',
         name: 'description',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
+        create: true,
     },
     {
         label: t('item.list.stems'),
         field: 'stems',
         name: 'stems',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
     },
     {
         label: t('item.list.size'),
         field: 'size',
         name: 'size',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
     },
     {
         label: t('item.list.typeName'),
         field: 'typeName',
         name: 'typeName',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnSelect,
-            filterParamKey: 'typeFk',
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                options: itemTypesOptions.value,
-                'option-value': 'id',
-                'option-label': 'name',
-                dense: true,
-            },
+        component: 'select',
+        attrs: {
+            url: 'ItemType',
+            fields: ['id', 'name'],
         },
     },
 
@@ -221,18 +95,10 @@ const columns = computed(() => [
         field: 'category',
         name: 'category',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnSelect,
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                options: itemCategoriesOptions.value,
-                'option-value': 'name',
-                'option-label': 'name',
-                dense: true,
-            },
+        component: 'select',
+        attrs: {
+            url: 'ItemCategory',
+            fields: ['id', 'name'],
         },
     },
 
@@ -241,18 +107,10 @@ const columns = computed(() => [
         field: 'intrastat',
         name: 'intrastat',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnSelect,
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                options: intrastatOptions.value,
-                'option-value': 'description',
-                'option-label': 'description',
-                dense: true,
-            },
+        component: 'select',
+        attrs: {
+            url: 'Intrastat',
+            fields: ['id', 'description'],
         },
     },
     {
@@ -260,18 +118,10 @@ const columns = computed(() => [
         field: 'origin',
         name: 'origin',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnSelect,
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                options: originsOptions.value,
-                'option-value': 'code',
-                'option-label': 'code',
-                dense: true,
-            },
+        component: 'select',
+        attrs: {
+            url: 'Origin',
+            fields: ['id', 'name'],
         },
     },
     {
@@ -279,36 +129,13 @@ const columns = computed(() => [
         field: 'userName',
         name: 'userName',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnSelect,
-            filterParamKey: 'buyerFk',
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                options: buyersOptions.value,
-                'option-value': 'id',
-                'option-label': 'nickname',
-                dense: true,
-            },
-        },
     },
     {
         label: t('item.list.weightByPiece'),
         field: 'weightByPiece',
         name: 'weightByPiece',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
+        component: 'input',
         format: (val) => dashIfEmpty(val),
     },
     {
@@ -316,16 +143,7 @@ const columns = computed(() => [
         field: 'stemMultiplier',
         name: 'stemMultiplier',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
+        component: 'input',
         format: (val) => dashIfEmpty(val),
     },
     {
@@ -333,40 +151,26 @@ const columns = computed(() => [
         field: 'isActive',
         name: 'isActive',
         align: 'left',
-        sortable: true,
-        columnFilter: null,
+        component: 'checkbox',
     },
     {
         label: t('item.list.producer'),
         field: 'producer',
         name: 'producer',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
+        component: 'select',
+        attrs: {
+            url: 'Producer',
+            fields: ['id', 'name'],
         },
-        format: (val) => dashIfEmpty(val),
     },
     {
         label: t('item.list.landed'),
         field: 'landed',
         name: 'landed',
         align: 'left',
-        sortable: true,
+        component: 'date',
         format: (val) => dashIfEmpty(toDateFormat(val)),
-        columnFilter: null,
-    },
-    {
-        label: '',
-        name: 'actions',
-        align: 'left',
-        columnFilter: null,
     },
 ]);
 
@@ -388,49 +192,11 @@ const cloneItem = async (itemFk) => {
     }
 };
 
-onMounted(async () => {
-    stateStore.rightDrawer = true;
-    const filteredColumns = columns.value.filter(
-        (col) => col.name !== 'picture' && col.name !== 'actions'
-    );
-    allColumnNames.value = filteredColumns.map((col) => col.name);
-});
-
 onUnmounted(() => (stateStore.rightDrawer = false));
 </script>
 
 <template>
-    <FetchData
-        url="ItemTypes"
-        :filter="{ fields: ['id', 'name'], order: 'name ASC' }"
-        auto-load
-        @on-fetch="(data) => (itemTypesOptions = data)"
-    />
-    <FetchData
-        url="ItemCategories"
-        :filter="{ fields: ['name'], order: 'name ASC' }"
-        auto-load
-        @on-fetch="(data) => (itemCategoriesOptions = data)"
-    />
-    <FetchData
-        url="Intrastats"
-        :filter="{ fields: ['description'], order: 'description ASC' }"
-        auto-load
-        @on-fetch="(data) => (intrastatOptions = data)"
-    />
-    <FetchData
-        url="Origins"
-        :filter="{ fields: ['code'], order: 'code ASC' }"
-        auto-load
-        @on-fetch="(data) => (originsOptions = data)"
-    />
-    <FetchData
-        url="TicketRequests/getItemTypeWorker"
-        :filter="{ fields: ['id', 'nickname'], order: 'nickname ASC' }"
-        auto-load
-        @on-fetch="(data) => (buyersOptions = data)"
-    />
-    <VnSubToolbar>
+    <!-- <VnSubToolbar>
         <template #st-data>
             <TableVisibleColumns
                 :all-columns="allColumnNames"
@@ -439,135 +205,28 @@ onUnmounted(() => (stateStore.rightDrawer = false));
                 @on-config-saved="visibleColumns = ['picture', ...$event, 'actions']"
             />
         </template>
-    </VnSubToolbar>
-    <RightMenu>
-        <template #right-panel>
-            <ItemListFilter data-key="ItemList" />
-        </template>
-    </RightMenu>
-    <QPage class="column items-center q-pa-md">
-        <VnPaginate
-            ref="paginateRef"
-            data-key="ItemList"
-            url="Items/filter"
-            :order="['isActive DESC', 'name', 'id']"
-            :limit="12"
-            :expr-builder="exprBuilder"
-            :user-params="params"
-            :keep-opts="['userParams']"
-            :offset="50"
-            auto-load
-        >
-            <template #body="{ rows }">
-                <QTable
-                    :rows="rows"
-                    :columns="columns"
-                    row-key="id"
-                    :pagination="{ rowsPerPage: 0 }"
-                    class="full-width q-mt-md"
-                    :visible-columns="visibleColumns"
-                    :no-data-label="t('globals.noResults')"
-                    @row-click="(_, row) => redirectToItemSummary(row.id)"
-                >
-                    <template #top-row="{ cols }">
-                        <QTr>
-                            <QTd
-                                v-for="(col, index) in cols"
-                                :key="index"
-                                style="max-width: 100px"
-                            >
-                                <component
-                                    :is="col.columnFilter.component"
-                                    v-if="col.columnFilter"
-                                    v-model="col.columnFilter.filterValue"
-                                    v-bind="col.columnFilter.attrs"
-                                    v-on="col.columnFilter.event(col)"
-                                    dense
-                                />
-                            </QTd>
-                        </QTr>
-                    </template>
-                    <template #body-cell-picture="{ row }">
-                        <QTd>
-                            <VnImg
-                                size="50x50"
-                                :id="row.id"
-                                height="50px"
-                                width="50px"
-                                class="image"
-                            />
-                        </QTd>
-                    </template>
-                    <template #body-cell-id="{ row }">
-                        <QTd @click.stop>
-                            <QBtn flat color="primary">
-                                {{ row.id }}
-                            </QBtn>
-                            <ItemDescriptorProxy :id="row.id" />
-                        </QTd>
-                    </template>
-                    <template #body-cell-userName="{ row }">
-                        <QTd @click.stop>
-                            <QBtn flat color="primary" dense>
-                                {{ row.userName }}
-                            </QBtn>
-                            <WorkerDescriptorProxy :id="row.buyerFk" />
-                        </QTd>
-                    </template>
-                    <template #body-cell-description="{ row }">
-                        <QTd class="col">
-                            <span>{{ row.name }} {{ row.subName }}</span>
-                            <FetchedTags :item="row" :max-length="6" />
-                        </QTd>
-                    </template>
-                    <template #body-cell-isActive="{ row }">
-                        <QTd>
-                            <QCheckbox :model-value="!!row.isActive" disable />
-                        </QTd>
-                    </template>
-                    <template #body-cell-actions="{ row }">
-                        <QTd>
-                            <QIcon
-                                @click.stop="
-                                    openConfirmationModal(
-                                        t(`All it's properties will be copied`),
-                                        t('Do you want to clone this item?'),
-                                        () => cloneItem(row.id)
-                                    )
-                                "
-                                class="q-ml-sm"
-                                color="primary"
-                                name="vn:clone"
-                                size="sm"
-                            >
-                                <QTooltip>
-                                    {{ t('globals.clone') }}
-                                </QTooltip>
-                            </QIcon>
-                            <QIcon
-                                @click.stop="viewSummary(row.id, ItemSummary)"
-                                class="q-ml-md"
-                                color="primary"
-                                name="preview"
-                                size="sm"
-                            >
-                                <QTooltip class="text-no-wrap">
-                                    {{ t('Preview') }}
-                                </QTooltip>
-                            </QIcon>
-                        </QTd>
-                    </template>
-                </QTable>
-            </template>
-        </VnPaginate>
-
-        <QPageSticky :offset="[20, 20]">
-            <QBtn @click="redirectToItemCreate()" color="primary" fab icon="add" />
-            <QTooltip class="text-no-wrap">
-                {{ t('New item') }}
-            </QTooltip>
-        </QPageSticky>
-    </QPage>
+    </VnSubToolbar> -->
+    <VnTable
+        ref="tableRef"
+        data-key="ItemList"
+        url="Items"
+        url-create="Items"
+        save-url="Items/crud"
+        :create="{
+            urlCreate: 'Items',
+            title: 'Create Item',
+            onDataSaved: () => tableRef.redirect(),
+            formInitialData: {
+                editorFk: entityId,
+            },
+        }"
+        order="id ASC"
+        :columns="columns"
+        auto-load
+        :right-search="false"
+        :is-editable="false"
+        :use-model="true"
+    />
 </template>
 
 <i18n>

From 16b5b5d9a1111f31a8c07f53272a8f6f77ae71ba Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 15 Jul 2024 13:48:59 +0200
Subject: [PATCH 02/87] refs #7283 filter

---
 src/pages/Item/ItemList.vue | 64 +++++++++++++++++++++++++++++++------
 1 file changed, 55 insertions(+), 9 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 334ef2604..4c49f068f 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -1,30 +1,39 @@
 <script setup>
 import { onMounted, ref, computed, reactive, onUnmounted } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { useRouter } from 'vue-router';
+import { useRouter, useRoute } from 'vue-router';
+import VnImg from 'src/components/ui/VnImg.vue';
 
 import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
-import { toDateFormat } from 'src/filters/date.js';
+import { toDate } from 'src/filters';
 import { dashIfEmpty } from 'src/filters';
 import axios from 'axios';
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
+const entityId = computed(() => route.params.id);
 
 const router = useRouter();
 const stateStore = useStateStore();
 const { t } = useI18n();
 const tableRef = ref();
+const route = useRoute();
 
 const itemFilter = {
     include: [
         {
-            relation: 'trainingCourseType',
+            relation: 'itemType',
             scope: {
                 fields: ['id', 'name'],
             },
         },
         {
-            relation: 'trainingCenter',
+            relation: 'intrastat',
+            scope: {
+                fields: ['id', 'description'],
+            },
+        },
+        {
+            relation: 'origin',
             scope: {
                 fields: ['id', 'name'],
             },
@@ -34,8 +43,18 @@ const itemFilter = {
 const columns = computed(() => [
     {
         label: '',
-        name: 'picture',
+        name: 'image',
         align: 'left',
+        columnField: {
+            component: VnImg,
+            attrs: (id) => {
+                return {
+                    id,
+                    width: '50px',
+                };
+            },
+        },
+        columnFilter: false,
     },
     {
         label: t('item.list.id'),
@@ -88,6 +107,10 @@ const columns = computed(() => [
             url: 'ItemType',
             fields: ['id', 'name'],
         },
+        columnField: {
+            component: null,
+        },
+        create: true,
     },
 
     {
@@ -100,6 +123,9 @@ const columns = computed(() => [
             url: 'ItemCategory',
             fields: ['id', 'name'],
         },
+        columnField: {
+            component: null,
+        },
     },
 
     {
@@ -112,6 +138,10 @@ const columns = computed(() => [
             url: 'Intrastat',
             fields: ['id', 'description'],
         },
+        columnField: {
+            component: null,
+        },
+        create: true,
     },
     {
         label: t('item.list.origin'),
@@ -123,6 +153,10 @@ const columns = computed(() => [
             url: 'Origin',
             fields: ['id', 'name'],
         },
+        columnField: {
+            component: null,
+        },
+        create: true,
     },
     {
         label: t('item.list.userName'),
@@ -136,7 +170,9 @@ const columns = computed(() => [
         name: 'weightByPiece',
         align: 'left',
         component: 'input',
-        format: (val) => dashIfEmpty(val),
+        columnField: {
+            component: null,
+        },
     },
     {
         label: t('item.list.stemMultiplier'),
@@ -144,7 +180,9 @@ const columns = computed(() => [
         name: 'stemMultiplier',
         align: 'left',
         component: 'input',
-        format: (val) => dashIfEmpty(val),
+        columnField: {
+            component: null,
+        },
     },
     {
         label: t('item.list.isActive'),
@@ -163,6 +201,9 @@ const columns = computed(() => [
             url: 'Producer',
             fields: ['id', 'name'],
         },
+        columnField: {
+            component: null,
+        },
     },
     {
         label: t('item.list.landed'),
@@ -170,7 +211,10 @@ const columns = computed(() => [
         name: 'landed',
         align: 'left',
         component: 'date',
-        format: (val) => dashIfEmpty(toDateFormat(val)),
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landed)),
     },
 ]);
 
@@ -209,9 +253,10 @@ onUnmounted(() => (stateStore.rightDrawer = false));
     <VnTable
         ref="tableRef"
         data-key="ItemList"
-        url="Items"
+        url="Items/filter"
         url-create="Items"
         save-url="Items/crud"
+        :filter="itemFilter"
         :create="{
             urlCreate: 'Items',
             title: 'Create Item',
@@ -223,6 +268,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         order="id ASC"
         :columns="columns"
         auto-load
+        redirect="Item"
         :right-search="false"
         :is-editable="false"
         :use-model="true"

From afbcd2ebda00ec2487ebc090940f83405ce54f1f Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 15 Jul 2024 14:31:33 +0200
Subject: [PATCH 03/87] refs #7283 item filters

---
 src/pages/Item/ItemList.vue     |  14 ++--
 src/pages/Item/ItemTypeList.vue | 140 ++++++++++++++++++++------------
 2 files changed, 91 insertions(+), 63 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 4c49f068f..e2c5f4bb3 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -7,9 +7,7 @@ import VnImg from 'src/components/ui/VnImg.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { toDate } from 'src/filters';
-import { dashIfEmpty } from 'src/filters';
 import axios from 'axios';
-import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 const entityId = computed(() => route.params.id);
 
 const router = useRouter();
@@ -104,7 +102,7 @@ const columns = computed(() => [
         align: 'left',
         component: 'select',
         attrs: {
-            url: 'ItemType',
+            url: 'ItemTypes',
             fields: ['id', 'name'],
         },
         columnField: {
@@ -112,7 +110,6 @@ const columns = computed(() => [
         },
         create: true,
     },
-
     {
         label: t('item.list.category'),
         field: 'category',
@@ -120,14 +117,13 @@ const columns = computed(() => [
         align: 'left',
         component: 'select',
         attrs: {
-            url: 'ItemCategory',
+            url: 'ItemCategories',
             fields: ['id', 'name'],
         },
         columnField: {
             component: null,
         },
     },
-
     {
         label: t('item.list.intrastat'),
         field: 'intrastat',
@@ -135,7 +131,7 @@ const columns = computed(() => [
         align: 'left',
         component: 'select',
         attrs: {
-            url: 'Intrastat',
+            url: 'Intrastats',
             fields: ['id', 'description'],
         },
         columnField: {
@@ -150,7 +146,7 @@ const columns = computed(() => [
         align: 'left',
         component: 'select',
         attrs: {
-            url: 'Origin',
+            url: 'Origins',
             fields: ['id', 'name'],
         },
         columnField: {
@@ -198,7 +194,7 @@ const columns = computed(() => [
         align: 'left',
         component: 'select',
         attrs: {
-            url: 'Producer',
+            url: 'Producers',
             fields: ['id', 'name'],
         },
         columnField: {
diff --git a/src/pages/Item/ItemTypeList.vue b/src/pages/Item/ItemTypeList.vue
index 125672d60..c02f9bb43 100644
--- a/src/pages/Item/ItemTypeList.vue
+++ b/src/pages/Item/ItemTypeList.vue
@@ -1,20 +1,13 @@
 <script setup>
 import { useI18n } from 'vue-i18n';
 import { useRouter } from 'vue-router';
-
-import VnPaginate from 'src/components/ui/VnPaginate.vue';
-import VnLv from 'src/components/ui/VnLv.vue';
-import CardList from 'src/components/ui/CardList.vue';
-import ItemTypeSummary from 'src/pages/ItemType/Card/ItemTypeSummary.vue';
-import ItemTypeFilter from 'src/pages/ItemType/ItemTypeFilter.vue';
+import { ref, computed } from 'vue';
 import ItemTypeSearchbar from '../ItemType/ItemTypeSearchbar.vue';
-import { useSummaryDialog } from 'src/composables/useSummaryDialog';
-import RightMenu from 'src/components/common/RightMenu.vue';
+import VnTable from 'components/VnTable/VnTable.vue';
 
 const router = useRouter();
 const { t } = useI18n();
-const { viewSummary } = useSummaryDialog();
-
+const tableRef = ref();
 const redirectToItemTypeSummary = (id) => {
     router.push({ name: 'ItemTypeSummary', params: { id } });
 };
@@ -56,52 +49,91 @@ const exprBuilder = (param, value) => {
             }
     }
 };
+
+const columns = computed(() => [
+    {
+        align: 'left',
+        name: 'id',
+        label: t('id'),
+        isId: true,
+        cardVisible: true,
+    },
+    {
+        align: 'left',
+        name: 'code',
+        label: t('code'),
+        isTitle: true,
+        cardVisible: true,
+        create: true,
+    },
+    {
+        align: 'left',
+        name: 'name',
+        label: t('name'),
+        cardVisible: true,
+        create: true,
+    },
+    {
+        align: 'left',
+        name: 'worker',
+        label: t('worker'),
+        create: true,
+        component: 'select',
+        attrs: {
+            url: 'Workers',
+            fields: ['id', 'firstName'],
+        },
+        cardVisible: true,
+    },
+    {
+        align: 'left',
+        name: 'ItemCategory',
+        label: t('ItemCategory'),
+        create: true,
+        component: 'select',
+        attrs: {
+            url: 'ItemCategories',
+            fields: ['id', 'name'],
+        },
+        cardVisible: true,
+    },
+    {
+        align: 'left',
+        name: 'Temperature',
+        label: t('Temperature'),
+        create: true,
+        component: 'select',
+        attrs: {
+            url: 'Temperatures',
+            fields: ['id', 'name'],
+        },
+        cardVisible: true,
+    },
+]);
 </script>
 
 <template>
     <ItemTypeSearchbar />
-    <RightMenu>
-        <template #right-panel>
-            <ItemTypeFilter data-key="ItemTypeList" />
-        </template>
-    </RightMenu>
-    <QPage class="column items-center q-pa-md">
-        <div class="vn-card-list">
-            <VnPaginate
-                data-key="ItemTypeList"
-                url="ItemTypes"
-                :order="['name']"
-                auto-load
-                :expr-builder="exprBuilder"
-            >
-                <template #body="{ rows }">
-                    <CardList
-                        v-for="row of rows"
-                        :key="row.id"
-                        :title="row.code"
-                        @click="redirectToItemTypeSummary(row.id)"
-                        :id="row.id"
-                    >
-                        <template #list-items>
-                            <VnLv :label="t('Name')" :value="row.name" />
-                        </template>
-                        <template #actions>
-                            <QBtn
-                                :label="t('components.smartCard.openSummary')"
-                                @click.stop="viewSummary(row.id, ItemTypeSummary)"
-                                color="primary"
-                                type="submit"
-                            />
-                        </template>
-                    </CardList>
-                </template>
-            </VnPaginate>
-        </div>
-    </QPage>
-    <QPageSticky :offset="[20, 20]">
-        <QBtn fab icon="add" color="primary" @click="redirectToCreateView()" />
-        <QTooltip>
-            {{ t('New item type') }}
-        </QTooltip>
-    </QPageSticky>
+    <VnTable
+        ref="tableRef"
+        data-key="ItemTypeList"
+        :url="`ItemTypes`"
+        :url-create="`ItemTypes`"
+        save-url="ItemTypes/crud"
+        :filter="courseFilter"
+        :create="{
+            urlCreate: 'ItemTypes',
+            title: 'Create ItemTypes',
+            onDataSaved: () => tableRef.reload(),
+            formInitialData: {
+                workerFk: entityId,
+            },
+        }"
+        order="id DESC"
+        :columns="columns"
+        auto-load
+        :right-search="false"
+        :is-editable="false"
+        :use-model="true"
+    />
 </template>

From daf99f47306f2ae346e9fd023bce9e8b8c222c7b Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 15 Jul 2024 15:00:43 +0200
Subject: [PATCH 04/87] refs #7283 itemRequestList

---
 src/pages/Item/ItemRequest.vue | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index ae6638953..10cb6c2a6 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -18,6 +18,7 @@ import useNotify from 'src/composables/useNotify.js';
 import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js';
 import axios from 'axios';
 import RightMenu from 'src/components/common/RightMenu.vue';
+import { toDate } from 'src/filters';
 
 const { t } = useI18n();
 const { notify } = useNotify();
@@ -46,21 +47,28 @@ const columns = computed(() => [
         name: 'id',
         field: 'id',
         align: 'left',
-        sortable: true,
+        isId: true,
+        chip: {
+            condition: () => true,
+        },
+        cardVisible: true,
     },
     {
         label: t('item.buyRequest.shipped'),
         field: 'shipped',
         name: 'shipped',
         align: 'left',
-        sortable: true,
+        component: 'date',
+        columnField: {
+            component: null,
+        },
+        format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.shipped)),
     },
     {
         label: t('globals.description'),
         field: 'description',
         name: 'description',
         align: 'left',
-        sortable: true,
     },
     {
         label: t('item.buyRequest.requester'),
@@ -80,29 +88,31 @@ const columns = computed(() => [
         field: 'price',
         name: 'price',
         align: 'left',
-        sortable: true,
-        format: (val) => toCurrency(val),
+        format: (row) => toCurrency(row.price),
     },
     {
         label: t('item.buyRequest.attender'),
         field: 'attender',
         name: 'attender',
         align: 'left',
-        sortable: true,
+        attrs: {
+            url: 'Workers',
+            fields: ['id', 'firstName'],
+        },
     },
     {
         label: t('item.buyRequest.item'),
         field: 'item',
         name: 'item',
         align: 'left',
-        sortable: true,
+        component: 'input',
     },
     {
         label: t('item.buyRequest.achieved'),
         field: 'achieved',
         name: 'achieved',
         align: 'left',
-        sortable: true,
+        component: 'input',
     },
     {
         label: t('item.buyRequest.concept'),

From b7ba8eec3da2524c3fc2834dc2e4ffb64dbfc20d Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 16 Jul 2024 08:24:57 +0200
Subject: [PATCH 05/87] refs #7283 fix searchbar

---
 src/pages/Item/ItemList.vue | 41 +++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index e2c5f4bb3..17a62c5b9 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -3,11 +3,12 @@ import { onMounted, ref, computed, reactive, onUnmounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRouter, useRoute } from 'vue-router';
 import VnImg from 'src/components/ui/VnImg.vue';
-
+import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { toDate } from 'src/filters';
 import axios from 'axios';
+import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 const entityId = computed(() => route.params.id);
 
 const router = useRouter();
@@ -212,16 +213,21 @@ const columns = computed(() => [
         },
         format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landed)),
     },
+    {
+        align: 'right',
+        label: '',
+        name: 'tableActions',
+        actions: [
+            {
+                title: t('Clone item'),
+                icon: 'vn:clone',
+                action: cloneItem,
+                isPrimary: true,
+            },
+        ],
+    },
 ]);
 
-const redirectToItemCreate = () => {
-    router.push({ name: 'ItemCreate' });
-};
-
-const redirectToItemSummary = (id) => {
-    router.push({ name: 'ItemSummary', params: { id } });
-};
-
 const cloneItem = async (itemFk) => {
     try {
         const { data } = await axios.post(`Items/${itemFk}/clone`);
@@ -236,16 +242,11 @@ onUnmounted(() => (stateStore.rightDrawer = false));
 </script>
 
 <template>
-    <!-- <VnSubToolbar>
-        <template #st-data>
-            <TableVisibleColumns
-                :all-columns="allColumnNames"
-                table-code="itemsIndex"
-                labels-traductions-path="item.list"
-                @on-config-saved="visibleColumns = ['picture', ...$event, 'actions']"
-            />
-        </template>
-    </VnSubToolbar> -->
+    <VnSearchbar
+        data-key="ItemList"
+        :label="t('Search Item')"
+        :info="t('You can search by id')"
+    />
     <VnTable
         ref="tableRef"
         data-key="ItemList"
@@ -265,7 +266,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         :columns="columns"
         auto-load
         redirect="Item"
-        :right-search="false"
+        :right-search="true"
         :is-editable="false"
         :use-model="true"
     />

From 85b030c7bc07fa7e2abf7e1c7e0d969c7000322d Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 16 Jul 2024 08:31:04 +0200
Subject: [PATCH 06/87] refs #7283 view summary

---
 src/pages/Item/ItemList.vue | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 17a62c5b9..0e444254f 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -9,8 +9,10 @@ import { useStateStore } from 'stores/useStateStore';
 import { toDate } from 'src/filters';
 import axios from 'axios';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
+import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 const entityId = computed(() => route.params.id);
 
+const { viewSummary } = useSummaryDialog();
 const router = useRouter();
 const stateStore = useStateStore();
 const { t } = useI18n();
@@ -224,6 +226,11 @@ const columns = computed(() => [
                 action: cloneItem,
                 isPrimary: true,
             },
+            {
+                title: t('view Summary'),
+                icon: 'preview',
+                action: (row) => viewSummary(row.id),
+            },
         ],
     },
 ]);

From cce1d891fb67b738a45d6f3d59cbcda6dd1dde5d Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 16 Jul 2024 08:48:50 +0200
Subject: [PATCH 07/87] refs #7283 fix viewSummary

---
 src/pages/Item/ItemList.vue | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 0e444254f..273374150 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -10,6 +10,7 @@ import { toDate } from 'src/filters';
 import axios from 'axios';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import { useSummaryDialog } from 'src/composables/useSummaryDialog';
+import ItemSummary from '../Item/Card/ItemSummary.vue';
 const entityId = computed(() => route.params.id);
 
 const { viewSummary } = useSummaryDialog();
@@ -229,7 +230,7 @@ const columns = computed(() => [
             {
                 title: t('view Summary'),
                 icon: 'preview',
-                action: (row) => viewSummary(row.id),
+                action: (row) => viewSummary(row.id, ItemSummary),
             },
         ],
     },

From 339f6e810bf87a9115691c69f447b43988b08e2d Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 16 Jul 2024 10:34:00 +0200
Subject: [PATCH 08/87] refs #7283 fix descriptorproxy

---
 src/pages/Item/ItemList.vue | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 273374150..6893d55a1 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -11,6 +11,7 @@ import axios from 'axios';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 import ItemSummary from '../Item/Card/ItemSummary.vue';
+import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 const entityId = computed(() => route.params.id);
 
 const { viewSummary } = useSummaryDialog();
@@ -277,7 +278,14 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         :right-search="true"
         :is-editable="false"
         :use-model="true"
-    />
+    >
+        <template #column-userName="{ row }">
+            <span class="link" @click.stop>
+                {{ row.userName }}
+                <WorkerDescriptorProxy :id="row.buyerFk" />
+            </span>
+        </template>
+    </VnTable>
 </template>
 
 <i18n>

From f29d873ed42abad1c45d641a51aa02bc2ab02db1 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 16 Jul 2024 12:15:39 +0200
Subject: [PATCH 09/87] refs #7283 fix request

---
 src/pages/Item/ItemRequest.vue | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 10cb6c2a6..e5faff6b2 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -120,13 +120,13 @@ const columns = computed(() => [
         name: 'concept',
         align: 'left',
         sortable: true,
+        component: 'input',
     },
     {
         label: t('item.buyRequest.state'),
         field: 'state',
         name: 'state',
         align: 'left',
-        sortable: true,
     },
     {
         label: '',
@@ -252,7 +252,6 @@ onBeforeMount(() => {
                     <TicketDescriptorProxy :id="row.ticketFk" />
                 </QTd>
             </template>
-
             <template #body-cell-shipped="{ row }">
                 <QTd>
                     <QBadge

From 86ae827fda7a8c45b346fdfaa490225b10039cbd Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 16 Jul 2024 13:48:32 +0200
Subject: [PATCH 10/87] refs #7283 clone

---
 src/pages/Item/ItemList.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 6893d55a1..c44438087 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -239,7 +239,7 @@ const columns = computed(() => [
 
 const cloneItem = async (itemFk) => {
     try {
-        const { data } = await axios.post(`Items/${itemFk}/clone`);
+        const { data } = await axios.post(`Items/${itemFk.id}/clone`);
         if (!data) return;
         router.push({ name: 'ItemTags', params: { id: data.id } });
     } catch (err) {

From 4d394a98a4f3d2b23bd580fcbe0a0186892e9b0c Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 22 Jul 2024 08:24:59 +0200
Subject: [PATCH 11/87] refs #7283 fix yml list basicData

---
 src/i18n/locale/en.yml                | 21 +++++++++++-
 src/i18n/locale/es.yml                | 21 +++++++++++-
 src/pages/Item/Card/ItemBasicData.vue | 47 ++++++++++++++++-----------
 src/pages/Item/ItemList.vue           |  1 -
 4 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index 2f1209a3a..a3d7362b3 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -246,7 +246,6 @@ globals:
         mailForwarding: Mail forwarding
         mailAlias: Mail alias
         privileges: Privileges
-        labeler: Labeler
     created: Created
     worker: Worker
     now: Now
@@ -1194,6 +1193,26 @@ item:
         stemMultiplier: Multiplier
         producer: Producer
         landed: Landed
+    basicData:
+        type: Type
+        reference: Reference
+        relevancy: Relevancy
+        stems: Stems
+        multiplier: Multiplier
+        generic: Generic
+        intrastat: Intrastat
+        expense: Expense
+        weightByPiece: Weight/Piece
+        boxUnits: Units/Box
+        recycledPlastic: Recycled Plastic
+        nonRecycledPlastic: Non recycled plastic
+        isActive: Active
+        hasKgPrice: Price in kg
+        isFragile: Fragile
+        isFragileTooltip: Is shown at website, app that this item cannot travel (wreath, palms, ...)
+        isPhotoRequested: Do photo
+        isPhotoRequestedTooltip: This item does need a photo
+        description: Description
     fixedPrice:
         itemId: Item ID
         groupingPrice: Grouping price
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index c5c4fab66..71b2c5919 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -248,7 +248,6 @@ globals:
         components: Componentes
         pictures: Fotos
         packages: Bultos
-        labeler: Etiquetas
     created: Fecha creación
     worker: Trabajador
     now: Ahora
@@ -1175,6 +1174,26 @@ item:
         stemMultiplier: Multiplicador
         producer: Productor
         landed: F. entrega
+    basicData:
+        type: Tipo
+        reference: Referencia
+        relevancy: Relevancia
+        stems: Tallos
+        multiplier: Multiplicador
+        generic: Genérico
+        intrastat: Intrastat
+        expense: Gasto
+        weightByPiece: Peso (gramos)/tallo
+        boxUnits: Unidades/caja
+        recycledPlastic: Plastico reciclado
+        nonRecycledPlastic: Plático no reciclado
+        isActive: Activo
+        hasKgPrice: Precio en kg
+        isFragile: Frágil
+        isFragileTooltip: Se muestra en la web, app que este artículo no puede viajar (coronas, palmas, ...)
+        isPhotoRequested: Hacer foto
+        isPhotoRequestedTooltip: Este artículo necesita una foto
+        description: Descripción
     fixedPrice:
         itemId: ID Artículo
         groupingPrice: Precio grouping
diff --git a/src/pages/Item/Card/ItemBasicData.vue b/src/pages/Item/Card/ItemBasicData.vue
index eb486f551..07242635b 100644
--- a/src/pages/Item/Card/ItemBasicData.vue
+++ b/src/pages/Item/Card/ItemBasicData.vue
@@ -73,7 +73,7 @@ const onIntrastatCreated = (response, formData) => {
         <template #form="{ data }">
             <VnRow class="row q-gutter-md q-mb-md">
                 <VnSelect
-                    :label="t('basicData.type')"
+                    :label="t('item.basicData.type')"
                     v-model="data.typeFk"
                     :options="itemTypesOptions"
                     option-value="id"
@@ -92,17 +92,20 @@ const onIntrastatCreated = (response, formData) => {
                         </QItem>
                     </template>
                 </VnSelect>
-                <VnInput :label="t('basicData.reference')" v-model="data.comment" />
-                <VnInput :label="t('basicData.relevancy')" v-model="data.relevancy" />
+                <VnInput :label="t('item.basicData.reference')" v-model="data.comment" />
+                <VnInput
+                    :label="t('item.basicData.relevancy')"
+                    v-model="data.relevancy"
+                />
             </VnRow>
             <VnRow class="row q-gutter-md q-mb-md">
-                <VnInput :label="t('basicData.stems')" v-model="data.stems" />
+                <VnInput :label="t('item.basicData.stems')" v-model="data.stems" />
                 <VnInput
-                    :label="t('basicData.multiplier')"
+                    :label="t('item.basicData.multiplier')"
                     v-model="data.stemMultiplier"
                 />
                 <VnSelectDialog
-                    :label="t('basicData.generic')"
+                    :label="t('item.basicData.generic')"
                     v-model="data.genericFk"
                     :options="itemsWithNameOptions"
                     option-value="id"
@@ -129,7 +132,7 @@ const onIntrastatCreated = (response, formData) => {
             </VnRow>
             <VnRow class="row q-gutter-md q-mb-md">
                 <VnSelectDialog
-                    :label="t('basicData.intrastat')"
+                    :label="t('item.basicData.intrastat')"
                     v-model="data.intrastatFk"
                     :options="intrastatsOptions"
                     option-value="id"
@@ -156,7 +159,7 @@ const onIntrastatCreated = (response, formData) => {
                 </VnSelectDialog>
                 <div class="col">
                     <VnSelect
-                        :label="t('basicData.expense')"
+                        :label="t('item.basicData.expense')"
                         v-model="data.expenseFk"
                         :options="expensesOptions"
                         option-value="id"
@@ -168,61 +171,67 @@ const onIntrastatCreated = (response, formData) => {
             </VnRow>
             <VnRow class="row q-gutter-md q-mb-md">
                 <VnInput
-                    :label="t('basicData.weightByPiece')"
+                    :label="t('item.basicData.weightByPiece')"
                     v-model.number="data.weightByPiece"
                     :min="0"
                     type="number"
                 />
                 <VnInput
-                    :label="t('basicData.boxUnits')"
+                    :label="t('item.basicData.boxUnits')"
                     v-model.number="data.packingOut"
                     :min="0"
                     type="number"
                 />
                 <VnInput
-                    :label="t('basicData.recycledPlastic')"
+                    :label="t('item.basicData.recycledPlastic')"
                     v-model.number="data.recycledPlastic"
                     :min="0"
                     type="number"
                 />
                 <VnInput
-                    :label="t('basicData.nonRecycledPlastic')"
+                    :label="t('item.basicData.nonRecycledPlastic')"
                     v-model.number="data.nonRecycledPlastic"
                     :min="0"
                     type="number"
                 />
             </VnRow>
             <VnRow class="row q-gutter-md q-mb-md">
-                <QCheckbox v-model="data.isActive" :label="t('basicData.isActive')" />
-                <QCheckbox v-model="data.hasKgPrice" :label="t('basicData.hasKgPrice')" />
+                <QCheckbox
+                    v-model="data.isActive"
+                    :label="t('item.basicData.isActive')"
+                />
+                <QCheckbox
+                    v-model="data.hasKgPrice"
+                    :label="t('item.basicData.hasKgPrice')"
+                />
                 <div>
                     <QCheckbox
                         v-model="data.isFragile"
-                        :label="t('basicData.isFragile')"
+                        :label="t('item.basicData.isFragile')"
                         class="q-mr-sm"
                     />
                     <QIcon name="info" class="cursor-pointer" size="xs">
                         <QTooltip max-width="300px">
-                            {{ t('basicData.isFragileTooltip') }}
+                            {{ t('item.basicData.isFragileTooltip') }}
                         </QTooltip>
                     </QIcon>
                 </div>
                 <div>
                     <QCheckbox
                         v-model="data.isPhotoRequested"
-                        :label="t('basicData.isPhotoRequested')"
+                        :label="t('item.basicData.isPhotoRequested')"
                         class="q-mr-sm"
                     />
                     <QIcon name="info" class="cursor-pointer" size="xs">
                         <QTooltip>
-                            {{ t('basicData.isPhotoRequestedTooltip') }}
+                            {{ t('item.basicData.isPhotoRequestedTooltip') }}
                         </QTooltip>
                     </QIcon>
                 </div>
             </VnRow>
             <VnRow>
                 <VnInput
-                    :label="t('basicData.description')"
+                    :label="t('item.basicData.description')"
                     type="textarea"
                     v-model="data.description"
                     fill-input
diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index c44438087..169ee93d6 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -226,7 +226,6 @@ const columns = computed(() => [
                 title: t('Clone item'),
                 icon: 'vn:clone',
                 action: cloneItem,
-                isPrimary: true,
             },
             {
                 title: t('view Summary'),

From f678c6304313cbc6d976c9df21f7f0e33c958dac Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 22 Jul 2024 13:35:41 +0200
Subject: [PATCH 12/87] refs #7283 request

---
 src/i18n/locale/en.yml         |  2 +-
 src/pages/Item/ItemList.vue    |  6 +----
 src/pages/Item/ItemRequest.vue | 40 +++++++++++++++++-----------------
 3 files changed, 22 insertions(+), 26 deletions(-)

diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index a3d7362b3..33862f766 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -1235,7 +1235,7 @@ item:
         requester: 'Requester'
         requested: 'Requested'
         price: 'Price'
-        attender: 'Atender'
+        attender: 'Attender'
         item: 'Item'
         achieved: 'Achieved'
         concept: 'Concept'
diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 169ee93d6..2532a6df2 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -1,9 +1,8 @@
 <script setup>
-import { onMounted, ref, computed, reactive, onUnmounted } from 'vue';
+import { ref, computed, onUnmounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRouter, useRoute } from 'vue-router';
 import VnImg from 'src/components/ui/VnImg.vue';
-import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { toDate } from 'src/filters';
@@ -245,8 +244,6 @@ const cloneItem = async (itemFk) => {
         console.error('Error cloning item', err);
     }
 };
-
-onUnmounted(() => (stateStore.rightDrawer = false));
 </script>
 
 <template>
@@ -274,7 +271,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         :columns="columns"
         auto-load
         redirect="Item"
-        :right-search="true"
         :is-editable="false"
         :use-model="true"
     >
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index e5faff6b2..ed6f623aa 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -1,24 +1,14 @@
 <script setup>
 import { ref, computed, onMounted, onBeforeMount, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
-import FetchData from 'components/FetchData.vue';
-import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
-import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
-import VnInput from 'src/components/common/VnInput.vue';
-import ItemRequestDenyForm from './ItemRequestDenyForm.vue';
-import ItemRequestFilter from './ItemRequestFilter.vue';
-import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
-import VnSelect from 'components/common/VnSelect.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { useArrayData } from 'composables/useArrayData';
-import { toDateFormat } from 'src/filters/date';
 import { toCurrency } from 'filters/index';
 import useNotify from 'src/composables/useNotify.js';
-import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js';
 import axios from 'axios';
-import RightMenu from 'src/components/common/RightMenu.vue';
 import { toDate } from 'src/filters';
+import VnTable from 'components/VnTable/VnTable.vue';
 
 const { t } = useI18n();
 const { notify } = useNotify();
@@ -72,16 +62,15 @@ const columns = computed(() => [
     },
     {
         label: t('item.buyRequest.requester'),
-        name: 'requester',
+        field: 'requesterName',
+        name: 'requesterFk',
         align: 'left',
-        sortable: true,
     },
     {
         label: t('item.buyRequest.requested'),
         field: 'quantity',
         name: 'requested',
         align: 'left',
-        sortable: true,
     },
     {
         label: t('item.buyRequest.price'),
@@ -95,10 +84,6 @@ const columns = computed(() => [
         field: 'attender',
         name: 'attender',
         align: 'left',
-        attrs: {
-            url: 'Workers',
-            fields: ['id', 'firstName'],
-        },
     },
     {
         label: t('item.buyRequest.item'),
@@ -218,7 +203,7 @@ onBeforeMount(() => {
 </script>
 
 <template>
-    <FetchData
+    <!-- <FetchData
         url="Workers"
         :filter="{ where: { role: 'buyer' } }"
         order="id"
@@ -350,7 +335,22 @@ onBeforeMount(() => {
                 @on-data-saved="onDenyAccept"
             />
         </QDialog>
-    </QPage>
+    </QPage> -->
+    <VnTable
+        ref="tableRef"
+        data-key="itemRequest"
+        url="ticketRequests"
+        order="id DESC"
+        :columns="columns"
+        auto-load
+    >
+        <template #column-attender="{ row }">
+            <span class="link" @click.stop>
+                {{ row.attenderFk }}
+                <WorkerDescriptorProxy :id="row.attenderFk" />
+            </span>
+        </template>
+    </VnTable>
 </template>
 
 <i18n>

From b668d07e2dc4fb453efcd1050abbc0f6fd570687 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 1 Aug 2024 13:20:33 +0200
Subject: [PATCH 13/87] refs #7283 fetchedTags

---
 src/pages/Item/ItemList.vue    | 46 +++++++++++++++++++++++-----------
 src/pages/Item/ItemRequest.vue | 17 ++++++++++---
 2 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 2532a6df2..a3b70372f 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -7,6 +7,7 @@ import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { toDate } from 'src/filters';
 import axios from 'axios';
+import FetchedTags from 'src/components/ui/FetchedTags.vue';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 import ItemSummary from '../Item/Card/ItemSummary.vue';
@@ -43,21 +44,21 @@ const itemFilter = {
     ],
 };
 const columns = computed(() => [
-    {
-        label: '',
-        name: 'image',
-        align: 'left',
-        columnField: {
-            component: VnImg,
-            attrs: (id) => {
-                return {
-                    id,
-                    width: '50px',
-                };
-            },
-        },
-        columnFilter: false,
-    },
+    // {
+    //     label: '',
+    //     name: 'image',
+    //     align: 'left',
+    //     columnField: {
+    //         component: VnImg,
+    //         attrs: (id) => {
+    //             return {
+    //                 id,
+    //                 width: '50px',
+    //             };
+    //         },
+    //     },
+    //     columnFilter: false,
+    // },
     {
         label: t('item.list.id'),
         name: 'id',
@@ -280,9 +281,24 @@ const cloneItem = async (itemFk) => {
                 <WorkerDescriptorProxy :id="row.buyerFk" />
             </span>
         </template>
+        <template #column-description="{ row }">
+            <div class="row column full-width justify-between items-start">
+                {{ row?.name }}
+                <div v-if="row?.subName" class="subName">
+                    {{ row?.subName.toUpperCase() }}
+                </div>
+            </div>
+            <FetchedTags :item="row" :max-length="6" />
+        </template>
     </VnTable>
 </template>
 
+<style lang="scss" scoped>
+.subName {
+    text-transform: uppercase;
+    color: var(--vn-label-color);
+}
+</style>
 <i18n>
 es:
     New item: Nuevo artículo
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index ed6f623aa..0389ba864 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -13,7 +13,6 @@ import VnTable from 'components/VnTable/VnTable.vue';
 const { t } = useI18n();
 const { notify } = useNotify();
 const stateStore = useStateStore();
-const workersOptions = ref([]);
 let filterParams = ref({});
 const denyFormRef = ref(null);
 const denyRequestId = ref(null);
@@ -91,6 +90,7 @@ const columns = computed(() => [
         name: 'item',
         align: 'left',
         component: 'input',
+        visible: false,
     },
     {
         label: t('item.buyRequest.achieved'),
@@ -98,6 +98,7 @@ const columns = computed(() => [
         name: 'achieved',
         align: 'left',
         component: 'input',
+        visible: false,
     },
     {
         label: t('item.buyRequest.concept'),
@@ -106,6 +107,7 @@ const columns = computed(() => [
         align: 'left',
         sortable: true,
         component: 'input',
+        visible: false,
     },
     {
         label: t('item.buyRequest.state'),
@@ -114,10 +116,17 @@ const columns = computed(() => [
         align: 'left',
     },
     {
+        align: 'right',
         label: '',
-        name: 'action',
-        align: 'left',
-        columnFilter: null,
+        name: 'tableActions',
+        actions: [
+            {
+                title: t('Client ticket list'),
+                icon: 'thumb_down',
+                action: onDenyAccept,
+                isPrimary: true,
+            },
+        ],
     },
 ]);
 

From fe78de0c4761772593a3e714c69894f36651e696 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 5 Aug 2024 11:49:06 +0200
Subject: [PATCH 14/87] refs #7283 fixedPrices

---
 src/pages/Item/ItemFixedPrice.vue | 325 +++++++-----------------------
 1 file changed, 70 insertions(+), 255 deletions(-)

diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 2ecd1f21b..41f2bac2f 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -1,7 +1,7 @@
 <script setup>
 import { onMounted, ref, reactive, computed, onUnmounted, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
-
+import { toDate } from 'src/filters';
 import FetchData from 'components/FetchData.vue';
 import FetchedTags from 'components/ui/FetchedTags.vue';
 import VnInput from 'src/components/common/VnInput.vue';
@@ -10,7 +10,7 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
 import EditTableCellValueForm from 'src/components/EditTableCellValueForm.vue';
 import ItemFixedPriceFilter from './ItemFixedPriceFilter.vue';
 import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
-
+import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { dashIfEmpty } from 'src/filters';
 import { useVnConfirm } from 'composables/useVnConfirm';
@@ -27,7 +27,7 @@ const { t } = useI18n();
 const { openConfirmationModal } = useVnConfirm();
 const state = useState();
 const { notify } = useNotify();
-
+const tableRef = ref();
 const editTableCellDialogRef = ref(null);
 const user = state.getUser();
 const fixedPrices = ref([]);
@@ -111,86 +111,81 @@ const defaultColumnAttrs = {
 const columns = computed(() => [
     {
         label: t('item.fixedPrice.itemId'),
-        name: 'itemId',
-        field: 'itemFk',
-        ...defaultColumnAttrs,
-        columnFilter: {
-            ...defaultColumnFilter,
+        name: 'itemFk',
+        align: 'left',
+        isId: true,
+        chip: {
+            condition: () => true,
         },
     },
     {
         label: t('globals.description'),
-        field: 'name',
         name: 'description',
-        ...defaultColumnAttrs,
-        columnFilter: {
-            ...defaultColumnFilter,
-        },
+        align: 'left',
+        create: true,
     },
     {
         label: t('item.fixedPrice.groupingPrice'),
-        field: 'rate2',
-        name: 'groupingPrice',
-        ...defaultColumnAttrs,
-        columnFilter: {
-            ...defaultColumnFilter,
-        },
-        format: (val) => toCurrency(val),
+        name: 'rate2',
+        align: 'left',
+        create: true,
     },
     {
         label: t('item.fixedPrice.packingPrice'),
-        field: 'rate3',
-        name: 'packingPrice',
-        ...defaultColumnAttrs,
-        columnFilter: {
-            ...defaultColumnFilter,
-        },
-        format: (val) => dashIfEmpty(val),
+        name: 'rate3',
+        align: 'left',
+        create: true,
     },
 
     {
         label: t('item.fixedPrice.minPrice'),
-        field: 'minPrice',
         name: 'minPrice',
-        ...defaultColumnAttrs,
-        columnFilter: {
-            ...defaultColumnFilter,
-        },
+        align: 'left',
+        create: true,
     },
     {
         label: t('item.fixedPrice.started'),
-        field: 'started',
         name: 'started',
-        ...defaultColumnAttrs,
-        columnFilter: null,
+        align: 'left',
+        create: true,
+        format: (row) => toDate(row.started),
     },
     {
         label: t('item.fixedPrice.ended'),
-        field: 'ended',
         name: 'ended',
-        ...defaultColumnAttrs,
-        columnFilter: null,
+        align: 'left',
+        create: true,
+        format: (row) => toDate(row.ended),
     },
-
     {
         label: t('item.fixedPrice.warehouse'),
-        field: 'warehouseFk',
-        name: 'warehouse',
-        ...defaultColumnAttrs,
+        name: 'warehouseFk',
         columnFilter: {
-            component: VnSelect,
-            type: 'select',
-            filterValue: null,
-            event: getColumnInputEvents,
+            component: 'select',
             attrs: {
-                options: warehousesOptions.value,
-                'option-value': 'id',
-                'option-label': 'name',
-                dense: true,
+                url: 'Warehouses',
+                optionValue: 'id',
+                optionLabel: 'name',
             },
         },
+        component: 'select',
+        attrs: {
+            url: 'Warehouses',
+            fields: ['id', 'name'],
+        },
+        disable: false,
+    },
+    {
+        align: 'right',
+        label: '',
+        name: 'tableActions',
+        actions: [
+            {
+                title: t('Delete'),
+                icon: 'delete',
+            },
+        ],
     },
-    { name: 'deleteAction', align: 'center' },
 ]);
 
 const editTableFieldsOptions = [
@@ -364,212 +359,32 @@ onUnmounted(() => (stateStore.rightDrawer = false));
 </script>
 
 <template>
-    <FetchData
-        url="Warehouses"
-        :filter="{ order: ['name'] }"
+    <VnTable
+        ref="tableRef"
+        data-key="ItemFixedPrices"
+        url="FixedPrices/filter"
+        :create="{
+            urlCreate: 'PriceFixed',
+            title: 'Create Item',
+            onDataSaved: () => tableRef.redirect(),
+            formInitialData: {},
+        }"
+        order="id ASC"
+        :columns="columns"
         auto-load
-        @on-fetch="(data) => onWarehousesFetched(data)"
-    />
-    <RightMenu>
-        <template #right-panel>
-            <ItemFixedPriceFilter
-                data-key="ItemFixedPrices"
-                :warehouses-options="warehousesOptions"
-            />
+        :is-editable="false"
+        :use-model="true"
+    >
+        <template #column-description="{ row }">
+            <div class="row column full-width justify-between items-start">
+                {{ row?.description }}
+                <div v-if="row?.description" class="subName">
+                    {{ row?.subName.toUpperCase() }}
+                </div>
+            </div>
+            <FetchedTags :item="row" :max-length="6" />
         </template>
-    </RightMenu>
-    <QPage class="column items-center q-pa-md">
-        <QTable
-            :rows="fixedPrices"
-            :columns="columns"
-            row-key="id"
-            selection="multiple"
-            v-model:selected="rowsSelected"
-            :pagination="{ rowsPerPage: 0 }"
-            class="full-width q-mt-md"
-            :no-data-label="t('globals.noResults')"
-        >
-            <template #top-row="{ cols }">
-                <QTr>
-                    <QTd />
-                    <QTd
-                        v-for="(col, index) in cols"
-                        :key="index"
-                        style="max-width: 100px"
-                    >
-                        <component
-                            :is="col.columnFilter.component"
-                            v-if="col.columnFilter"
-                            v-model="col.columnFilter.filterValue"
-                            v-bind="col.columnFilter.attrs"
-                            v-on="col.columnFilter.event(col)"
-                            dense
-                        />
-                    </QTd>
-                </QTr>
-            </template>
-
-            <template #body-cell-itemId="props">
-                <QTd>
-                    <VnSelect
-                        url="Items/withName"
-                        hide-selected
-                        option-label="id"
-                        option-value="id"
-                        v-model="props.row.itemFk"
-                        v-on="getRowUpdateInputEvents(props, true, 'select')"
-                    >
-                        <template #option="scope">
-                            <QItem v-bind="scope.itemProps">
-                                <QItemSection>
-                                    <QItemLabel> #{{ scope.opt?.id }} </QItemLabel>
-                                    <QItemLabel caption>{{ scope.opt?.name }}</QItemLabel>
-                                </QItemSection>
-                            </QItem>
-                        </template>
-                    </VnSelect>
-                </QTd>
-            </template>
-            <template #body-cell-description="{ row }">
-                <QTd class="col">
-                    <span class="link">
-                        {{ row.name }}
-                    </span>
-                    <ItemDescriptorProxy :id="row.itemFk" />
-                    <FetchedTags :item="row" :max-length="6" />
-                </QTd>
-            </template>
-            <template #body-cell-groupingPrice="props">
-                <QTd class="col">
-                    <VnInput
-                        v-model.number="props.row.rate2"
-                        v-on="getRowUpdateInputEvents(props)"
-                    >
-                        <template #append>€</template>
-                    </VnInput>
-                </QTd>
-            </template>
-            <template #body-cell-packingPrice="props">
-                <QTd class="col">
-                    <VnInput
-                        v-model.number="props.row.rate3"
-                        v-on="getRowUpdateInputEvents(props)"
-                    >
-                        <template #append>€</template>
-                    </VnInput>
-                </QTd>
-            </template>
-            <template #body-cell-minPrice="props">
-                <QTd class="col">
-                    <div class="row">
-                        <QCheckbox
-                            class="col"
-                            :model-value="props.row.hasMinPrice"
-                            @update:model-value="updateMinPrice($event, props)"
-                            :false-value="0"
-                            :true-value="1"
-                            :toggle-indeterminate="false"
-                        />
-                        <VnInput
-                            class="col"
-                            :disable="!props.row.hasMinPrice"
-                            v-model.number="props.row.minPrice"
-                            v-on="getRowUpdateInputEvents(props)"
-                            type="number"
-                        />
-                    </div>
-                </QTd>
-            </template>
-            <template #body-cell-started="props">
-                <QTd class="col" style="min-width: 160px">
-                    <VnInputDate
-                        v-model="props.row.started"
-                        v-on="getRowUpdateInputEvents(props, false, 'date')"
-                        v-bind="
-                            isBigger(props.row.started)
-                                ? { 'bg-color': 'warning', 'is-outlined': true }
-                                : {}
-                        "
-                    />
-                </QTd>
-            </template>
-            <template #body-cell-ended="props">
-                <QTd class="col" style="min-width: 150px">
-                    <VnInputDate
-                        v-model="props.row.ended"
-                        v-on="getRowUpdateInputEvents(props, false, 'date')"
-                        v-bind="
-                            isLower(props.row.ended)
-                                ? { 'bg-color': 'warning', 'is-outlined': true }
-                                : {}
-                        "
-                    />
-                </QTd>
-            </template>
-            <template #body-cell-warehouse="props">
-                <QTd class="col">
-                    <VnSelect
-                        :options="warehousesOptions"
-                        hide-selected
-                        option-label="name"
-                        option-value="id"
-                        v-model="props.row.warehouseFk"
-                        v-on="getRowUpdateInputEvents(props, false, 'select')"
-                    />
-                </QTd>
-            </template>
-            <template #body-cell-deleteAction="{ row, rowIndex }">
-                <QTd class="col">
-                    <QIcon
-                        name="delete"
-                        size="sm"
-                        class="cursor-pointer fill-icon-on-hover"
-                        color="primary"
-                        @click.stop="
-                            openConfirmationModal(
-                                t('This row will be removed'),
-                                t('Do you want to clone this item?'),
-                                () => removePrice(row.id, rowIndex)
-                            )
-                        "
-                    >
-                        <QTooltip class="text-no-wrap">
-                            {{ t('Delete') }}
-                        </QTooltip>
-                    </QIcon>
-                </QTd>
-            </template>
-            <template #bottom-row>
-                <QTd align="center">
-                    <QIcon
-                        @click.stop="addRow()"
-                        class="fill-icon-on-hover"
-                        color="primary"
-                        name="add_circle"
-                        size="sm"
-                    >
-                        <QTooltip>
-                            {{ t('Add fixed price') }}
-                        </QTooltip>
-                    </QIcon>
-                </QTd>
-            </template>
-        </QTable>
-        <QPageSticky v-if="rowsSelected.length" :offset="[20, 20]">
-            <QBtn @click="openEditTableCellDialog()" color="primary" fab icon="edit" />
-            <QTooltip>
-                {{ t('Edit fixed price(s)') }}
-            </QTooltip>
-        </QPageSticky>
-        <QDialog ref="editTableCellDialogRef">
-            <EditTableCellValueForm
-                edit-url="FixedPrices/editFixedPrice"
-                :rows="rowsSelected"
-                :fields-options="editTableFieldsOptions"
-                @on-data-saved="onEditCellDataSaved()"
-            />
-        </QDialog>
-    </QPage>
+    </VnTable>
 </template>
 
 <i18n>

From 6ca8ede946356c0d3b04cf57671e583f349f7f2b Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Wed, 7 Aug 2024 09:53:42 +0200
Subject: [PATCH 15/87] refs #7283 item request

---
 src/pages/Item/ItemRequest.vue  | 28 ++++++++--------------------
 src/pages/Item/ItemTypeList.vue |  3 +++
 2 files changed, 11 insertions(+), 20 deletions(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 0389ba864..8791a575f 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -33,8 +33,7 @@ watch(
 const columns = computed(() => [
     {
         label: t('item.buyRequest.ticketId'),
-        name: 'id',
-        field: 'id',
+        name: 'ticketFk',
         align: 'left',
         isId: true,
         chip: {
@@ -44,7 +43,6 @@ const columns = computed(() => [
     },
     {
         label: t('item.buyRequest.shipped'),
-        field: 'shipped',
         name: 'shipped',
         align: 'left',
         component: 'date',
@@ -61,57 +59,46 @@ const columns = computed(() => [
     },
     {
         label: t('item.buyRequest.requester'),
-        field: 'requesterName',
-        name: 'requesterFk',
+        name: 'requesterName',
         align: 'left',
     },
     {
         label: t('item.buyRequest.requested'),
-        field: 'quantity',
-        name: 'requested',
+        name: 'saleQuantity',
         align: 'left',
     },
     {
         label: t('item.buyRequest.price'),
-        field: 'price',
         name: 'price',
         align: 'left',
         format: (row) => toCurrency(row.price),
     },
     {
         label: t('item.buyRequest.attender'),
-        field: 'attender',
-        name: 'attender',
+        name: 'attenderName',
         align: 'left',
     },
     {
         label: t('item.buyRequest.item'),
-        field: 'item',
         name: 'item',
         align: 'left',
         component: 'input',
-        visible: false,
     },
     {
         label: t('item.buyRequest.achieved'),
-        field: 'achieved',
         name: 'achieved',
         align: 'left',
         component: 'input',
-        visible: false,
     },
     {
         label: t('item.buyRequest.concept'),
-        field: 'concept',
         name: 'concept',
         align: 'left',
         sortable: true,
         component: 'input',
-        visible: false,
     },
     {
         label: t('item.buyRequest.state'),
-        field: 'state',
         name: 'state',
         align: 'left',
     },
@@ -123,7 +110,7 @@ const columns = computed(() => [
             {
                 title: t('Client ticket list'),
                 icon: 'thumb_down',
-                action: onDenyAccept,
+                action: showDenyRequestForm,
                 isPrimary: true,
             },
         ],
@@ -348,14 +335,15 @@ onBeforeMount(() => {
     <VnTable
         ref="tableRef"
         data-key="itemRequest"
-        url="ticketRequests"
+        url="ticketRequests/filter"
         order="id DESC"
         :columns="columns"
+        :is-editable="false"
         auto-load
     >
         <template #column-attender="{ row }">
             <span class="link" @click.stop>
-                {{ row.attenderFk }}
+                {{ row }}
                 <WorkerDescriptorProxy :id="row.attenderFk" />
             </span>
         </template>
diff --git a/src/pages/Item/ItemTypeList.vue b/src/pages/Item/ItemTypeList.vue
index c02f9bb43..5ebbec62b 100644
--- a/src/pages/Item/ItemTypeList.vue
+++ b/src/pages/Item/ItemTypeList.vue
@@ -84,6 +84,7 @@ const columns = computed(() => [
             fields: ['id', 'firstName'],
         },
         cardVisible: true,
+        visible: false,
     },
     {
         align: 'left',
@@ -96,6 +97,7 @@ const columns = computed(() => [
             fields: ['id', 'name'],
         },
         cardVisible: true,
+        visible: false,
     },
     {
         align: 'left',
@@ -108,6 +110,7 @@ const columns = computed(() => [
             fields: ['id', 'name'],
         },
         cardVisible: true,
+        visible: false,
     },
 ]);
 </script>

From 589ee629cfbfc3c2b79c32ecef9ff47f30d33c00 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 13 Aug 2024 12:45:30 +0200
Subject: [PATCH 16/87] refs #7283 fix conflicts

---
 src/pages/Item/ItemFixedPrice.vue | 255 +++++++++---------------------
 src/pages/Item/ItemRequest.vue    |  15 +-
 2 files changed, 89 insertions(+), 181 deletions(-)

diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 41f2bac2f..56ad7a17d 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -2,25 +2,15 @@
 import { onMounted, ref, reactive, computed, onUnmounted, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { toDate } from 'src/filters';
-import FetchData from 'components/FetchData.vue';
 import FetchedTags from 'components/ui/FetchedTags.vue';
 import VnInput from 'src/components/common/VnInput.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
-import VnInputDate from 'src/components/common/VnInputDate.vue';
-import EditTableCellValueForm from 'src/components/EditTableCellValueForm.vue';
-import ItemFixedPriceFilter from './ItemFixedPriceFilter.vue';
-import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
-import { dashIfEmpty } from 'src/filters';
 import { useVnConfirm } from 'composables/useVnConfirm';
 import { useState } from 'src/composables/useState';
-import { toCurrency } from 'filters/index';
 import useNotify from 'src/composables/useNotify.js';
 import axios from 'axios';
 import { useArrayData } from 'composables/useArrayData';
-import { isLower, isBigger } from 'src/filters/date.js';
-import RightMenu from 'src/components/common/RightMenu.vue';
 
 const stateStore = useStateStore();
 const { t } = useI18n();
@@ -75,39 +65,6 @@ watch(
     (data) => onFixedPricesFetched(data)
 );
 
-const applyColumnFilter = async (col) => {
-    try {
-        const paramKey = col.columnFilter?.filterParamKey || col.field;
-        params[paramKey] = col.columnFilter.filterValue;
-        await arrayData.addFilter({ params });
-    } catch (err) {
-        console.error('Error applying column filter', err);
-    }
-};
-
-const getColumnInputEvents = (col) => {
-    return col.columnFilter.type === 'select'
-        ? { 'update:modelValue': () => applyColumnFilter(col) }
-        : {
-              'keyup.enter': () => applyColumnFilter(col),
-          };
-};
-
-const defaultColumnFilter = {
-    component: VnInput,
-    type: 'text',
-    filterValue: null,
-    event: getColumnInputEvents,
-    attrs: {
-        dense: true,
-    },
-};
-
-const defaultColumnAttrs = {
-    align: 'left',
-    sortable: true,
-};
-
 const columns = computed(() => [
     {
         label: t('item.fixedPrice.itemId'),
@@ -127,12 +84,14 @@ const columns = computed(() => [
     {
         label: t('item.fixedPrice.groupingPrice'),
         name: 'rate2',
+        component: 'input',
         align: 'left',
         create: true,
     },
     {
         label: t('item.fixedPrice.packingPrice'),
         name: 'rate3',
+        component: 'input',
         align: 'left',
         create: true,
     },
@@ -140,6 +99,7 @@ const columns = computed(() => [
     {
         label: t('item.fixedPrice.minPrice'),
         name: 'minPrice',
+        component: 'input',
         align: 'left',
         create: true,
     },
@@ -188,70 +148,14 @@ const columns = computed(() => [
     },
 ]);
 
-const editTableFieldsOptions = [
-    {
-        field: 'rate2',
-        label: t('item.fixedPrice.groupingPrice'),
-        component: 'input',
-        attrs: {
-            type: 'number',
-        },
-    },
-    {
-        field: 'rate3',
-        label: t('item.fixedPrice.packingPrice'),
-        component: 'input',
-        attrs: {
-            type: 'number',
-        },
-    },
-    {
-        field: 'minPrice',
-        label: t('item.fixedPrice.minPrice'),
-        component: 'input',
-        attrs: {
-            type: 'number',
-        },
-    },
-    {
-        field: 'hasMinPrice',
-        label: t('item.fixedPrice.hasMinPrice'),
-        component: 'checkbox',
-        attrs: {
-            'false-value': 0,
-            'true-value': 1,
-        },
-    },
-    {
-        field: 'started',
-        label: t('item.fixedPrice.started'),
-        component: 'date',
-    },
-    {
-        field: 'ended',
-        label: t('item.fixedPrice.ended'),
-        component: 'date',
-    },
-    {
-        field: 'warehouseFk',
-        label: t('item.fixedPrice.warehouse'),
-        component: 'select',
-        attrs: {
-            options: [],
-            'option-label': 'name',
-            'option-value': 'id',
-        },
-    },
-];
-
-const getRowUpdateInputEvents = (props, resetMinPrice, inputType = 'text') => {
-    return inputType === 'text'
-        ? {
-              'keyup.enter': () => upsertPrice(props, resetMinPrice),
-              blur: () => upsertPrice(props, resetMinPrice),
-          }
-        : { 'update:modelValue': () => upsertPrice(props, resetMinPrice) };
-};
+// const getRowUpdateInputEvents = (props, resetMinPrice, inputType = 'text') => {
+//     return inputType === 'text'
+//         ? {
+//               'keyup.enter': () => upsertPrice(props, resetMinPrice),
+//               blur: () => upsertPrice(props, resetMinPrice),
+//           }
+//         : { 'update:modelValue': () => upsertPrice(props, resetMinPrice) };
+// };
 
 const validations = (row, rowIndex, col) => {
     const isNew = !row.id;
@@ -281,81 +185,73 @@ const upsertPrice = async ({ row, col, rowIndex }, resetMinPrice = false) => {
     }
 };
 
-const addRow = () => {
-    if (!fixedPrices.value || fixedPrices.value.length === 0) {
-        fixedPrices.value = [];
+// const addRow = () => {
+//     if (!fixedPrices.value || fixedPrices.value.length === 0) {
+//         fixedPrices.value = [];
 
-        const today = Date.vnNew();
-        const millisecsInDay = 86400000;
-        const daysInWeek = 7;
-        const nextWeek = new Date(today.getTime() + daysInWeek * millisecsInDay);
+//         const today = Date.vnNew();
+//         const millisecsInDay = 86400000;
+//         const daysInWeek = 7;
+//         const nextWeek = new Date(today.getTime() + daysInWeek * millisecsInDay);
 
-        const newPrice = {
-            started: today,
-            ended: nextWeek,
-            hasMinPrice: 0,
-        };
+//         const newPrice = {
+//             started: today,
+//             ended: nextWeek,
+//             hasMinPrice: 0,
+//         };
 
-        fixedPricesOriginalData.value.push({ ...newPrice });
-        fixedPrices.value.push({ ...newPrice });
-        return;
-    }
+//         fixedPricesOriginalData.value.push({ ...newPrice });
+//         fixedPrices.value.push({ ...newPrice });
+//         return;
+//     }
 
-    const lastItemCopy = JSON.parse(
-        JSON.stringify(fixedPrices.value[fixedPrices.value.length - 1])
-    );
-    delete lastItemCopy.id;
-    fixedPricesOriginalData.value.push(lastItemCopy);
-    fixedPrices.value.push(lastItemCopy);
-};
+//     const lastItemCopy = JSON.parse(
+//         JSON.stringify(fixedPrices.value[fixedPrices.value.length - 1])
+//     );
+//     delete lastItemCopy.id;
+//     fixedPricesOriginalData.value.push(lastItemCopy);
+//     fixedPrices.value.push(lastItemCopy);
+// };
 
-const openEditTableCellDialog = () => {
-    editTableCellDialogRef.value.show();
-};
+// const openEditTableCellDialog = () => {
+//     editTableCellDialogRef.value.show();
+// };
 
-const onEditCellDataSaved = async () => {
-    rowsSelected.value = [];
-    await fetchFixedPrices();
-};
+// const onEditCellDataSaved = async () => {
+//     rowsSelected.value = [];
+//     await fetchFixedPrices();
+// };
 
-const onWarehousesFetched = (data) => {
-    warehousesOptions.value = data;
-    // Actualiza las 'options' del elemento con field 'warehouseFk' en 'editTableFieldsOptions'.
-    const warehouseField = editTableFieldsOptions.find(
-        (field) => field.field === 'warehouseFk'
-    );
-    warehouseField.attrs.options = data;
-};
+// const onWarehousesFetched = (data) => {
+//     warehousesOptions.value = data;
+//     // Actualiza las 'options' del elemento con field 'warehouseFk' en 'editTableFieldsOptions'.
+//     const warehouseField = editTableFieldsOptions.find(
+//         (field) => field.field === 'warehouseFk'
+//     );
+//     warehouseField.attrs.options = data;
+// };
 
-const removePrice = async (id, rowIndex) => {
-    try {
-        await axios.delete(`FixedPrices/${id}`);
-        fixedPrices.value.splice(rowIndex, 1);
-        fixedPricesOriginalData.value.splice(rowIndex, 1);
-        notify(t('globals.dataSaved'), 'positive');
-    } catch (err) {
-        console.error('Error removing price', err);
-    }
-};
+// const removePrice = async (id, rowIndex) => {
+//     try {
+//         await axios.delete(`FixedPrices/${id}`);
+//         fixedPrices.value.splice(rowIndex, 1);
+//         fixedPricesOriginalData.value.splice(rowIndex, 1);
+//         notify(t('globals.dataSaved'), 'positive');
+//     } catch (err) {
+//         console.error('Error removing price', err);
+//     }
+// };
 
-const updateMinPrice = async (value, props) => {
-    // El checkbox hasMinPrice se encuentra en la misma columna que el input hasMinPrice
-    // Por lo tanto le mandamos otro objeto con las mismas propiedades pero con el campo 'field' cambiado
-    props.row.hasMinPrice = value;
-    await upsertPrice({
-        row: props.row,
-        col: { field: 'hasMinPrice' },
-        rowIndex: props.rowIndex,
-    });
-};
-
-onMounted(async () => {
-    stateStore.rightDrawer = true;
-    params.warehouseFk = user.value.warehouseFk;
-    await fetchFixedPrices();
-});
-
-onUnmounted(() => (stateStore.rightDrawer = false));
+// const updateMinPrice = async (value, props) => {
+//     // El checkbox hasMinPrice se encuentra en la misma columna que el input hasMinPrice
+//     // Por lo tanto le mandamos otro objeto con las mismas propiedades pero con el campo 'field' cambiado
+//     props.row.hasMinPrice = value;
+//     await upsertPrice({
+//         row: props.row,
+//         col: { field: 'hasMinPrice' },
+//         rowIndex: props.rowIndex,
+//     });
+// };
 </script>
 
 <template>
@@ -372,13 +268,13 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         order="id ASC"
         :columns="columns"
         auto-load
-        :is-editable="false"
+        :is-editable="true"
         :use-model="true"
     >
         <template #column-description="{ row }">
             <div class="row column full-width justify-between items-start">
-                {{ row?.description }}
-                <div v-if="row?.description" class="subName">
+                {{ row?.name }}
+                <div v-if="row?.subName" class="subName">
                     {{ row?.subName.toUpperCase() }}
                 </div>
             </div>
@@ -386,7 +282,12 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         </template>
     </VnTable>
 </template>
-
+<style lang="scss" scoped>
+.subName {
+    text-transform: uppercase;
+    color: var(--vn-label-color);
+}
+</style>
 <i18n>
 es:
     Add fixed price: Añadir precio fijado
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 8791a575f..f67f7eda2 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -100,6 +100,7 @@ const columns = computed(() => [
     {
         label: t('item.buyRequest.state'),
         name: 'state',
+        action: (row) => getState(row.isOk),
         align: 'left',
     },
     {
@@ -146,7 +147,6 @@ const confirmRequest = async (request) => {
                 `TicketRequests/${request.id}/confirm`,
                 params
             );
-
             request.itemDescription = data.concept;
             request.isOk = true;
             notify(t('globals.dataSaved'), 'positive');
@@ -338,15 +338,22 @@ onBeforeMount(() => {
         url="ticketRequests/filter"
         order="id DESC"
         :columns="columns"
-        :is-editable="false"
+        :is-editable="true"
         auto-load
     >
-        <template #column-attender="{ row }">
+        <template #column-attenderName="{ row }">
             <span class="link" @click.stop>
-                {{ row }}
+                {{ row.attenderName }}
                 <WorkerDescriptorProxy :id="row.attenderFk" />
             </span>
         </template>
+
+        <template #column-requesterName="{ row }">
+            <span class="link" @click.stop>
+                {{ row.requesterName }}
+                <WorkerDescriptorProxy :id="row.requesterFk" />
+            </span>
+        </template>
     </VnTable>
 </template>
 

From 1df089cef78e6728c764d7d72cc015b573f44f66 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Wed, 14 Aug 2024 15:50:13 +0200
Subject: [PATCH 17/87] refs #7283 fix itemFixedPrice

---
 src/pages/Item/ItemFixedPrice.vue | 65 ++++++++++++++++++++++++-------
 1 file changed, 51 insertions(+), 14 deletions(-)

diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 56ad7a17d..30eb8544e 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -1,9 +1,10 @@
 <script setup>
-import { onMounted, ref, reactive, computed, onUnmounted, watch } from 'vue';
+import { ref, reactive, computed, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { toDate } from 'src/filters';
+import { useQuasar } from 'quasar';
 import FetchedTags from 'components/ui/FetchedTags.vue';
-import VnInput from 'src/components/common/VnInput.vue';
+import { useRoute } from 'vue-router';
 import VnTable from 'components/VnTable/VnTable.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { useVnConfirm } from 'composables/useVnConfirm';
@@ -11,20 +12,30 @@ import { useState } from 'src/composables/useState';
 import useNotify from 'src/composables/useNotify.js';
 import axios from 'axios';
 import { useArrayData } from 'composables/useArrayData';
+import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
+import VnConfirm from 'components/ui/VnConfirm.vue';
 
-const stateStore = useStateStore();
+const route = useRoute();
 const { t } = useI18n();
 const { openConfirmationModal } = useVnConfirm();
 const state = useState();
 const { notify } = useNotify();
 const tableRef = ref();
-const editTableCellDialogRef = ref(null);
+const quasar = useQuasar();
 const user = state.getUser();
 const fixedPrices = ref([]);
 const fixedPricesOriginalData = ref([]);
 const warehousesOptions = ref([]);
 const rowsSelected = ref([]);
 
+// function localUserData() {
+//     state.setUser(user.value);
+// }
+
+// const userLocal = localUserData();
+// console.log('localUserData', userLocal);
+
+console.log('user', user.value.warehouseFk);
 const exprBuilder = (param, value) => {
     switch (param) {
         case 'name':
@@ -80,6 +91,10 @@ const columns = computed(() => [
         name: 'description',
         align: 'left',
         create: true,
+        columnCreate: {
+            component: 'select',
+            url: 'Items',
+        },
     },
     {
         label: t('item.fixedPrice.groupingPrice'),
@@ -109,6 +124,9 @@ const columns = computed(() => [
         align: 'left',
         create: true,
         format: (row) => toDate(row.started),
+        columnCreate: {
+            component: 'date',
+        },
     },
     {
         label: t('item.fixedPrice.ended'),
@@ -116,6 +134,9 @@ const columns = computed(() => [
         align: 'left',
         create: true,
         format: (row) => toDate(row.ended),
+        columnCreate: {
+            component: 'date',
+        },
     },
     {
         label: t('item.fixedPrice.warehouse'),
@@ -148,6 +169,27 @@ const columns = computed(() => [
     },
 ]);
 
+function confirmRemove(row) {
+    quasar.dialog({
+        component: VnConfirm,
+        componentProps: {
+            title: t('confirmDeletion'),
+            message: t('confirmDeletionMessage'),
+            promise: () => remove(row),
+        },
+    });
+}
+
+async function remove(item) {
+    await axios.post('FixedPrices/filter', {
+        rows: [item.id],
+    });
+    quasar.notify({
+        message: t('globals.dataDeleted'),
+        type: 'positive',
+    });
+    tableRef.value.reload();
+}
 // const getRowUpdateInputEvents = (props, resetMinPrice, inputType = 'text') => {
 //     return inputType === 'text'
 //         ? {
@@ -213,15 +255,6 @@ const upsertPrice = async ({ row, col, rowIndex }, resetMinPrice = false) => {
 //     fixedPrices.value.push(lastItemCopy);
 // };
 
-// const openEditTableCellDialog = () => {
-//     editTableCellDialogRef.value.show();
-// };
-
-// const onEditCellDataSaved = async () => {
-//     rowsSelected.value = [];
-//     await fetchFixedPrices();
-// };
-
 // const onWarehousesFetched = (data) => {
 //     warehousesOptions.value = data;
 //     // Actualiza las 'options' del elemento con field 'warehouseFk' en 'editTableFieldsOptions'.
@@ -259,6 +292,7 @@ const upsertPrice = async ({ row, col, rowIndex }, resetMinPrice = false) => {
         ref="tableRef"
         data-key="ItemFixedPrices"
         url="FixedPrices/filter"
+        :filter="{ where: { warehouseFk: user.warehouseFk } }"
         :create="{
             urlCreate: 'PriceFixed',
             title: 'Create Item',
@@ -273,7 +307,10 @@ const upsertPrice = async ({ row, col, rowIndex }, resetMinPrice = false) => {
     >
         <template #column-description="{ row }">
             <div class="row column full-width justify-between items-start">
-                {{ row?.name }}
+                <span class="link" @click.stop>
+                    {{ row?.name }}
+                    <ItemDescriptorProxy class="link" :id="row.itemFk" />
+                </span>
                 <div v-if="row?.subName" class="subName">
                     {{ row?.subName.toUpperCase() }}
                 </div>

From 12a5d6cec035b72deaa3c9f316d0f329d5411081 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Mon, 19 Aug 2024 17:05:00 +0200
Subject: [PATCH 18/87] fix: refs #7283 css

---
 src/components/VnTable/VnTable.vue | 7 ++++---
 src/pages/Item/ItemRequest.vue     | 1 +
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 6c77d44df..69c4739bf 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -486,11 +486,12 @@ defineExpose({
                                 :icon="btn.icon"
                                 class="q-px-sm"
                                 flat
-                                :class="
+                                :class="[
                                     btn.isPrimary
                                         ? 'text-primary-light'
-                                        : 'color-vn-text '
-                                "
+                                        : 'color-vn-text ',
+                                    btn.class,
+                                ]"
                                 :style="`visibility: ${
                                     (btn.show && btn.show(row)) ?? true
                                         ? 'visible'
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index f67f7eda2..65c0aaae1 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -111,6 +111,7 @@ const columns = computed(() => [
             {
                 title: t('Client ticket list'),
                 icon: 'thumb_down',
+                class: 'fill-icon',
                 action: showDenyRequestForm,
                 isPrimary: true,
             },

From bae0b4de351f43a65de5b6ef05fbdaa9cd525d7c Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Thu, 22 Aug 2024 10:38:15 +0200
Subject: [PATCH 19/87] fix: itemBotanical

---
 src/pages/Item/Card/ItemBotanical.vue | 35 +++++++++++++--------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/src/pages/Item/Card/ItemBotanical.vue b/src/pages/Item/Card/ItemBotanical.vue
index 416c7f78b..88d251c47 100644
--- a/src/pages/Item/Card/ItemBotanical.vue
+++ b/src/pages/Item/Card/ItemBotanical.vue
@@ -13,7 +13,6 @@ import CreateSpecieForm from './CreateSpecieForm.vue';
 const route = useRoute();
 const { t } = useI18n();
 
-const itemBotanicalsRef = ref(null);
 const itemGenusOptions = ref([]);
 const itemSpeciesOptions = ref([]);
 const itemBotanicals = ref([]);
@@ -31,22 +30,19 @@ const onSpecieCreated = (response, formData) => {
 const entityId = computed(() => {
     return route.params.id;
 });
-onMounted(async () => {
-    itemBotanicalsForm.itemFk = entityId.value;
-    itemBotanicals.value = await itemBotanicalsRef.value.fetch();
-    if (itemBotanicals.value.length > 0)
-        Object.assign(itemBotanicalsForm, itemBotanicals.value[0]);
-});
+// onMounted(async () => {
+//     itemBotanicalsForm.itemFk = entityId.value;
+//     // itemBotanicals.value = await itemBotanicalsRef.value.fetch();
+//     if (itemBotanicals.value.length > 0)
+//         Object.assign(itemBotanicalsForm, itemBotanicals.value[0]);
+// });
+async function handleItemBotanical(data) {
+    itemBotanicalsForm = data;
+    // if (data.length > 0) Object.assign(itemBotanicalsForm, itemBotanicals.value[0]);
+}
 </script>
 <template>
-    <FetchData
-        ref="itemBotanicalsRef"
-        url="ItemBotanicals"
-        :filter="{
-            where: { itemFk: entityId },
-        }"
-        @on-fetch="(data) => (itemBotanicals = data)"
-    />
+    <!-- <FetchData ref="itemBotanicalsRef" @on-fetch="(data) => (itemBotanicals = data)" /> -->
     <FetchData
         url="Genera"
         :filter="{ fields: ['id', 'name'], order: 'name ASC' }"
@@ -60,11 +56,14 @@ onMounted(async () => {
         auto-load
     />
     <FormModel
+        url="ItemBotanicals"
         url-update="ItemBotanicals"
-        model="entry"
+        model="item"
         auto-load
-        :form-initial-data="itemBotanicalsForm"
-        :clear-store-on-unmount="false"
+        :filter="{
+            where: { itemFk: entityId },
+        }"
+        @on-fetch="handleItemBotanical"
     >
         <template #form="{ data }">
             <VnRow>

From 2ef56f9f9730c0cbc8c287531ad12363a9f4c447 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 27 Aug 2024 08:00:07 +0200
Subject: [PATCH 20/87] refs #7283 fixedPrice

---
 src/pages/Item/ItemFixedPrice.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 30eb8544e..05a8545c8 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -292,6 +292,7 @@ const upsertPrice = async ({ row, col, rowIndex }, resetMinPrice = false) => {
         ref="tableRef"
         data-key="ItemFixedPrices"
         url="FixedPrices/filter"
+        save-url="FixedPrices/crud"
         :filter="{ where: { warehouseFk: user.warehouseFk } }"
         :create="{
             urlCreate: 'PriceFixed',

From 6de59c64194c4aec32294575a531dda73d5d8b0d Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 27 Aug 2024 14:39:21 +0200
Subject: [PATCH 21/87] refs #7283 itemRequestFixed

---
 src/pages/Item/ItemFixedPrice.vue |  1 +
 src/pages/Item/ItemList.vue       |  2 ++
 src/pages/Item/ItemRequest.vue    | 31 +++++++++++++++++++++++++++----
 3 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 05a8545c8..7ba4984e7 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -164,6 +164,7 @@ const columns = computed(() => [
             {
                 title: t('Delete'),
                 icon: 'delete',
+                isPrimary: true,
             },
         ],
     },
diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index a3b70372f..2f3d20390 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -226,11 +226,13 @@ const columns = computed(() => [
                 title: t('Clone item'),
                 icon: 'vn:clone',
                 action: cloneItem,
+                isPrimary: true,
             },
             {
                 title: t('view Summary'),
                 icon: 'preview',
                 action: (row) => viewSummary(row.id, ItemSummary),
+                isPrimary: true,
             },
         ],
     },
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 65c0aaae1..0d641f8e2 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -9,7 +9,8 @@ import useNotify from 'src/composables/useNotify.js';
 import axios from 'axios';
 import { toDate } from 'src/filters';
 import VnTable from 'components/VnTable/VnTable.vue';
-
+import VnInput from 'src/components/common/VnInput.vue';
+import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 const { t } = useI18n();
 const { notify } = useNotify();
 const stateStore = useStateStore();
@@ -64,7 +65,7 @@ const columns = computed(() => [
     },
     {
         label: t('item.buyRequest.requested'),
-        name: 'saleQuantity',
+        name: 'quantity',
         align: 'left',
     },
     {
@@ -100,7 +101,7 @@ const columns = computed(() => [
     {
         label: t('item.buyRequest.state'),
         name: 'state',
-        action: (row) => getState(row.isOk),
+        format: (row) => getState(row.isOk),
         align: 'left',
     },
     {
@@ -333,11 +334,12 @@ onBeforeMount(() => {
             />
         </QDialog>
     </QPage> -->
+    <VnSubToolbar />
     <VnTable
         ref="tableRef"
         data-key="itemRequest"
         url="ticketRequests/filter"
-        order="id DESC"
+        order="shippedDate ASC, isOk ASC"
         :columns="columns"
         :is-editable="true"
         auto-load
@@ -355,6 +357,27 @@ onBeforeMount(() => {
                 <WorkerDescriptorProxy :id="row.requesterFk" />
             </span>
         </template>
+
+        <template #column-item="{ row }">
+            <span @click.stop disabled="row.isOk != null">
+                <VnInput type="number" v-model="row.item" fill-input />
+            </span>
+        </template>
+        <template #column-achieved="{ row }">
+            <span @click.stop disabled="!request.itemFk || request.isOk != null">
+                <VnInput
+                    type="number"
+                    v-model="row.achieved"
+                    fill-input
+                    @keyup.enter="changeQuantity(row)"
+                />
+            </span>
+        </template>
+        <template #column-concept="{ row }">
+            <span @click.stop disabled="row.isOk != null">
+                {{ row.itemDescription }}
+            </span>
+        </template>
     </VnTable>
 </template>
 

From cd1b5f56f711ad8a0b0c3141c085f03897f36f8c Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Wed, 28 Aug 2024 11:35:57 +0200
Subject: [PATCH 22/87] refs #7283 column-action

---
 src/pages/Item/ItemRequest.vue | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 0d641f8e2..41248afbb 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -110,7 +110,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('Client ticket list'),
+                title: t('Deny Request'),
                 icon: 'thumb_down',
                 class: 'fill-icon',
                 action: showDenyRequestForm,
@@ -378,6 +378,32 @@ onBeforeMount(() => {
                 {{ row.itemDescription }}
             </span>
         </template>
+        <template #column-action="{ row, rowIndex }">
+            <QTd>
+                <QIcon
+                    v-if="row.response?.length"
+                    name="insert_drive_file"
+                    color="primary"
+                    size="sm"
+                >
+                    <QTooltip>
+                        {{ row.response }}
+                    </QTooltip>
+                </QIcon>
+                <QIcon
+                    v-if="row.isOk == null"
+                    name="thumb_down"
+                    color="primary"
+                    size="sm"
+                    class="fill-icon"
+                    @click="showDenyRequestForm(row.id, rowIndex)"
+                >
+                    <QTooltip>
+                        {{ t('Discard') }}
+                    </QTooltip>
+                </QIcon>
+            </QTd>
+        </template>
     </VnTable>
 </template>
 

From e4aec1773b74c002913bf60f807c07ca39a873f5 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 29 Aug 2024 12:38:57 +0200
Subject: [PATCH 23/87] refs #7283 itemRequest fix deny

---
 src/pages/Item/ItemRequest.vue | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 41248afbb..0e59a16c4 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -7,6 +7,7 @@ import { useArrayData } from 'composables/useArrayData';
 import { toCurrency } from 'filters/index';
 import useNotify from 'src/composables/useNotify.js';
 import axios from 'axios';
+import ItemRequestDenyForm from './ItemRequestDenyForm.vue';
 import { toDate } from 'src/filters';
 import VnTable from 'components/VnTable/VnTable.vue';
 import VnInput from 'src/components/common/VnInput.vue';
@@ -26,6 +27,10 @@ const arrayData = useArrayData('ItemRequests', {
 });
 const store = arrayData.store;
 
+const userParams = {
+    state: 'pending',
+};
+
 watch(
     () => store.data,
     (value) => (itemRequestsOptions.value = value)
@@ -174,7 +179,9 @@ const onDenyAccept = (_, responseData) => {
     itemRequestsOptions.value[denyRequestIndex.value].isOk = responseData.isOk;
     itemRequestsOptions.value[denyRequestIndex.value].attenderFk =
         responseData.attenderFk;
+    console.log('itemRequestsOptions: ', itemRequestsOptions.value);
     itemRequestsOptions.value[denyRequestIndex.value].response = responseData.response;
+    console.log('itemRequestsOptions.value', itemRequestsOptions.value);
     denyRequestId.value = null;
     denyRequestIndex.value = null;
 };
@@ -341,8 +348,10 @@ onBeforeMount(() => {
         url="ticketRequests/filter"
         order="shippedDate ASC, isOk ASC"
         :columns="columns"
+        :user-params="userParams"
         :is-editable="true"
         auto-load
+        :disable-option="{ card: true }"
     >
         <template #column-attenderName="{ row }">
             <span class="link" @click.stop>
@@ -378,7 +387,7 @@ onBeforeMount(() => {
                 {{ row.itemDescription }}
             </span>
         </template>
-        <template #column-action="{ row, rowIndex }">
+        <template #column-tableActions="{ row, rowIndex }">
             <QTd>
                 <QIcon
                     v-if="row.response?.length"
@@ -405,6 +414,9 @@ onBeforeMount(() => {
             </QTd>
         </template>
     </VnTable>
+    <QDialog ref="denyFormRef" transition-show="scale" transition-hide="scale">
+        <ItemRequestDenyForm :request-id="denyRequestId" @on-data-saved="onDenyAccept" />
+    </QDialog>
 </template>
 
 <i18n>

From 388036a2eb589b6475132e630ee555147938b4a6 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 2 Sep 2024 09:19:49 +0200
Subject: [PATCH 24/87] refs #7283 itemRequest fix

---
 src/pages/Item/ItemRequest.vue | 146 ++-------------------------------
 1 file changed, 7 insertions(+), 139 deletions(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 0e59a16c4..10ed237b4 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -208,140 +208,6 @@ onBeforeMount(() => {
 </script>
 
 <template>
-    <!-- <FetchData
-        url="Workers"
-        :filter="{ where: { role: 'buyer' } }"
-        order="id"
-        @on-fetch="(data) => (workersOptions = data)"
-        auto-load
-    />
-    <VnSearchbar
-        data-key="ItemRequests"
-        url="TicketRequests/filter"
-        :label="t('globals.search')"
-        :info="t('You can search by Id or alias')"
-        :redirect="false"
-    />
-    <RightMenu>
-        <template #right-panel>
-            <ItemRequestFilter data-key="ItemRequests" />
-        </template>
-    </RightMenu>
-    <QPage class="column items-center q-pa-md">
-        <QTable
-            :rows="itemRequestsOptions"
-            :columns="columns"
-            row-key="id"
-            :pagination="{ rowsPerPage: 0 }"
-            class="full-width q-mt-md"
-            :no-data-label="t('globals.noResults')"
-        >
-            <template #body-cell-id="{ row }">
-                <QTd>
-                    <QBtn flat color="primary"> {{ row.ticketFk }}</QBtn>
-                    <TicketDescriptorProxy :id="row.ticketFk" />
-                </QTd>
-            </template>
-            <template #body-cell-shipped="{ row }">
-                <QTd>
-                    <QBadge
-                        v-if="getDateQBadgeColor(row.shipped)"
-                        :color="getDateQBadgeColor(row.shipped)"
-                        text-color="black"
-                        class="q-ma-none"
-                        dense
-                        style="font-size: 14px"
-                    >
-                        {{ toDateFormat(row.shipped) }}
-                    </QBadge>
-                    <span v-else>{{ toDateFormat(row.shipped) }}</span>
-                </QTd>
-            </template>
-            <template #body-cell-requester="{ row }">
-                <QTd>
-                    <QBtn flat dense color="primary"> {{ row.requesterName }}</QBtn>
-                    <WorkerDescriptorProxy :id="row.requesterFk" />
-                </QTd>
-            </template>
-            <template #body-cell-attender="{ row }">
-                <QTd>
-                    <VnSelect
-                        v-model="row.attenderFk"
-                        :options="workersOptions"
-                        hide-selected
-                        option-label="firstName"
-                        option-value="id"
-                        dense
-                    />
-                </QTd>
-            </template>
-            <template #body-cell-item="{ row }">
-                <QTd>
-                    <VnInput
-                        v-model.number="row.itemFk"
-                        type="number"
-                        :disable="row.isOk != null"
-                        dense
-                    />
-                </QTd>
-            </template>
-            <template #body-cell-achieved="{ row }">
-                <QTd>
-                    <VnInput
-                        v-model.number="row.saleQuantity"
-                        @blur="changeQuantity(row)"
-                        type="number"
-                        :disable="!row.itemFk || row.isOk != null"
-                        dense
-                    />
-                </QTd>
-            </template>
-            <template #body-cell-concept="{ row }">
-                <QTd>
-                    <QBtn flat dense color="primary"> {{ row.itemDescription }}</QBtn>
-                    <ItemDescriptorProxy :id="row.itemFk" />
-                </QTd>
-            </template>
-            <template #body-cell-state="{ row }">
-                <QTd>
-                    <span>{{ getState(row.isOk) }}</span>
-                </QTd>
-            </template>
-            <template #body-cell-action="{ row, rowIndex }">
-                <QTd>
-                    <QIcon
-                        v-if="row.response?.length"
-                        name="insert_drive_file"
-                        color="primary"
-                        size="sm"
-                    >
-                        <QTooltip>
-                            {{ row.response }}
-                        </QTooltip>
-                    </QIcon>
-                    <QIcon
-                        v-if="row.isOk == null"
-                        name="thumb_down"
-                        color="primary"
-                        size="sm"
-                        class="fill-icon"
-                        @click="showDenyRequestForm(row.id, rowIndex)"
-                    >
-                        <QTooltip>
-                            {{ t('Discard') }}
-                        </QTooltip>
-                    </QIcon>
-                </QTd>
-            </template>
-        </QTable>
-        <QDialog ref="denyFormRef" transition-show="scale" transition-hide="scale">
-            <ItemRequestDenyForm
-                :request-id="denyRequestId"
-                @on-data-saved="onDenyAccept"
-            />
-        </QDialog>
-    </QPage> -->
-    <VnSubToolbar />
     <VnTable
         ref="tableRef"
         data-key="itemRequest"
@@ -368,17 +234,19 @@ onBeforeMount(() => {
         </template>
 
         <template #column-item="{ row }">
-            <span @click.stop disabled="row.isOk != null">
-                <VnInput type="number" v-model="row.item" fill-input />
+            <span>
+                <VnInput v-model.number="row.itemFk" dense />
             </span>
         </template>
         <template #column-achieved="{ row }">
-            <span @click.stop disabled="!request.itemFk || request.isOk != null">
+            <span>
                 <VnInput
                     type="number"
-                    v-model="row.achieved"
-                    fill-input
+                    v-model.number="row.saleQuantity"
+                    :disable="!row.itemFk || row.isOk != null"
+                    @blur="changeQuantity(row)"
                     @keyup.enter="changeQuantity(row)"
+                    dense
                 />
             </span>
         </template>

From 3bf3e8eeaa4c93dd2c8a737d5a95fb0528abbe50 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 2 Sep 2024 11:08:50 +0200
Subject: [PATCH 25/87] refs #7283 itemRequest fix deny

---
 src/pages/Item/ItemRequest.vue | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 10ed237b4..8273c5c91 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -112,16 +112,7 @@ const columns = computed(() => [
     {
         align: 'right',
         label: '',
-        name: 'tableActions',
-        actions: [
-            {
-                title: t('Deny Request'),
-                icon: 'thumb_down',
-                class: 'fill-icon',
-                action: showDenyRequestForm,
-                isPrimary: true,
-            },
-        ],
+        name: 'denyOptions',
     },
 ]);
 
@@ -171,7 +162,9 @@ const getState = (isOk) => {
 
 const showDenyRequestForm = (requestId, rowIndex) => {
     denyRequestId.value = requestId;
+    console.log('denyRequestId.value: ', denyRequestId.value);
     denyRequestIndex.value = rowIndex;
+    console.log('denyRequestIndex.value: ', denyRequestIndex.value);
     denyFormRef.value.show();
 };
 
@@ -255,8 +248,8 @@ onBeforeMount(() => {
                 {{ row.itemDescription }}
             </span>
         </template>
-        <template #column-tableActions="{ row, rowIndex }">
-            <QTd>
+        <template #column-denyOptions="{ row, rowIndex }">
+            <QTd class="sticky no-padding">
                 <QIcon
                     v-if="row.response?.length"
                     name="insert_drive_file"

From 488dc74c1f07c9314dc14618765c7250191ae72d Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 2 Sep 2024 12:14:23 +0200
Subject: [PATCH 26/87] refs #7283 itemRequest fix reload

---
 src/pages/Item/ItemRequest.vue | 24 +++---------------------
 1 file changed, 3 insertions(+), 21 deletions(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 8273c5c91..4062f8538 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, computed, onMounted, onBeforeMount, watch } from 'vue';
+import { ref, computed, onMounted, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 import { useStateStore } from 'stores/useStateStore';
@@ -11,7 +11,6 @@ import ItemRequestDenyForm from './ItemRequestDenyForm.vue';
 import { toDate } from 'src/filters';
 import VnTable from 'components/VnTable/VnTable.vue';
 import VnInput from 'src/components/common/VnInput.vue';
-import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 const { t } = useI18n();
 const { notify } = useNotify();
 const stateStore = useStateStore();
@@ -31,6 +30,7 @@ const userParams = {
     state: 'pending',
 };
 
+const tableRef = ref();
 watch(
     () => store.data,
     (value) => (itemRequestsOptions.value = value)
@@ -162,9 +162,7 @@ const getState = (isOk) => {
 
 const showDenyRequestForm = (requestId, rowIndex) => {
     denyRequestId.value = requestId;
-    console.log('denyRequestId.value: ', denyRequestId.value);
     denyRequestIndex.value = rowIndex;
-    console.log('denyRequestIndex.value: ', denyRequestIndex.value);
     denyFormRef.value.show();
 };
 
@@ -172,32 +170,16 @@ const onDenyAccept = (_, responseData) => {
     itemRequestsOptions.value[denyRequestIndex.value].isOk = responseData.isOk;
     itemRequestsOptions.value[denyRequestIndex.value].attenderFk =
         responseData.attenderFk;
-    console.log('itemRequestsOptions: ', itemRequestsOptions.value);
     itemRequestsOptions.value[denyRequestIndex.value].response = responseData.response;
-    console.log('itemRequestsOptions.value', itemRequestsOptions.value);
     denyRequestId.value = null;
     denyRequestIndex.value = null;
+    tableRef.value.reload();
 };
 
 onMounted(async () => {
     await arrayData.fetch({ append: false });
     stateStore.rightDrawer = true;
 });
-
-onBeforeMount(() => {
-    const today = Date.vnNew();
-    today.setHours(0, 0, 0, 0);
-
-    const nextWeek = Date.vnNew();
-    nextWeek.setHours(23, 59, 59, 59);
-    nextWeek.setDate(nextWeek.getDate() + 7);
-
-    filterParams.value = {
-        from: today,
-        to: nextWeek,
-        state: 'pending',
-    };
-});
 </script>
 
 <template>

From 04c8481b51e70f3062d7d0a997bdab2fece7c98a Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 12 Sep 2024 07:43:12 +0200
Subject: [PATCH 27/87] refs #7283 fix itemFixed

---
 src/pages/Item/ItemFixedPrice.vue | 28 +++++++++++++---------------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 29b886e25..d91b5189e 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -1,6 +1,5 @@
 <script setup>
 import { onMounted, ref, reactive, onUnmounted, nextTick, computed } from 'vue';
-import { ref, reactive, computed, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import FetchedTags from 'components/ui/FetchedTags.vue';
@@ -27,15 +26,12 @@ import { QCheckbox } from 'quasar';
 
 const quasar = useQuasar();
 const stateStore = useStateStore();
-const route = useRoute();
 const { t } = useI18n();
 const { openConfirmationModal } = useVnConfirm();
 const state = useState();
 const { notify } = useNotify();
 const tableRef = ref();
 const editTableCellDialogRef = ref(null);
-const tableRef = ref();
-const quasar = useQuasar();
 const user = state.getUser();
 const fixedPrices = ref([]);
 const warehousesOptions = ref([]);
@@ -129,6 +125,7 @@ const columns = computed(() => [
     },
     {
         label: t('item.fixedPrice.started'),
+        field: 'started',
         name: 'started',
         format: ({ started }) => toDate(started),
         cardVisible: true,
@@ -144,6 +141,7 @@ const columns = computed(() => [
     },
     {
         label: t('item.fixedPrice.ended'),
+        field: 'ended',
         name: 'ended',
         ...defaultColumnAttrs,
         cardVisible: true,
@@ -157,6 +155,7 @@ const columns = computed(() => [
         columnClass: 'expand',
         format: (row) => toDate(row.ended),
     },
+
     {
         label: t('item.fixedPrice.warehouse'),
         field: 'warehouseFk',
@@ -223,18 +222,17 @@ const editTableFieldsOptions = [
         label: t('item.fixedPrice.ended'),
         component: 'date',
     },
-];
-
-function confirmRemove(row) {
-    quasar.dialog({
-        component: VnConfirm,
-        componentProps: {
-            title: t('confirmDeletion'),
-            message: t('confirmDeletionMessage'),
-            promise: () => remove(row),
+    {
+        field: 'warehouseFk',
+        label: t('item.fixedPrice.warehouse'),
+        component: 'select',
+        attrs: {
+            options: [],
+            'option-label': 'name',
+            'option-value': 'id',
         },
-    }),
-};
+    },
+];
 const getRowUpdateInputEvents = (props, resetMinPrice, inputType = 'text') => {
     return inputType === 'text'
         ? {

From 039a8d1d02e1ca30a2dd6701a60b7211b3de01cd Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 12 Sep 2024 09:32:41 +0200
Subject: [PATCH 28/87] refs #7283 fix items

---
 src/i18n/locale/en.yml           |  2 ++
 src/i18n/locale/es.yml           |  2 ++
 src/pages/Item/Card/ItemCard.vue |  2 +-
 src/pages/Item/ItemList.vue      | 49 ++++++++++++--------------------
 src/pages/Item/ItemRequest.vue   |  2 +-
 5 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index 6546b78c4..37d1e3726 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -1022,6 +1022,8 @@ travel:
         travelFileDescription: 'Travel id { travelId }'
         file: File
 item:
+    searchbar:
+        label: Search item
     descriptor:
         item: Item
         buyer: Buyer
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 79e66b5f7..0c0447b78 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -1007,6 +1007,8 @@ travel:
         travelFileDescription: 'Id envío { travelId }'
         file: Fichero
 item:
+    searchbar:
+        label: Buscar artículo
     descriptor:
         item: Artículo
         buyer: Comprador
diff --git a/src/pages/Item/Card/ItemCard.vue b/src/pages/Item/Card/ItemCard.vue
index 1162327c1..4cf1372cc 100644
--- a/src/pages/Item/Card/ItemCard.vue
+++ b/src/pages/Item/Card/ItemCard.vue
@@ -12,7 +12,7 @@ import ItemListFilter from '../ItemListFilter.vue';
         search-data-key="ItemList"
         :searchbar-props="{
             url: 'Items/filter',
-            label: 'searchbar.labelr',
+            label: 'item.searchbar.label',
             info: 'searchbar.info',
         }"
     />
diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 2f3d20390..c31302bba 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -44,25 +44,24 @@ const itemFilter = {
     ],
 };
 const columns = computed(() => [
-    // {
-    //     label: '',
-    //     name: 'image',
-    //     align: 'left',
-    //     columnField: {
-    //         component: VnImg,
-    //         attrs: (id) => {
-    //             return {
-    //                 id,
-    //                 width: '50px',
-    //             };
-    //         },
-    //     },
-    //     columnFilter: false,
-    // },
+    {
+        label: '',
+        name: 'image',
+        align: 'left',
+        columnField: {
+            component: VnImg,
+            attrs: (id) => {
+                return {
+                    id,
+                    width: '50px',
+                };
+            },
+        },
+        columnFilter: false,
+    },
     {
         label: t('item.list.id'),
         name: 'id',
-        field: 'id',
         align: 'left',
         isId: true,
         chip: {
@@ -71,38 +70,35 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.grouping'),
-        field: 'grouping',
         name: 'grouping',
         align: 'left',
     },
     {
         label: t('item.list.packing'),
-        field: 'packing',
         name: 'packing',
         align: 'left',
     },
     {
         label: t('globals.description'),
-        field: 'name',
         name: 'description',
         align: 'left',
         create: true,
+        columnFilter: {
+            name: 'description',
+        },
     },
     {
         label: t('item.list.stems'),
-        field: 'stems',
         name: 'stems',
         align: 'left',
     },
     {
         label: t('item.list.size'),
-        field: 'size',
         name: 'size',
         align: 'left',
     },
     {
         label: t('item.list.typeName'),
-        field: 'typeName',
         name: 'typeName',
         align: 'left',
         component: 'select',
@@ -117,7 +113,6 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.category'),
-        field: 'category',
         name: 'category',
         align: 'left',
         component: 'select',
@@ -131,7 +126,6 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.intrastat'),
-        field: 'intrastat',
         name: 'intrastat',
         align: 'left',
         component: 'select',
@@ -146,7 +140,6 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.origin'),
-        field: 'origin',
         name: 'origin',
         align: 'left',
         component: 'select',
@@ -161,13 +154,11 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.userName'),
-        field: 'userName',
         name: 'userName',
         align: 'left',
     },
     {
         label: t('item.list.weightByPiece'),
-        field: 'weightByPiece',
         name: 'weightByPiece',
         align: 'left',
         component: 'input',
@@ -177,7 +168,6 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.stemMultiplier'),
-        field: 'stemMultiplier',
         name: 'stemMultiplier',
         align: 'left',
         component: 'input',
@@ -187,14 +177,12 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.isActive'),
-        field: 'isActive',
         name: 'isActive',
         align: 'left',
         component: 'checkbox',
     },
     {
         label: t('item.list.producer'),
-        field: 'producer',
         name: 'producer',
         align: 'left',
         component: 'select',
@@ -208,7 +196,6 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.landed'),
-        field: 'landed',
         name: 'landed',
         align: 'left',
         component: 'date',
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index be0a9c2e8..4bf45fe4c 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -188,7 +188,7 @@ onMounted(async () => {
         ref="tableRef"
         data-key="itemRequest"
         url="ticketRequests/filter"
-        order="shippedDate ASC, isOk ASC"
+        order="shipped ASC, isOk ASC"
         :columns="columns"
         :user-params="userParams"
         :is-editable="true"

From 68a2ac385f6638d0b23168f085984b2d8b40d313 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 12 Sep 2024 11:36:02 +0200
Subject: [PATCH 29/87] refs #7283 fix items images

---
 src/pages/Item/ItemList.vue | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index c31302bba..ca00a6502 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -50,9 +50,9 @@ const columns = computed(() => [
         align: 'left',
         columnField: {
             component: VnImg,
-            attrs: (id) => {
+            attrs: ({ row }) => {
                 return {
-                    id,
+                    id: row.id,
                     width: '50px',
                 };
             },
@@ -102,9 +102,11 @@ const columns = computed(() => [
         name: 'typeName',
         align: 'left',
         component: 'select',
-        attrs: {
-            url: 'ItemTypes',
-            fields: ['id', 'name'],
+        columnFilter: {
+            attrs: {
+                url: 'ItemTypes',
+                fields: ['name'],
+            },
         },
         columnField: {
             component: null,

From 050d8ae208329f51e38f3e3acb79fe4c8e8a991a Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 12 Sep 2024 11:43:37 +0200
Subject: [PATCH 30/87] refs #7283 fix items error get images

---
 src/pages/Item/ItemList.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index ca00a6502..bed30725b 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -52,7 +52,7 @@ const columns = computed(() => [
             component: VnImg,
             attrs: ({ row }) => {
                 return {
-                    id: row.id,
+                    id: row?.id,
                     width: '50px',
                 };
             },

From 1916c6e4bf0b3b161b9c1ccaf6d554d5e5c2c83b Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Mon, 16 Sep 2024 14:29:39 +0200
Subject: [PATCH 31/87] refs #7283 itemFilters

---
 src/pages/Item/ItemList.vue    | 50 ++++++++++++++++++++++++----------
 src/pages/Item/ItemRequest.vue | 11 ++++++--
 2 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index bed30725b..b6668edea 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -84,7 +84,7 @@ const columns = computed(() => [
         align: 'left',
         create: true,
         columnFilter: {
-            name: 'description',
+            name: 'search',
         },
     },
     {
@@ -103,9 +103,10 @@ const columns = computed(() => [
         align: 'left',
         component: 'select',
         columnFilter: {
+            name: 'typeFk',
             attrs: {
                 url: 'ItemTypes',
-                fields: ['name'],
+                fields: ['id', 'name'],
             },
         },
         columnField: {
@@ -118,9 +119,12 @@ const columns = computed(() => [
         name: 'category',
         align: 'left',
         component: 'select',
-        attrs: {
-            url: 'ItemCategories',
-            fields: ['id', 'name'],
+        columnFilter: {
+            name: 'categoryFk',
+            attrs: {
+                url: 'ItemCategories',
+                fields: ['id', 'name'],
+            },
         },
         columnField: {
             component: null,
@@ -131,9 +135,15 @@ const columns = computed(() => [
         name: 'intrastat',
         align: 'left',
         component: 'select',
-        attrs: {
-            url: 'Intrastats',
-            fields: ['id', 'description'],
+        columnFilter: {
+            name: 'description',
+            attrs: {
+                url: 'Intrastats',
+                optionValue: 'description',
+                optionLabel: 'description',
+            },
+            inWhere: true,
+            alias: 'intr',
         },
         columnField: {
             component: null,
@@ -145,9 +155,15 @@ const columns = computed(() => [
         name: 'origin',
         align: 'left',
         component: 'select',
-        attrs: {
-            url: 'Origins',
-            fields: ['id', 'name'],
+        columnFilter: {
+            name: 'id',
+            attrs: {
+                url: 'Origins',
+                optionValue: 'id',
+                optionLabel: 'code',
+            },
+            inWhere: true,
+            alias: 'ori',
         },
         columnField: {
             component: null,
@@ -158,6 +174,14 @@ const columns = computed(() => [
         label: t('item.list.userName'),
         name: 'userName',
         align: 'left',
+        columnFilter: {
+            name: 'workerFk',
+            attrs: {
+                url: 'Users',
+                optionValue: 'id',
+                optionLabel: 'userName',
+            },
+        },
     },
     {
         label: t('item.list.weightByPiece'),
@@ -249,8 +273,6 @@ const cloneItem = async (itemFk) => {
         data-key="ItemList"
         url="Items/filter"
         url-create="Items"
-        save-url="Items/crud"
-        :filter="itemFilter"
         :create="{
             urlCreate: 'Items',
             title: 'Create Item',
@@ -264,7 +286,7 @@ const cloneItem = async (itemFk) => {
         auto-load
         redirect="Item"
         :is-editable="false"
-        :use-model="true"
+        :filer="itemFilter"
     >
         <template #column-userName="{ row }">
             <span class="link" @click.stop>
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 4bf45fe4c..1a1d98211 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -57,45 +57,51 @@ const columns = computed(() => [
             component: null,
         },
         format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.shipped)),
+        columnClass: 'shrink',
     },
     {
         label: t('globals.description'),
         field: 'description',
         name: 'description',
         align: 'left',
+        columnClass: 'expand',
     },
     {
         label: t('item.buyRequest.requester'),
         name: 'requesterName',
-        align: 'left',
+        columnClass: 'shrink',
     },
     {
         label: t('item.buyRequest.requested'),
         name: 'quantity',
-        align: 'left',
+        columnClass: 'shrink',
     },
     {
         label: t('item.buyRequest.price'),
         name: 'price',
         align: 'left',
         format: (row) => toCurrency(row.price),
+        columnClass: 'shrink',
     },
     {
         label: t('item.buyRequest.attender'),
         name: 'attenderName',
         align: 'left',
+        columnClass: 'shrink',
     },
     {
         label: t('item.buyRequest.item'),
         name: 'item',
         align: 'left',
         component: 'input',
+        columnClass: 'expand',
     },
     {
         label: t('item.buyRequest.achieved'),
         name: 'achieved',
         align: 'left',
         component: 'input',
+        columnClass: 'shrink',
     },
     {
         label: t('item.buyRequest.concept'),
@@ -103,6 +109,7 @@ const columns = computed(() => [
         align: 'left',
         sortable: true,
         component: 'input',
+        columnClass: 'expand',
     },
     {
         label: t('item.buyRequest.state'),

From db783e15384163fdb7221afae2fc4e509e0c4c52 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 17 Sep 2024 15:03:30 +0200
Subject: [PATCH 32/87] refs #7283 item Descriptor

---
 src/composables/useArrayData.js             |   1 +
 src/pages/Item/Card/ItemDescriptor.vue      |  70 ++++++-------
 src/pages/Item/Card/ItemDescriptorImage.vue |   8 +-
 src/pages/Item/Card/ItemDiary.vue           | 110 +++++++++++---------
 4 files changed, 98 insertions(+), 91 deletions(-)

diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js
index 651bcefb0..6671632b3 100644
--- a/src/composables/useArrayData.js
+++ b/src/composables/useArrayData.js
@@ -246,6 +246,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
     }
 
     function updateStateParams() {
+        if (!route) return;
         const newUrl = { path: route.path, query: { ...(route.query ?? {}) } };
         newUrl.query[store.searchUrl] = JSON.stringify(store.currentFilter);
 
diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index baac0c608..a14ee1446 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -14,6 +14,7 @@ import useCardDescription from 'src/composables/useCardDescription';
 import { getUrl } from 'src/composables/getUrl';
 import axios from 'axios';
 import { dashIfEmpty } from 'src/filters';
+import { useArrayData } from 'src/composables/useArrayData';
 
 const $props = defineProps({
     id: {
@@ -49,58 +50,49 @@ const entityId = computed(() => {
 });
 
 const regularizeStockFormDialog = ref(null);
-const available = ref(null);
-const visible = ref(null);
 const salixUrl = ref();
+const mounted = ref();
+
+const arrayDataStock = useArrayData('descriptorStock', {
+    url: `Items/${entityId.value}/getVisibleAvailable`,
+});
 
 onMounted(async () => {
-    salixUrl.value = await getUrl('');
+    salixUrl.value = await getUrl('getVisibleAvailable');
     await getItemConfigs();
-    await updateStock();
+    mounted.value = true;
 });
 
 const data = ref(useCardDescription());
 const setData = async (entity) => {
-    try {
-        if (!entity) return;
-        data.value = useCardDescription(entity.name, entity.id);
-        await updateStock();
-    } catch (err) {
-        console.error('Error item');
-    }
+    if (!entity) return;
+    data.value = useCardDescription(entity.name, entity.id);
+    await updateStock();
 };
 
 const getItemConfigs = async () => {
-    try {
-        const { data } = await axios.get('ItemConfigs/findOne');
-        if (!data) return;
-        return (warehouseConfig.value = data.warehouseFk);
-    } catch (err) {
-        console.error('Error item');
-    }
+    const { data } = await axios.get('ItemConfigs/findOne');
+    if (!data) return;
+    return (warehouseConfig.value = data.warehouseFk);
 };
 const updateStock = async () => {
-    try {
-        available.value = null;
-        visible.value = null;
+    if (!mounted.value) return;
+    await getItemConfigs();
 
-        const params = {
-            warehouseFk: $props.warehouseFk,
-            dated: $props.dated,
-        };
+    const params = {
+        warehouseFk: $props.warehouseFk ?? warehouseConfig.value,
+        dated: $props.dated,
+    };
 
-        await getItemConfigs();
-        if (!params.warehouseFk) {
-            params.warehouseFk = warehouseConfig.value;
-        }
-        const { data } = await axios.get(`Items/${entityId.value}/getVisibleAvailable`, {
-            params,
-        });
-        available.value = data.available;
-        visible.value = data.visible;
-    } catch (err) {
-        console.error('Error updating stock');
-    }
+    if (!params.warehouseFk) return;
+
+    const stock = useArrayData('descriptorStock', {
+        url: `Items/${entityId.value}/getVisibleAvailable`,
+        userParams: params,
+    });
+    const storeData = stock.store.data;
+    if (storeData?.itemFk == entityId.value) return;
+    await stock.fetch({});
 };
 
 const openRegularizeStockForm = () => {
@@ -163,8 +155,8 @@ const openCloneDialog = async () => {
         <template #before>
             <ItemDescriptorImage
                 :entity-id="entityId"
-                :visible="visible"
-                :available="available"
+                :visible="arrayDataStock.store.data?.visible"
+                :available="arrayDataStock.store.data?.available"
             />
         </template>
         <template #body="{ entity }">
diff --git a/src/pages/Item/Card/ItemDescriptorImage.vue b/src/pages/Item/Card/ItemDescriptorImage.vue
index a4ef22ce3..b035a630a 100644
--- a/src/pages/Item/Card/ItemDescriptorImage.vue
+++ b/src/pages/Item/Card/ItemDescriptorImage.vue
@@ -32,6 +32,10 @@ const editPhotoFormDialog = ref(null);
 const showEditPhotoForm = ref(false);
 const warehouseName = ref(null);
 
+onMounted(async () => {
+    getItemConfigs();
+});
+
 const toggleEditPictureForm = () => {
     showEditPhotoForm.value = !showEditPhotoForm.value;
 };
@@ -56,10 +60,6 @@ const getWarehouseName = async (warehouseFk) => {
     warehouseName.value = data.name;
 };
 
-onMounted(async () => {
-    getItemConfigs();
-});
-
 const handlePhotoUpdated = (evt = false) => {
     image.value.reload(evt);
 };
diff --git a/src/pages/Item/Card/ItemDiary.vue b/src/pages/Item/Card/ItemDiary.vue
index 68633caa2..a36b6a246 100644
--- a/src/pages/Item/Card/ItemDiary.vue
+++ b/src/pages/Item/Card/ItemDiary.vue
@@ -17,6 +17,7 @@ import { toDateFormat } from 'src/filters/date.js';
 import { dashIfEmpty } from 'src/filters';
 import { date } from 'quasar';
 import { useState } from 'src/composables/useState';
+import { useArrayData } from 'src/composables/useArrayData';
 import axios from 'axios';
 
 const { t } = useI18n();
@@ -37,6 +38,33 @@ const warehouseFk = ref(null);
 const _showWhatsBeforeInventory = ref(false);
 const inventoriedDate = ref(null);
 
+const originTypeMap = {
+    entry: {
+        descriptor: EntryDescriptorProxy,
+        icon: 'vn:entry',
+        color: 'green',
+    },
+    ticket: {
+        descriptor: TicketDescriptorProxy,
+        icon: 'vn:ticket',
+        color: 'red',
+    },
+    order: {
+        descriptor: OrderDescriptorProxy,
+        icon: 'vn:basket',
+        color: 'yellow',
+    },
+};
+
+const entityTypeMap = {
+    client: {
+        descriptor: CustomerDescriptorProxy,
+    },
+    supplier: {
+        descriptor: SupplierDescriptorProxy,
+    },
+};
+
 const columns = computed(() => [
     {
         name: 'claim',
@@ -105,6 +133,28 @@ const showWhatsBeforeInventory = computed({
     },
 });
 
+onMounted(async () => {
+    today.value.setHours(0, 0, 0, 0);
+    if (route.query.warehouseFk) warehouseFk.value = route.query.warehouseFk;
+    else if (user.value) warehouseFk.value = user.value.warehouseFk;
+    itemsBalanceFilter.where.warehouseFk = warehouseFk.value;
+    const { data } = await axios.get('Configs/findOne');
+    inventoriedDate.value = data.inventoried;
+    await fetchItemBalances();
+    await scrollToToday();
+    await updateWarehouse(warehouseFk.value);
+});
+
+onUnmounted(() => (stateStore.rightDrawer = false));
+
+watch(
+    () => router.currentRoute.value.params.id,
+    (newId) => {
+        itemsBalanceFilter.where.itemFk = newId;
+        itemBalancesRef.value.fetch();
+    }
+);
+
 const fetchItemBalances = async () => await itemBalancesRef.value.fetch();
 
 const getBadgeAttrs = (_date) => {
@@ -131,53 +181,15 @@ const formatDateForAttribute = (dateValue) => {
     return dateValue;
 };
 
-const originTypeMap = {
-    entry: {
-        descriptor: EntryDescriptorProxy,
-        icon: 'vn:entry',
-        color: 'green',
-    },
-    ticket: {
-        descriptor: TicketDescriptorProxy,
-        icon: 'vn:ticket',
-        color: 'red',
-    },
-    order: {
-        descriptor: OrderDescriptorProxy,
-        icon: 'vn:basket',
-        color: 'yellow',
-    },
-};
-
-const entityTypeMap = {
-    client: {
-        descriptor: CustomerDescriptorProxy,
-    },
-    supplier: {
-        descriptor: SupplierDescriptorProxy,
-    },
-};
-
-onMounted(async () => {
-    today.value.setHours(0, 0, 0, 0);
-    if (route.query.warehouseFk) warehouseFk.value = route.query.warehouseFk;
-    else if (user.value) warehouseFk.value = user.value.warehouseFk;
-    itemsBalanceFilter.where.warehouseFk = warehouseFk.value;
-    const { data } = await axios.get('Configs/findOne');
-    inventoriedDate.value = data.inventoried;
-    await fetchItemBalances();
-    await scrollToToday();
-});
-
-onUnmounted(() => (stateStore.rightDrawer = false));
-
-watch(
-    () => router.currentRoute.value.params.id,
-    (newId) => {
-        itemsBalanceFilter.where.itemFk = newId;
-        itemBalancesRef.value.fetch();
-    }
-);
+async function updateWarehouse(warehouseFk) {
+    const stock = useArrayData('descriptorStock', {
+        userParams: {
+            warehouseFk,
+        },
+    });
+    await stock.fetch({});
+    stock.store.data.itemFk = route.params.id
+}
 </script>
 
 <template>
@@ -203,7 +215,9 @@ watch(
                 option-value="id"
                 dense
                 v-model="itemsBalanceFilter.where.warehouseFk"
-                @update:model-value="fetchItemBalances"
+                @update:model-value="
+                    (value) => fetchItemBalances() && updateWarehouse(value)
+                "
                 class="q-mr-lg"
             />
             <QCheckbox

From 716d018121026767ecd2e9b5b1f47dffa349a028 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Fri, 20 Sep 2024 14:20:26 +0200
Subject: [PATCH 33/87] refs #72983 fix filters

---
 src/pages/Item/ItemList.vue | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index b6668edea..48fe3280e 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -54,6 +54,7 @@ const columns = computed(() => [
                 return {
                     id: row?.id,
                     width: '50px',
+                    zoomResolution: '1600x900',
                 };
             },
         },
@@ -72,11 +73,19 @@ const columns = computed(() => [
         label: t('item.list.grouping'),
         name: 'grouping',
         align: 'left',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         label: t('item.list.packing'),
         name: 'packing',
         align: 'left',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         label: t('globals.description'),
@@ -91,11 +100,19 @@ const columns = computed(() => [
         label: t('item.list.stems'),
         name: 'stems',
         align: 'left',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         label: t('item.list.size'),
         name: 'size',
         align: 'left',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         label: t('item.list.typeName'),

From 54015fb6bfbf975a7fed3150cf82de904df56d63 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Tue, 1 Oct 2024 08:44:08 +0200
Subject: [PATCH 34/87] refs #7283 fix itemMigration

---
 src/pages/Item/ItemRequest.vue | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 1a1d98211..7fbeccbf9 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -117,6 +117,15 @@ const columns = computed(() => [
         format: (row) => getState(row.isOk),
         align: 'left',
     },
+    {
+        align: 'left',
+        name: 'daysOnward',
+        label: t('item.buyRequest.daysOnward'),
+        visible: false,
+        columnFilter: {
+            inWhere: false,
+        },
+    },
     {
         align: 'right',
         label: '',
@@ -238,6 +247,17 @@ onMounted(async () => {
                 {{ row.itemDescription }}
             </span>
         </template>
+        <template #moreFilterPanel="{ params }">
+            <VnInputNumber
+                :label="t('params.scopeDays')"
+                v-model.number="params.scopeDays"
+                @keyup.enter="(evt) => handleScopeDays(evt.target.value)"
+                @remove="handleScopeDays()"
+                class="q-px-xs q-pr-lg"
+                filled
+                dense
+            />
+        </template>
         <template #column-denyOptions="{ row, rowIndex }">
             <QTd class="sticky no-padding">
                 <QIcon

From 55ddc8644f0450091f49ce96d4ef1ad2d3988a68 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Wed, 2 Oct 2024 12:51:33 +0200
Subject: [PATCH 35/87] refs #7283 fix itemMigration list filters

---
 src/pages/Item/ItemList.vue    | 8 +++++++-
 src/pages/Item/ItemRequest.vue | 3 ++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 48fe3280e..ad2c2e238 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -208,6 +208,9 @@ const columns = computed(() => [
         columnField: {
             component: null,
         },
+        columnFilter: {
+            inWhere: true,
+        },
     },
     {
         label: t('item.list.stemMultiplier'),
@@ -217,11 +220,14 @@ const columns = computed(() => [
         columnField: {
             component: null,
         },
+        columnFilter: {
+            inWhere: true,
+        },
     },
     {
         label: t('item.list.isActive'),
         name: 'isActive',
-        align: 'left',
+        align: 'center',
         component: 'checkbox',
     },
     {
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 7fbeccbf9..0eba6f9a4 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -29,6 +29,7 @@ const store = arrayData.store;
 
 const userParams = {
     state: 'pending',
+    daysOnward: 7,
 };
 
 const tableRef = ref();
@@ -120,7 +121,7 @@ const columns = computed(() => [
     {
         align: 'left',
         name: 'daysOnward',
-        label: t('item.buyRequest.daysOnward'),
+        label: t('travel.travelList.tableVisibleColumns.daysOnward'),
         visible: false,
         columnFilter: {
             inWhere: false,

From f2cb0111eb6a5ceb1232da91f5190b5610c2e81d Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Wed, 16 Oct 2024 14:45:33 +0200
Subject: [PATCH 36/87] fix: refs #7283 fix image

---
 src/pages/Item/ItemList.vue | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index ad2c2e238..6c7b7eaed 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -1,10 +1,9 @@
 <script setup>
-import { ref, computed, onUnmounted } from 'vue';
+import { ref, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRouter, useRoute } from 'vue-router';
 import VnImg from 'src/components/ui/VnImg.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
-import { useStateStore } from 'stores/useStateStore';
 import { toDate } from 'src/filters';
 import axios from 'axios';
 import FetchedTags from 'src/components/ui/FetchedTags.vue';
@@ -16,7 +15,6 @@ const entityId = computed(() => route.params.id);
 
 const { viewSummary } = useSummaryDialog();
 const router = useRouter();
-const stateStore = useStateStore();
 const { t } = useI18n();
 const tableRef = ref();
 const route = useRoute();
@@ -53,8 +51,8 @@ const columns = computed(() => [
             attrs: ({ row }) => {
                 return {
                     id: row?.id,
-                    width: '50px',
                     zoomResolution: '1600x900',
+                    zoom: true,
                 };
             },
         },
@@ -116,9 +114,13 @@ const columns = computed(() => [
     },
     {
         label: t('item.list.typeName'),
-        name: 'typeName',
+        name: 'typeFk',
         align: 'left',
         component: 'select',
+        attrs: {
+            url: 'ItemTypes',
+            fields: ['id', 'name'],
+        },
         columnFilter: {
             name: 'typeFk',
             attrs: {
@@ -152,6 +154,11 @@ const columns = computed(() => [
         name: 'intrastat',
         align: 'left',
         component: 'select',
+        attrs: {
+            url: 'Intrastats',
+            optionValue: 'description',
+            optionLabel: 'description',
+        },
         columnFilter: {
             name: 'description',
             attrs: {
@@ -159,7 +166,6 @@ const columns = computed(() => [
                 optionValue: 'description',
                 optionLabel: 'description',
             },
-            inWhere: true,
             alias: 'intr',
         },
         columnField: {
@@ -172,6 +178,11 @@ const columns = computed(() => [
         name: 'origin',
         align: 'left',
         component: 'select',
+        attrs: {
+            url: 'Origins',
+            optionValue: 'id',
+            optionLabel: 'code',
+        },
         columnFilter: {
             name: 'id',
             attrs: {

From 2b2ccbc6a105da40fb07f20fc012d4cb87589f9f Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Mon, 21 Oct 2024 12:14:54 +0200
Subject: [PATCH 37/87] feat: refs #7524 myTeam filter & default params

---
 src/i18n/locale/en.yml                   |  1 +
 src/i18n/locale/es.yml                   |  1 +
 src/pages/Ticket/TicketAdvance.vue       |  3 +++
 src/pages/Ticket/TicketAdvanceFilter.vue | 19 +++++++++++++++++--
 src/pages/Ticket/locale/es.yml           |  4 ++--
 5 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index 7eb3829fe..17a3e097a 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -296,6 +296,7 @@ globals:
         from: From
         To: To
         stateFk: State
+        myTeam: My team
 errors:
     statusUnauthorized: Access denied
     statusInternalServerError: An internal server error has ocurred
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 9d5cd53f3..fc61936d2 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -300,6 +300,7 @@ globals:
         from: Desde
         To: Hasta
         stateFk: Estado
+        myTeam: Mi equipo
 errors:
     statusUnauthorized: Acceso denegado
     statusInternalServerError: Ha ocurrido un error interno del servidor
diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index 177b3a29b..2cce1dba8 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -462,6 +462,9 @@ onMounted(async () => {
     userParams.dateFuture = tomorrow;
     userParams.dateToAdvance = today;
     userParams.warehouseFk = user.value.warehouseFk;
+    userParams.ipt = 'H';
+    userParams.futureIpt = 'H';
+    userParams.isFullMovable = true;
     const filter = { limit: 0 };
     await arrayData.addFilter({ filter, userParams });
 });
diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index 209a1a307..38a0dd4c2 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -10,7 +10,7 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
 import axios from 'axios';
 import { onMounted } from 'vue';
 
-const { t } = useI18n();
+const { t, te } = useI18n();
 const props = defineProps({
     dataKey: {
         type: String,
@@ -42,6 +42,11 @@ const getItemPackingTypes = async () => {
     }
 };
 
+const getLocale = (val) => {
+    const param = `params.${val}`;
+    return te(param) ? t(param) : t(`globals.${param}`);
+};
+
 onMounted(async () => await getItemPackingTypes());
 </script>
 
@@ -59,7 +64,7 @@ onMounted(async () => await getItemPackingTypes());
     >
         <template #tags="{ tag, formatFn }">
             <div class="q-gutter-x-xs">
-                <strong>{{ t(`params.${tag.label}`) }}: </strong>
+                <strong>{{ getLocale(tag.label) }}: </strong>
                 <span>{{ formatFn(tag.value) }}</span>
             </div>
         </template>
@@ -142,6 +147,16 @@ onMounted(async () => await getItemPackingTypes());
                     </VnSelect>
                 </QItemSection>
             </QItem>
+            <QItem>
+                <QItemSection>
+                    <QCheckbox
+                        :label="t('globals.params.myTeam')"
+                        v-model="params.myTeam"
+                        toggle-indeterminate
+                        @update:model-value="searchFn()"
+                    />
+                </QItemSection>
+            </QItem>
         </template>
     </VnFilterPanel>
 </template>
diff --git a/src/pages/Ticket/locale/es.yml b/src/pages/Ticket/locale/es.yml
index 0a27519ad..d4ba1f26a 100644
--- a/src/pages/Ticket/locale/es.yml
+++ b/src/pages/Ticket/locale/es.yml
@@ -86,9 +86,9 @@ weeklyTickets:
     search: Buscar por tickets programados
     searchInfo: Buscar tickets programados por el identificador o el identificador del cliente
 advanceTickets:
-    preparation: Preparación    
+    preparation: Preparación
     origin: Origen
-    destination: Destinatario
+    destination: Destino
     originAgency: 'Agencia origen: {agency}'
     destinationAgency: 'Agencia destino: {agency}'
     ticketId: ID

From a4358ec0edbcebd07fcf427c8a49097913b62dcb Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Mon, 21 Oct 2024 12:36:16 +0200
Subject: [PATCH 38/87] chore: refs #7524 refactor order

---
 src/pages/Ticket/TicketAdvanceFilter.vue | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index 38a0dd4c2..07c745250 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -129,6 +129,12 @@ onMounted(async () => await getItemPackingTypes());
                         toggle-indeterminate
                         @update:model-value="searchFn()"
                     />
+                    <QCheckbox
+                        :label="t('globals.params.myTeam')"
+                        v-model="params.myTeam"
+                        toggle-indeterminate
+                        @update:model-value="searchFn()"
+                    />
                 </QItemSection>
             </QItem>
             <QItem>
@@ -147,16 +153,6 @@ onMounted(async () => await getItemPackingTypes());
                     </VnSelect>
                 </QItemSection>
             </QItem>
-            <QItem>
-                <QItemSection>
-                    <QCheckbox
-                        :label="t('globals.params.myTeam')"
-                        v-model="params.myTeam"
-                        toggle-indeterminate
-                        @update:model-value="searchFn()"
-                    />
-                </QItemSection>
-            </QItem>
         </template>
     </VnFilterPanel>
 </template>

From 52981953f7e9efbc1a8875c321376e02a50c3b33 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 21 Oct 2024 13:23:45 +0200
Subject: [PATCH 39/87] feat(): refs #8039 canceledError not notify

---
 src/boot/axios.js  | 5 +++--
 src/boot/quasar.js | 3 ++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/boot/axios.js b/src/boot/axios.js
index 3bd80f487..d3e981adb 100644
--- a/src/boot/axios.js
+++ b/src/boot/axios.js
@@ -3,6 +3,7 @@ import { useSession } from 'src/composables/useSession';
 import { Router } from 'src/router';
 import useNotify from 'src/composables/useNotify.js';
 import { useStateQueryStore } from 'src/stores/useStateQueryStore';
+import { CanceledError } from 'axios';
 
 const session = useSession();
 const { notify } = useNotify();
@@ -42,7 +43,7 @@ const onResponseError = (error) => {
     let message = '';
 
     const response = error.response;
-    const responseData = response && response.data;
+    const responseData = response?.data;
     const responseError = responseData && response.data.error;
     if (responseError) {
         message = responseError.message;
@@ -78,7 +79,7 @@ const onResponseError = (error) => {
         return Promise.reject(error);
     }
 
-    notify(message, 'negative');
+    if (!(error instanceof CanceledError)) notify(message, 'negative');
 
     return Promise.reject(error);
 };
diff --git a/src/boot/quasar.js b/src/boot/quasar.js
index 5db6edd24..41a7990c7 100644
--- a/src/boot/quasar.js
+++ b/src/boot/quasar.js
@@ -3,6 +3,7 @@ import qFormMixin from './qformMixin';
 import mainShortcutMixin from './mainShortcutMixin';
 import keyShortcut from './keyShortcut';
 import useNotify from 'src/composables/useNotify.js';
+import { CanceledError } from 'axios';
 const { notify } = useNotify();
 
 export default boot(({ app }) => {
@@ -11,6 +12,6 @@ export default boot(({ app }) => {
     app.directive('shortcut', keyShortcut);
     app.config.errorHandler = function (err) {
         console.error(err);
-        notify('globals.error', 'negative', 'error');
+        if (!(err instanceof CanceledError)) notify('globals.error', 'negative', 'error');
     };
 });

From 9780fe596fa0af4212f308a3150d1066a3275517 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 21 Oct 2024 13:33:12 +0200
Subject: [PATCH 40/87] feat: refs #8039 notify error unify

---
 src/boot/axios.js  | 34 +---------------------------------
 src/boot/quasar.js | 37 ++++++++++++++++++++++++++++++++++---
 2 files changed, 35 insertions(+), 36 deletions(-)

diff --git a/src/boot/axios.js b/src/boot/axios.js
index d3e981adb..b084b835d 100644
--- a/src/boot/axios.js
+++ b/src/boot/axios.js
@@ -40,37 +40,7 @@ const onResponse = (response) => {
 const onResponseError = (error) => {
     stateQuery.remove(error.config);
 
-    let message = '';
-
-    const response = error.response;
-    const responseData = response?.data;
-    const responseError = responseData && response.data.error;
-    if (responseError) {
-        message = responseError.message;
-    }
-
-    switch (response?.status) {
-        case 422:
-            if (error.name == 'ValidationError')
-                message +=
-                    ' "' +
-                    responseError.details.context +
-                    '.' +
-                    Object.keys(responseError.details.codes).join(',') +
-                    '"';
-            break;
-        case 500:
-            message = 'errors.statusInternalServerError';
-            break;
-        case 502:
-            message = 'errors.statusBadGateway';
-            break;
-        case 504:
-            message = 'errors.statusGatewayTimeout';
-            break;
-    }
-
-    if (session.isLoggedIn() && response?.status === 401) {
+    if (session.isLoggedIn() && error.response?.status === 401) {
         session.destroy(false);
         const hash = window.location.hash;
         const url = hash.slice(1);
@@ -79,8 +49,6 @@ const onResponseError = (error) => {
         return Promise.reject(error);
     }
 
-    if (!(error instanceof CanceledError)) notify(message, 'negative');
-
     return Promise.reject(error);
 };
 
diff --git a/src/boot/quasar.js b/src/boot/quasar.js
index 41a7990c7..bf5175ee6 100644
--- a/src/boot/quasar.js
+++ b/src/boot/quasar.js
@@ -10,8 +10,39 @@ export default boot(({ app }) => {
     app.mixin(qFormMixin);
     app.mixin(mainShortcutMixin);
     app.directive('shortcut', keyShortcut);
-    app.config.errorHandler = function (err) {
-        console.error(err);
-        if (!(err instanceof CanceledError)) notify('globals.error', 'negative', 'error');
+    app.config.errorHandler = (error) => {
+        let message;
+        const response = error.response;
+        const responseData = response?.data;
+        const responseError = responseData && response.data.error;
+        if (responseError) {
+            message = responseError.message;
+        }
+
+        switch (response?.status) {
+            case 422:
+                if (error.name == 'ValidationError')
+                    message +=
+                        ' "' +
+                        responseError.details.context +
+                        '.' +
+                        Object.keys(responseError.details.codes).join(',') +
+                        '"';
+                break;
+            case 500:
+                message = 'errors.statusInternalServerError';
+                break;
+            case 502:
+                message = 'errors.statusBadGateway';
+                break;
+            case 504:
+                message = 'errors.statusGatewayTimeout';
+                break;
+        }
+
+        console.error(error);
+        if (error instanceof CanceledError) return;
+
+        notify(message ?? 'globals.error', 'negative', 'error');
     };
 });

From c69f7af3906e5d88f321350813ec42cc692bd6f4 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 21 Oct 2024 13:38:35 +0200
Subject: [PATCH 41/87] test: refs #8039 axios not notify

---
 test/vitest/__tests__/boot/axios.spec.js | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/test/vitest/__tests__/boot/axios.spec.js b/test/vitest/__tests__/boot/axios.spec.js
index 7a802b4d2..19d396ec5 100644
--- a/test/vitest/__tests__/boot/axios.spec.js
+++ b/test/vitest/__tests__/boot/axios.spec.js
@@ -36,8 +36,6 @@ describe('Axios boot', () => {
 
     describe('onResponseError()', async () => {
         it('should call to the Notify plugin with a message error for an status code "500"', async () => {
-            Notify.create = vi.fn();
-
             const error = {
                 response: {
                     status: 500,
@@ -45,19 +43,10 @@ describe('Axios boot', () => {
             };
 
             const result = onResponseError(error);
-
             expect(result).rejects.toEqual(expect.objectContaining(error));
-            expect(Notify.create).toHaveBeenCalledWith(
-                expect.objectContaining({
-                    message: 'An internal server error has ocurred',
-                    type: 'negative',
-                })
-            );
         });
 
         it('should call to the Notify plugin with a message from the response property', async () => {
-            Notify.create = vi.fn();
-
             const error = {
                 response: {
                     status: 401,
@@ -70,14 +59,7 @@ describe('Axios boot', () => {
             };
 
             const result = onResponseError(error);
-
             expect(result).rejects.toEqual(expect.objectContaining(error));
-            expect(Notify.create).toHaveBeenCalledWith(
-                expect.objectContaining({
-                    message: 'Invalid user or password',
-                    type: 'negative',
-                })
-            );
         });
     });
 });

From 29a7f3b2fed499111e620941fd17baa55611a388 Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Mon, 21 Oct 2024 13:48:43 +0200
Subject: [PATCH 42/87] fix: refs #7283 #7283 ItemDiary subToolbar

---
 src/pages/Item/Card/ItemDiary.vue | 67 ++++++++++++++++---------------
 1 file changed, 34 insertions(+), 33 deletions(-)

diff --git a/src/pages/Item/Card/ItemDiary.vue b/src/pages/Item/Card/ItemDiary.vue
index a36b6a246..23dc6214e 100644
--- a/src/pages/Item/Card/ItemDiary.vue
+++ b/src/pages/Item/Card/ItemDiary.vue
@@ -188,7 +188,7 @@ async function updateWarehouse(warehouseFk) {
         },
     });
     await stock.fetch({});
-    stock.store.data.itemFk = route.params.id
+    stock.store.data.itemFk = route.params.id;
 }
 </script>
 
@@ -205,38 +205,39 @@ async function updateWarehouse(warehouseFk) {
         auto-load
         @on-fetch="(data) => (warehousesOptions = data)"
     />
-    <QToolbar class="justify-end">
-        <div id="st-data" class="row">
-            <VnSelect
-                :label="t('itemDiary.warehouse')"
-                :options="warehousesOptions"
-                hide-selected
-                option-label="name"
-                option-value="id"
-                dense
-                v-model="itemsBalanceFilter.where.warehouseFk"
-                @update:model-value="
-                    (value) => fetchItemBalances() && updateWarehouse(value)
-                "
-                class="q-mr-lg"
-            />
-            <QCheckbox
-                :label="t('itemDiary.showBefore')"
-                v-model="showWhatsBeforeInventory"
-                @update:model-value="fetchItemBalances"
-                class="q-mr-lg"
-            />
-            <VnInputDate
-                v-if="showWhatsBeforeInventory"
-                :label="t('itemDiary.since')"
-                dense
-                v-model="itemsBalanceFilter.where.date"
-                @update:model-value="fetchItemBalances"
-            />
-        </div>
-        <QSpace />
-        <div id="st-actions"></div>
-    </QToolbar>
+    <template v-if="stateStore.isHeaderMounted()">
+        <Teleport to="#st-data">
+            <div class="row">
+                <VnSelect
+                    :label="t('itemDiary.warehouse')"
+                    :options="warehousesOptions"
+                    hide-selected
+                    option-label="name"
+                    option-value="id"
+                    dense
+                    v-model="itemsBalanceFilter.where.warehouseFk"
+                    @update:model-value="
+                        (value) => fetchItemBalances() && updateWarehouse(value)
+                    "
+                    class="q-mr-lg"
+                />
+                <QCheckbox
+                    :label="t('itemDiary.showBefore')"
+                    v-model="showWhatsBeforeInventory"
+                    @update:model-value="fetchItemBalances"
+                    class="q-mr-lg"
+                />
+                <VnInputDate
+                    v-if="showWhatsBeforeInventory"
+                    :label="t('itemDiary.since')"
+                    dense
+                    v-model="itemsBalanceFilter.where.date"
+                    @update:model-value="fetchItemBalances"
+                />
+            </div>
+        </Teleport>
+        <Teleport to="#st-actions"> </Teleport>
+    </template>
     <QPage class="column items-center q-pa-md">
         <QTable
             :rows="itemBalances"

From 0fbd5f45e1c929aaaa1c1918c346ee9e7fcb56eb Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Mon, 21 Oct 2024 14:29:29 +0200
Subject: [PATCH 43/87] fix: refs #7524 select department

---
 src/i18n/locale/en.yml                   |  1 +
 src/i18n/locale/es.yml                   |  1 +
 src/pages/Ticket/TicketAdvanceFilter.vue | 17 ++++++++++++-----
 3 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index 17a3e097a..1c17e92f9 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -297,6 +297,7 @@ globals:
         To: To
         stateFk: State
         myTeam: My team
+        departmentFk: Department
 errors:
     statusUnauthorized: Access denied
     statusInternalServerError: An internal server error has ocurred
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index fc61936d2..5d3d9d859 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -301,6 +301,7 @@ globals:
         To: Hasta
         stateFk: Estado
         myTeam: Mi equipo
+        departmentFk: Departamento
 errors:
     statusUnauthorized: Acceso denegado
     statusInternalServerError: Ha ocurrido un error interno del servidor
diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index 07c745250..182f715a3 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -129,11 +129,18 @@ onMounted(async () => await getItemPackingTypes());
                         toggle-indeterminate
                         @update:model-value="searchFn()"
                     />
-                    <QCheckbox
-                        :label="t('globals.params.myTeam')"
-                        v-model="params.myTeam"
-                        toggle-indeterminate
-                        @update:model-value="searchFn()"
+                </QItemSection>
+            </QItem>
+            <QItem>
+                <QItemSection>
+                    <VnSelect
+                        :label="t('globals.params.departmentFk')"
+                        v-model="params.departmentFk"
+                        url="Departments"
+                        :fields="['id', 'name']"
+                        dense
+                        outlined
+                        rounded
                     />
                 </QItemSection>
             </QItem>

From f3a62091893009b75b4ef3a701f7db1b43f151e1 Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Tue, 22 Oct 2024 12:00:11 +0200
Subject: [PATCH 44/87] fix: refs #7283 #7283 bugs

---
 src/pages/Item/Card/ItemDescriptorImage.vue |  4 +-
 src/pages/Item/ItemList.vue                 | 55 ++++++++++++++++-----
 2 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/src/pages/Item/Card/ItemDescriptorImage.vue b/src/pages/Item/Card/ItemDescriptorImage.vue
index b035a630a..3cd51758b 100644
--- a/src/pages/Item/Card/ItemDescriptorImage.vue
+++ b/src/pages/Item/Card/ItemDescriptorImage.vue
@@ -134,10 +134,10 @@ es:
     Regularize stock: Regularizar stock
     All it's properties will be copied: Todas sus propiedades serán copiadas
     Do you want to clone this item?: ¿Desea clonar este artículo?
-    warehouseText: Calculated on the warehouse of { warehouseName }
+    warehouseText: Calculado sobre el almacén de { warehouseName }
 
 en:
-    warehouseText: Calculado sobre el almacén de { warehouseName }
+    warehouseText: Calculated on the warehouse of { warehouseName }
 </i18n>
 
 <style lang="scss" scoped>
diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 6c7b7eaed..92c9d188b 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -11,6 +11,9 @@ import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 import ItemSummary from '../Item/Card/ItemSummary.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
+import VnConfirm from 'src/components/ui/VnConfirm.vue';
+import { useQuasar } from 'quasar';
 const entityId = computed(() => route.params.id);
 
 const { viewSummary } = useSummaryDialog();
@@ -18,6 +21,7 @@ const router = useRouter();
 const { t } = useI18n();
 const tableRef = ref();
 const route = useRoute();
+const quasar = useQuasar();
 
 const itemFilter = {
     include: [
@@ -53,10 +57,12 @@ const columns = computed(() => [
                     id: row?.id,
                     zoomResolution: '1600x900',
                     zoom: true,
+                    class: 'rounded',
                 };
             },
         },
         columnFilter: false,
+        cardVisible: true,
     },
     {
         label: t('item.list.id'),
@@ -66,6 +72,7 @@ const columns = computed(() => [
         chip: {
             condition: () => true,
         },
+        cardVisible: true,
     },
     {
         label: t('item.list.grouping'),
@@ -93,6 +100,7 @@ const columns = computed(() => [
         columnFilter: {
             name: 'search',
         },
+        cardVisible: true,
     },
     {
         label: t('item.list.stems'),
@@ -102,6 +110,7 @@ const columns = computed(() => [
             component: 'number',
             inWhere: true,
         },
+        cardVisible: true,
     },
     {
         label: t('item.list.size'),
@@ -111,6 +120,7 @@ const columns = computed(() => [
             component: 'number',
             inWhere: true,
         },
+        cardVisible: true,
     },
     {
         label: t('item.list.typeName'),
@@ -172,6 +182,7 @@ const columns = computed(() => [
             component: null,
         },
         create: true,
+        cardVisible: true,
     },
     {
         label: t('item.list.origin'),
@@ -197,6 +208,7 @@ const columns = computed(() => [
             component: null,
         },
         create: true,
+        cardVisible: true,
     },
     {
         label: t('item.list.userName'),
@@ -270,13 +282,14 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('Clone item'),
+                title: t('globals.clone'),
+
                 icon: 'vn:clone',
-                action: cloneItem,
+                action: openCloneDialog,
                 isPrimary: true,
             },
             {
-                title: t('view Summary'),
+                title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
                 action: (row) => viewSummary(row.id, ItemSummary),
                 isPrimary: true,
@@ -285,21 +298,34 @@ const columns = computed(() => [
     },
 ]);
 
-const cloneItem = async (itemFk) => {
+const cloneItem = async () => {
     try {
-        const { data } = await axios.post(`Items/${itemFk.id}/clone`);
-        if (!data) return;
+        const { data } = await axios.post(`Items/${entityId.value}/clone`);
         router.push({ name: 'ItemTags', params: { id: data.id } });
     } catch (err) {
-        console.error('Error cloning item', err);
+        console.error('Error cloning item');
     }
 };
+
+const openCloneDialog = async () => {
+    quasar
+        .dialog({
+            component: VnConfirm,
+            componentProps: {
+                title: t('All its properties will be copied'),
+                message: t('Do you want to clone this item?'),
+            },
+        })
+        .onOk(async () => {
+            await cloneItem();
+        });
+};
 </script>
 
 <template>
     <VnSearchbar
         data-key="ItemList"
-        :label="t('Search Item')"
+        :label="t('item.searchbar.label')"
         :info="t('You can search by id')"
     />
     <VnTable
@@ -309,19 +335,25 @@ const cloneItem = async (itemFk) => {
         url-create="Items"
         :create="{
             urlCreate: 'Items',
-            title: 'Create Item',
+            title: t('Create Item'),
             onDataSaved: () => tableRef.redirect(),
             formInitialData: {
                 editorFk: entityId,
             },
         }"
-        order="id ASC"
+        :order="['isActive DESC', 'name', 'id']"
         :columns="columns"
         auto-load
         redirect="Item"
         :is-editable="false"
         :filer="itemFilter"
     >
+        <template #column-id="{ row }">
+            <span class="link" @click.stop>
+                {{ row.id }}
+                <ItemDescriptorProxy :id="row.id" />
+            </span>
+        </template>
         <template #column-userName="{ row }">
             <span class="link" @click.stop>
                 {{ row.userName }}
@@ -349,7 +381,8 @@ const cloneItem = async (itemFk) => {
 <i18n>
 es:
     New item: Nuevo artículo
-    All it's properties will be copied: Todas sus propiedades serán copiadas
+    All its properties will be copied: Todas sus propiedades serán copiadas
     Do you want to clone this item?: ¿Desea clonar este artículo?
     Preview: Vista previa
+    Regularize stock: Regularizar stock
 </i18n>

From d6b8d41b6c4cf5144018754d8bc7cdee1e73f5ba Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Tue, 22 Oct 2024 12:09:19 +0200
Subject: [PATCH 45/87] fix: refs #7283 #7283 ItemSummary bugs

---
 src/pages/Item/Card/ItemSummary.vue | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/pages/Item/Card/ItemSummary.vue b/src/pages/Item/Card/ItemSummary.vue
index 7b6015c30..071203038 100644
--- a/src/pages/Item/Card/ItemSummary.vue
+++ b/src/pages/Item/Card/ItemSummary.vue
@@ -135,7 +135,7 @@ const getUrl = (id, param) => `#/Item/${id}/${param}`;
                 <VnLv
                     v-for="(tax, index) in item.taxes"
                     :key="index"
-                    :label="tax.country.country"
+                    :label="tax.country.name"
                     :value="tax.taxClass.description"
                 />
             </QCard>
@@ -155,7 +155,8 @@ const getUrl = (id, param) => `#/Item/${id}/${param}`;
                     :url="getUrl(entityId, 'barcode')"
                     :text="t('item.summary.barcode')"
                 />
-                <p
+                <div
+                    class="text-bold"
                     v-for="(barcode, index) in item.itemBarcode"
                     :key="index"
                     v-text="barcode.code"

From fff3310658db3eb3a80d8a259e94ac57a02a3d48 Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Tue, 22 Oct 2024 12:09:32 +0200
Subject: [PATCH 46/87] fix: refs #7283 tooltips !Item

---
 src/pages/Account/AccountList.vue       | 2 +-
 src/pages/Account/Role/AccountRoles.vue | 2 +-
 src/pages/Route/RouteAutonomous.vue     | 2 +-
 src/pages/Route/RouteExtendedList.vue   | 2 +-
 src/pages/Ticket/TicketList.vue         | 2 +-
 src/pages/Zone/ZoneList.vue             | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/pages/Account/AccountList.vue b/src/pages/Account/AccountList.vue
index 72c445fa9..9e7f1b10a 100644
--- a/src/pages/Account/AccountList.vue
+++ b/src/pages/Account/AccountList.vue
@@ -74,7 +74,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('View Summary'),
+                title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
                 action: (row) => viewSummary(row.id, AccountSummary),
                 isPrimary: true,
diff --git a/src/pages/Account/Role/AccountRoles.vue b/src/pages/Account/Role/AccountRoles.vue
index ea175d913..5398485e3 100644
--- a/src/pages/Account/Role/AccountRoles.vue
+++ b/src/pages/Account/Role/AccountRoles.vue
@@ -54,7 +54,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('View Summary'),
+                title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
                 action: (row) => viewSummary(row.id, RoleSummary),
                 isPrimary: true,
diff --git a/src/pages/Route/RouteAutonomous.vue b/src/pages/Route/RouteAutonomous.vue
index 5ad349942..4a691dbef 100644
--- a/src/pages/Route/RouteAutonomous.vue
+++ b/src/pages/Route/RouteAutonomous.vue
@@ -126,7 +126,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('Preview'),
+                title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
                 isPrimary: true,
                 action: (row) => viewSummary(row?.routeFk, RouteSummary),
diff --git a/src/pages/Route/RouteExtendedList.vue b/src/pages/Route/RouteExtendedList.vue
index 51da4ec12..dbf646935 100644
--- a/src/pages/Route/RouteExtendedList.vue
+++ b/src/pages/Route/RouteExtendedList.vue
@@ -204,7 +204,7 @@ const columns = computed(() => [
                 isPrimary: true,
             },
             {
-                title: t('route.components.smartCard.viewSummary'),
+                title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
                 action: (row) => viewSummary(row?.id, RouteSummary),
                 isPrimary: true,
diff --git a/src/pages/Ticket/TicketList.vue b/src/pages/Ticket/TicketList.vue
index ad97e75c1..272d3a666 100644
--- a/src/pages/Ticket/TicketList.vue
+++ b/src/pages/Ticket/TicketList.vue
@@ -202,7 +202,7 @@ const columns = computed(() => [
                 action: (row) => redirectToLines(row.id),
             },
             {
-                title: t('ticketList.summary'),
+                title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
                 isPrimary: true,
                 action: (row) => viewSummary(row.id, TicketSummary),
diff --git a/src/pages/Zone/ZoneList.vue b/src/pages/Zone/ZoneList.vue
index d160ea6b5..89f2dd42c 100644
--- a/src/pages/Zone/ZoneList.vue
+++ b/src/pages/Zone/ZoneList.vue
@@ -103,7 +103,7 @@ const columns = computed(() => [
         name: 'tableActions',
         actions: [
             {
-                title: t('list.zoneSummary'),
+                title: t('components.smartCard.viewSummary'),
                 icon: 'preview',
                 action: (row) => viewSummary(row.id, ZoneSummary),
                 isPrimary: true,

From 49c0d64c07e27e2c469499d85dacba8a611184e3 Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Tue, 22 Oct 2024 12:13:43 +0200
Subject: [PATCH 47/87] fix: refs #7283 #7283 ItemSummary bugs

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

diff --git a/src/pages/Item/Card/ItemSummary.vue b/src/pages/Item/Card/ItemSummary.vue
index 071203038..6ad09ac64 100644
--- a/src/pages/Item/Card/ItemSummary.vue
+++ b/src/pages/Item/Card/ItemSummary.vue
@@ -119,7 +119,7 @@ const getUrl = (id, param) => `#/Item/${id}/${param}`;
                 <VnLv
                     v-for="(tag, index) in tags"
                     :key="index"
-                    :label="`${tag.priority} ${tag.tag.name}`"
+                    :label="`${tag.priority} ${tag.tag.name}:`"
                     :value="tag.value"
                 />
             </QCard>

From 9db1c4f721a3a0d5f3f3a103060a65b78bca4fa4 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 12:29:33 +0200
Subject: [PATCH 48/87] fix: refs #8039 bad tests

---
 src/components/FormModel.vue                     | 3 ---
 test/cypress/integration/outLogin/logout.spec.js | 7 ++++---
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 05f947cf3..9ac2d38a5 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -217,9 +217,6 @@ async function save() {
         updateAndEmit('onDataSaved', formData.value, response?.data);
         if ($props.reload) await arrayData.fetch({});
         hasChanges.value = false;
-    } catch (err) {
-        console.error(err);
-        notify('errors.writeRequest', 'negative');
     } finally {
         isLoading.value = false;
     }
diff --git a/test/cypress/integration/outLogin/logout.spec.js b/test/cypress/integration/outLogin/logout.spec.js
index 423189908..8d4e90aac 100644
--- a/test/cypress/integration/outLogin/logout.spec.js
+++ b/test/cypress/integration/outLogin/logout.spec.js
@@ -13,7 +13,7 @@ describe('Logout', () => {
     });
     describe('not user', () => {
         beforeEach(() => {
-            cy.intercept('GET', '**/VnUsers/acl', {
+            cy.intercept('GET', '**DefaultViewConfigs**', {
                 statusCode: 401,
                 body: {
                     error: {
@@ -24,10 +24,11 @@ describe('Logout', () => {
                     },
                 },
                 statusMessage: 'AUTHORIZATION_REQUIRED',
-            }).as('someRoute');
+            });
         });
+
         it('when token not exists', () => {
-            cy.reload();
+            cy.get('.q-list > [href="#/item"]').click();
             cy.get('.q-notification__message').should(
                 'have.text',
                 'Authorization Required'

From a732ec05fbe6ba834d46c8eaf3d348c9dbcc0b01 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 13:21:16 +0200
Subject: [PATCH 49/87] test: refs #8039 add hasNotify and, refactor:
 agencyWorkCenter test

---
 src/components/FormModelPopup.vue             |  2 ++
 .../route/agency/agencyWorkCenter.spec.js     | 33 +++++++------------
 test/cypress/support/commands.js              | 11 +++++++
 3 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/src/components/FormModelPopup.vue b/src/components/FormModelPopup.vue
index 118c8f5f4..d91f07535 100644
--- a/src/components/FormModelPopup.vue
+++ b/src/components/FormModelPopup.vue
@@ -61,6 +61,7 @@ defineExpose({
                     :loading="isLoading"
                     @click="emit('onDataCanceled')"
                     v-close-popup
+                    data-cy="FormModelPopup_cancel"
                 />
                 <QBtn
                     :label="t('globals.save')"
@@ -70,6 +71,7 @@ defineExpose({
                     class="q-ml-sm"
                     :disabled="isLoading"
                     :loading="isLoading"
+                    data-cy="FormModelPopup_save"
                 />
             </div>
         </template>
diff --git a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
index 353c5805b..6a3cab664 100644
--- a/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
+++ b/test/cypress/integration/route/agency/agencyWorkCenter.spec.js
@@ -7,31 +7,20 @@ describe('AgencyWorkCenter', () => {
     const createButton = '.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon';
     const workCenterCombobox = 'input[role="combobox"]';
 
-    it('assign workCenter', () => {
+    it('check workCenter crud', () => {
+        // create
         cy.get(createButton).click();
         cy.get(workCenterCombobox).type('workCenterOne{enter}');
-        cy.get('.q-notification__message').should('have.text', 'Data created');
-    });
+        cy.hasNotify('Data created');
 
-    it('delete workCenter', () => {
+        // expect error when duplicate
+        cy.get(createButton).click();
+        cy.get('[data-cy="FormModelPopup_save"]').click();
+        cy.hasNotify('This workCenter is already assigned to this agency');
+        cy.get('[data-cy="FormModelPopup_cancel"]').click();
+
+        // delete
         cy.get('.q-item__section--side > .q-btn > .q-btn__content > .q-icon').click();
-        cy.get('.q-notification__message').should(
-            'have.text',
-            'WorkCenter removed successfully'
-        );
-    });
-
-    it('error on duplicate workCenter', () => {
-        cy.get(createButton).click();
-        cy.get(workCenterCombobox).type('workCenterOne{enter}');
-        cy.get('.q-notification__message').should('have.text', 'Data created');
-        cy.get(createButton).click();
-        cy.get(
-            '.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
-        ).type('workCenterOne{enter}');
-
-        cy.get(
-            ':nth-child(2) > .q-notification__wrapper > .q-notification__content > .q-notification__message'
-        ).should('have.text', 'This workCenter is already assigned to this agency');
+        cy.hasNotify('WorkCenter removed successfully');
     });
 });
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 83f45b721..c7b36cd3a 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -254,3 +254,14 @@ Cypress.Commands.add('openUserPanel', () => {
         '.column > .q-avatar > .q-avatar__content > .q-img > .q-img__container > .q-img__image'
     ).click();
 });
+
+Cypress.Commands.add('hasNotify', (text) => {
+    //last
+    cy.get('.q-notification')
+        .should('be.visible')
+        .last()
+        .then(($lastNotification) => {
+            if (!Cypress.$($lastNotification).text().includes(text))
+                throw new Error(`Notification not found: "${text}"`);
+        });
+});

From f751408de2bfc1e34e6294f294de7365dd699a07 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Tue, 22 Oct 2024 13:22:43 +0200
Subject: [PATCH 50/87] feat: refs #8083 add change state btn

---
 src/components/VnTable/VnTable.vue            |   3 +
 src/components/common/VnBtnSelect.vue         |  19 +
 src/i18n/locale/en.yml                        |   2 +-
 src/i18n/locale/es.yml                        |   2 +-
 src/pages/Claim/Card/ClaimSummary.vue         |   2 +-
 src/pages/Ticket/Card/TicketExpedition.vue    | 338 +++++++-----------
 src/pages/Ticket/Card/TicketSummary.vue       |   2 +-
 .../ticket/ticketExpedition.spec.js           |  28 ++
 test/cypress/support/commands.js              |   8 +
 9 files changed, 190 insertions(+), 214 deletions(-)
 create mode 100644 src/components/common/VnBtnSelect.vue
 create mode 100644 test/cypress/integration/ticket/ticketExpedition.spec.js

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index f18892a31..9d64591e9 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -127,6 +127,7 @@ const splittedColumns = ref({ columns: [] });
 const columnsVisibilitySkipped = ref();
 const createForm = ref();
 const tableFilterRef = ref([]);
+const tableRef = ref();
 
 const tableModes = [
     {
@@ -308,6 +309,7 @@ defineExpose({
     selected,
     CrudModelRef,
     params,
+    tableRef,
 });
 
 function handleOnDataSaved(_) {
@@ -398,6 +400,7 @@ function handleOnDataSaved(_) {
         </template>
         <template #body="{ rows }">
             <QTable
+                ref="tableRef"
                 v-bind="table"
                 class="vnTable"
                 :columns="splittedColumns.columns"
diff --git a/src/components/common/VnBtnSelect.vue b/src/components/common/VnBtnSelect.vue
new file mode 100644
index 000000000..b0616a6b2
--- /dev/null
+++ b/src/components/common/VnBtnSelect.vue
@@ -0,0 +1,19 @@
+<script setup>
+import VnSelect from './VnSelect.vue';
+
+defineProps({
+    selectProps: { type: Object, required: true },
+    promise: { type: Function, default: () => {} },
+});
+</script>
+<template>
+    <QBtnDropdown v-bind="$attrs" color="primary">
+        <VnSelect
+            v-bind="selectProps"
+            hide-selected
+            hide-dropdown-icon
+            focus-on-mount
+            @update:model-value="promise"
+        />
+    </QBtnDropdown>
+</template>
diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index 7eb3829fe..33ecb4850 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -296,6 +296,7 @@ globals:
         from: From
         To: To
         stateFk: State
+    changeState: Change state
 errors:
     statusUnauthorized: Access denied
     statusInternalServerError: An internal server error has ocurred
@@ -538,7 +539,6 @@ ticket:
         package: Package
         taxClass: Tax class
         services: Services
-        changeState: Change state
         requester: Requester
         atender: Atender
         request: Request
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 9d5cd53f3..f8a796116 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -300,6 +300,7 @@ globals:
         from: Desde
         To: Hasta
         stateFk: Estado
+    changeState: Cambiar estado
 errors:
     statusUnauthorized: Acceso denegado
     statusInternalServerError: Ha ocurrido un error interno del servidor
@@ -547,7 +548,6 @@ ticket:
         package: Embalaje
         taxClass: Tipo IVA
         services: Servicios
-        changeState: Cambiar estado
         requester: Solicitante
         atender: Comprador
         request: Petición de compra
diff --git a/src/pages/Claim/Card/ClaimSummary.vue b/src/pages/Claim/Card/ClaimSummary.vue
index d77f718c6..edfa52b4b 100644
--- a/src/pages/Claim/Card/ClaimSummary.vue
+++ b/src/pages/Claim/Card/ClaimSummary.vue
@@ -204,7 +204,7 @@ function claimUrl(section) {
                 top
                 color="black"
                 text-color="white"
-                :label="t('ticket.summary.changeState')"
+                :label="t('globals.changeState')"
             >
                 <QList>
                     <QVirtualScroll
diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index c4ab63b39..987862c22 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -1,39 +1,38 @@
 <script setup>
-import { onMounted, ref, computed, onUnmounted, reactive, watch } from 'vue';
+import { onMounted, ref, computed, onUnmounted, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
 
-import VnInput from 'src/components/common/VnInput.vue';
 import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
-import TicketEditManaProxy from './TicketEditMana.vue';
-import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import ExpeditionNewTicket from './ExpeditionNewTicket.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
 
 import { useStateStore } from 'stores/useStateStore';
-import { toCurrency, toPercentage } from 'src/filters';
 import { useArrayData } from 'composables/useArrayData';
 import { useVnConfirm } from 'composables/useVnConfirm';
 import useNotify from 'src/composables/useNotify.js';
 import { toDateTimeFormat } from 'src/filters/date';
 import axios from 'axios';
+import VnTable from 'src/components/VnTable/VnTable.vue';
+import VnBtnSelect from 'src/components/common/VnBtnSelect.vue';
+import FetchData from 'src/components/FetchData.vue';
 
 const route = useRoute();
 const stateStore = useStateStore();
 const { t } = useI18n();
 const { notify } = useNotify();
 const { openConfirmationModal } = useVnConfirm();
-const editPriceProxyRef = ref(null);
 const newTicketDialogRef = ref(null);
 const logsTableDialogRef = ref(null);
-
+const vnTableRef = ref();
 const expeditionsLogsData = ref([]);
 const selectedExpeditions = ref([]);
 const allColumnNames = ref([]);
-const visibleColumns = ref([]);
 const newTicketWithRoute = ref(false);
+const selectedRows = ref([]);
+const hasSelectedRows = computed(() => selectedRows.value.length > 0);
+const expeditionStateTypes = ref([]);
 
 const exprBuilder = (param, value) => {
     switch (param) {
@@ -54,8 +53,6 @@ const expeditionsArrayData = useArrayData('ticketExpeditions', {
     filter: expeditionsFilter.value,
     exprBuilder: exprBuilder,
 });
-const expeditionsStore = expeditionsArrayData.store;
-const ticketExpeditions = computed(() => expeditionsStore.data);
 
 const ticketArrayData = useArrayData('ticketData');
 const ticketStore = ticketArrayData.store;
@@ -73,129 +70,87 @@ watch(
     { immediate: true }
 );
 
-const params = reactive({});
-
-const applyColumnFilter = async (col) => {
-    try {
-        const paramKey = col.columnFilter?.filterParamKey || col.field;
-        params[paramKey] = col.columnFilter.filterValue;
-        await expeditionsArrayData.addFilter({ filter: expeditionsFilter.value, params });
-    } catch (err) {
-        console.error('Error applying column filter', err);
-    }
-};
-
-const getInputEvents = (col) => {
-    return col.columnFilter.type === 'select'
-        ? { 'update:modelValue': () => applyColumnFilter(col) }
-        : {
-              'keyup.enter': () => applyColumnFilter(col),
-          };
-};
-
 const columns = computed(() => [
     {
+        align: 'left',
         label: t('expedition.id'),
         name: 'id',
-        field: 'id',
-        align: 'left',
-        sortable: true,
+        chip: {
+            condition: () => true,
+        },
+        isId: true,
         columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterParamKey: 'expeditionFk',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
+            inWhere: true,
         },
     },
     {
         label: t('expedition.item'),
-        name: 'item',
+        name: 'packagingItemFk',
         align: 'left',
+        cardVisible: true,
         columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterParamKey: 'packageItemName',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
+            inWhere: true,
         },
     },
     {
         label: t('expedition.name'),
-        name: 'name',
-        field: 'packageItemName',
+        name: 'packageItemName',
         align: 'left',
+        isTitle: true,
         columnFilter: {
-            component: VnSelect,
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                url: 'Items',
-                fields: ['id', 'name'],
-                'sort-by': 'name ASC',
-                'option-value': 'id',
-                'option-label': 'name',
-                dense: true,
-            },
+            inWhere: true,
         },
     },
     {
         label: t('expedition.packageType'),
-        name: 'packageType',
-        field: 'freightItemName',
+        name: 'freightItemName',
         align: 'left',
         columnFilter: {
-            component: VnInput,
-            type: 'text',
-            // filterParamKey: 'expeditionFk',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
+            inWhere: true,
         },
     },
     {
         label: t('expedition.counter'),
         name: 'counter',
-        field: 'counter',
         align: 'left',
-        columnFilter: null,
+        columnFilter: {
+            inWhere: true,
+        },
     },
     {
         label: t('expedition.externalId'),
         name: 'externalId',
-        field: 'externalId',
         align: 'left',
-        columnFilter: null,
+        cardVisible: true,
+        columnFilter: {
+            inWhere: true,
+        },
     },
     {
         label: t('expedition.created'),
         name: 'created',
-        field: 'created',
         align: 'left',
-        columnFilter: null,
-        format: (value) => toDateTimeFormat(value),
+        cardVisible: true,
+        format: (row) => toDateTimeFormat(row.created),
     },
     {
         label: t('expedition.state'),
         name: 'state',
-        field: 'state',
         align: 'left',
-        columnFilter: null,
+        cardVisible: true,
+        columnFilter: { inWhere: true },
     },
     {
-        label: '',
-        name: 'history',
-        align: 'left',
-        columnFilter: null,
+        align: 'right',
+        name: 'tableActions',
+        actions: [
+            {
+                title: t('expedition.historyAction'),
+                icon: 'history',
+                isPrimary: true,
+                action: (row) => showLog(row),
+            },
+        ],
     },
 ]);
 
@@ -204,23 +159,29 @@ const logTableColumns = computed(() => [
         label: t('expedition.state'),
         name: 'state',
         field: 'state',
-        align: 'left',
+        align: 'center',
         sortable: true,
     },
     {
         label: t('expedition.name'),
         name: 'name',
-        align: 'name',
+        field: 'name',
+        align: 'center',
         columnFilter: null,
     },
     {
         label: t('expedition.created'),
         name: 'created',
         field: 'created',
-        align: 'left',
-        columnFilter: null,
+        align: 'center',
         format: (value) => toDateTimeFormat(value),
     },
+    {
+        label: t('expedition.isScanned'),
+        name: 'isScanned',
+        field: 'isScanned',
+        align: 'center',
+    },
 ]);
 
 const showNewTicketDialog = (withRoute = false) => {
@@ -255,10 +216,20 @@ const getExpeditionState = async (expedition) => {
             order: ['created DESC'],
         };
 
-        const { data } = await axios.get(`ExpeditionStates/filter`, {
+        const { data: expeditionStates } = await axios.get(`ExpeditionStates/filter`, {
             params: { filter: JSON.stringify(filter) },
         });
-        expeditionsLogsData.value = data;
+        const { data: scannedStates } = await axios.get(`ExpeditionStates`, {
+            params: { filter: JSON.stringify(filter), fields: ['id', 'isScanned'] },
+        });
+
+        expeditionsLogsData.value = expeditionStates.map((state) => {
+            const scannedState = scannedStates.find((s) => s.id === state.id);
+            return {
+                ...state,
+                isScanned: scannedState ? scannedState.isScanned : false,
+            };
+        });
     } catch (error) {
         console.error(error);
     }
@@ -274,22 +245,39 @@ onUnmounted(() => (stateStore.rightDrawer = false));
 </script>
 
 <template>
+    <FetchData
+        url="expeditionStateTypes"
+        @on-fetch="(data) => (expeditionStateTypes = data)"
+        auto-load
+    />
     <VnSubToolbar>
-        <template #st-data>
-            <TableVisibleColumns
-                :all-columns="allColumnNames"
-                table-code="expeditionIndex"
-                labels-traductions-path="expedition"
-                @on-config-saved="visibleColumns = [...$event, 'history']"
-            />
-        </template>
         <template #st-actions>
             <QBtnGroup push class="q-gutter-x-sm" flat>
+                <VnBtnSelect
+                    :disable="!hasSelectedRows"
+                    color="primary"
+                    :label="t('globals.changeState')"
+                    :select-props="{
+                        options: expeditionStateTypes,
+                        optionLabel: 'description',
+                    }"
+                    :promise="
+                        async (stateTypeFk) => {
+                            await vnTableRef.CrudModelRef.saveChanges({
+                                updates: selectedRows.map(({ id }) => ({
+                                    data: { stateTypeFk },
+                                    where: { id },
+                                })),
+                            });
+                            vnTableRef.tableRef.clearSelection();
+                        }
+                    "
+                />
                 <QBtnDropdown
                     ref="btnDropdownRef"
                     color="primary"
                     :label="t('expedition.move')"
-                    :disable="!selectedExpeditions.length"
+                    :disable="!hasSelectedRows"
                 >
                     <template #label>
                         <QTooltip>{{ t('Select lines to see the options') }}</QTooltip>
@@ -322,7 +310,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
                     </QList>
                 </QBtnDropdown>
                 <QBtn
-                    :disable="!selectedExpeditions.length"
+                    :disable="!hasSelectedRows"
                     icon="delete"
                     color="primary"
                     @click="
@@ -332,115 +320,34 @@ onUnmounted(() => (stateStore.rightDrawer = false));
                             deleteExpedition
                         )
                     "
-                />
+                >
+                    <QTooltip>{{ t('expedition.removeExpedition') }}</QTooltip>
+                </QBtn>
             </QBtnGroup>
         </template>
     </VnSubToolbar>
-
-    <QTable
-        :rows="ticketExpeditions"
+    <VnTable
+        ref="vnTableRef"
+        data-key="TicketExpedition"
+        url="Expeditions/filter"
         :columns="columns"
-        row-key="id"
-        :pagination="{ rowsPerPage: 0 }"
-        class="full-width q-mt-md"
-        selection="multiple"
-        v-model:selected="selectedExpeditions"
-        :visible-columns="visibleColumns"
-        :no-data-label="t('globals.noResults')"
+        :filter="expeditionsFilter"
+        v-model:selected="selectedRows"
+        :table="{
+            'row-key': 'id',
+            selection: 'multiple',
+        }"
+        save-url="Expeditions/crud"
+        auto-load
+        order="created DESC"
     >
-        <template #top-row="{ cols }">
-            <QTr>
-                <QTd />
-                <QTd v-for="(col, index) in cols" :key="index" style="max-width: 100px">
-                    <component
-                        :is="col.columnFilter.component"
-                        v-if="col.columnFilter"
-                        v-model="col.columnFilter.filterValue"
-                        v-bind="col.columnFilter.attrs"
-                        v-on="col.columnFilter.event(col)"
-                        dense
-                    />
-                </QTd>
-            </QTr>
-        </template>
-        <template #body-cell-item="{ row }">
-            <QTd auto-width @click.stop>
-                <QBtn flat color="primary">{{ row.packagingItemFk }}</QBtn>
+        <template #column-packagingItemFk="{ row }">
+            <span class="link" @click.stop>
+                {{ row.packagingItemFk }}
                 <ItemDescriptorProxy :id="row.packagingItemFk" />
-            </QTd>
+            </span>
         </template>
-        <template #body-cell-available="{ row }">
-            <QTd @click.stop>
-                <QBadge :color="row.available < 0 ? 'alert' : 'transparent'" dense>
-                    {{ row.available }}
-                </QBadge>
-            </QTd>
-        </template>
-
-        <template #body-cell-price="{ row }">
-            <QTd>
-                <template v-if="isTicketEditable && row.id">
-                    <QBtn flat color="primary" dense @click="onOpenEditPricePopover(row)">
-                        {{ toCurrency(row.price) }}
-                    </QBtn>
-                    <TicketEditManaProxy
-                        ref="editPriceProxyRef"
-                        :mana="mana"
-                        :new-price="getNewPrice"
-                        @save="updatePrice(row)"
-                    >
-                        <VnInput
-                            v-model.number="edit.price"
-                            :label="t('ticketSale.price')"
-                            type="number"
-                        />
-                    </TicketEditManaProxy>
-                </template>
-                <span v-else>{{ toCurrency(row.price) }}</span>
-            </QTd>
-        </template>
-        <template #body-cell-discount="{ row }">
-            <QTd>
-                <template v-if="!isLocked && row.id">
-                    <QBtn
-                        flat
-                        color="primary"
-                        dense
-                        @click="onOpenEditDiscountPopover(row)"
-                    >
-                        {{ toPercentage(row.discount / 100) }}
-                    </QBtn>
-                    <TicketEditManaProxy
-                        :mana="mana"
-                        :new-price="getNewPrice"
-                        @save="changeDiscount(row)"
-                    >
-                        <VnInput
-                            v-model.number="edit.discount"
-                            :label="t('ticketSale.discount')"
-                            type="number"
-                        />
-                    </TicketEditManaProxy>
-                </template>
-                <span v-else>{{ toPercentage(row.discount / 100) }}</span>
-            </QTd>
-        </template>
-        <template #body-cell-history="{ row }">
-            <QTd>
-                <QBtn
-                    @click.stop="showLog(row)"
-                    color="primary"
-                    icon="history"
-                    size="md"
-                    flat
-                >
-                    <QTooltip class="text-no-wrap">
-                        {{ t('expedition.historyAction') }}
-                    </QTooltip>
-                </QBtn>
-            </QTd>
-        </template>
-    </QTable>
+    </VnTable>
     <QDialog ref="newTicketDialogRef" transition-show="scale" transition-hide="scale">
         <ExpeditionNewTicket
             :ticket="ticketData"
@@ -454,12 +361,23 @@ onUnmounted(() => (stateStore.rightDrawer = false));
             data-key="TicketExpeditionLog"
             :rows="expeditionsLogsData"
             :columns="logTableColumns"
-            class="q-pa-sm"
+            class="q-pa-md full-width"
         >
             <template #body-cell-name="{ row }">
-                <QTd auto-width>
-                    <QBtn flat dense color="primary">{{ row.name }}</QBtn>
-                    <WorkerDescriptorProxy :id="row.workerFk" />
+                <QTd style="text-align: center">
+                    <span class="link" @click.stop>
+                        <QBtn flat dense>{{ row.name }}</QBtn>
+                        <WorkerDescriptorProxy :id="row.workerFk" />
+                    </span>
+                </QTd>
+            </template>
+            <template #body-cell-isScanned="{ row }">
+                <QTd style="text-align: center">
+                    <QCheckbox disable v-model="row.isScanned">
+                        {{
+                            row.isScanned === 1 ? t('expedition.yes') : t('expedition.no')
+                        }}
+                    </QCheckbox>
                 </QTd>
             </template>
         </QTable>
diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue
index 1f2a7ca79..358f74af2 100644
--- a/src/pages/Ticket/Card/TicketSummary.vue
+++ b/src/pages/Ticket/Card/TicketSummary.vue
@@ -105,7 +105,7 @@ async function changeState(value) {
                 ref="stateBtnDropdownRef"
                 color="black"
                 text-color="white"
-                :label="t('ticket.summary.changeState')"
+                :label="t('globals.changeState')"
                 :disable="!isEditable()"
             >
                 <VnSelect
diff --git a/test/cypress/integration/ticket/ticketExpedition.spec.js b/test/cypress/integration/ticket/ticketExpedition.spec.js
new file mode 100644
index 000000000..5eb2c1a2a
--- /dev/null
+++ b/test/cypress/integration/ticket/ticketExpedition.spec.js
@@ -0,0 +1,28 @@
+/// <reference types="cypress" />
+
+describe('Ticket expedtion', () => {
+    const tableContent = '.q-table .q-virtual-scroll__content';
+    const stateTd = 'td:nth-child(9)';
+
+    beforeEach(() => {
+        cy.login('developer');
+        cy.viewport(1920, 1080);
+    });
+
+    it('should change the state', () => {
+        cy.visit('#/ticket/1/expedition');
+        cy.intercept('GET', /\/api\/Expeditions\/filter/).as('expeditions');
+        cy.intercept('POST', /\/api\/Expeditions\/crud/).as('crud');
+
+        cy.wait('@expeditions');
+
+        cy.selectRows([1, 2]);
+        cy.get('#subToolbar [aria-controls]:nth-child(1)').click();
+        cy.get('.q-menu .q-item').contains('Perdida').click();
+        cy.wait('@crud');
+
+        cy.get(`${tableContent} tr:nth-child(-n+2) ${stateTd}`).each(($el) => {
+            cy.wrap($el).contains('Perdida');
+        });
+    });
+});
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 43788f59f..f895d7bb3 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -152,6 +152,14 @@ Cypress.Commands.add('notificationHas', (selector, text) => {
     cy.get(selector).should('have.text', text);
 });
 
+Cypress.Commands.add('selectRows', (rows) => {
+    rows.forEach((row) => {
+        cy.get('.q-table .q-virtual-scroll__content tr .q-checkbox__inner')
+            .eq(row - 1)
+            .click();
+    });
+});
+
 Cypress.Commands.add('fillRow', (rowSelector, data) => {
     // Usar el selector proporcionado para obtener la fila deseada
     cy.waitForElement('tbody');

From 2d81cffb3329bb874f32e41b3fe38c2eef6eb55e Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 13:34:20 +0200
Subject: [PATCH 51/87] feat: refs #8039 show duplicate request in local

---
 src/boot/quasar.js | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/boot/quasar.js b/src/boot/quasar.js
index bf5175ee6..7845719fe 100644
--- a/src/boot/quasar.js
+++ b/src/boot/quasar.js
@@ -4,6 +4,7 @@ import mainShortcutMixin from './mainShortcutMixin';
 import keyShortcut from './keyShortcut';
 import useNotify from 'src/composables/useNotify.js';
 import { CanceledError } from 'axios';
+
 const { notify } = useNotify();
 
 export default boot(({ app }) => {
@@ -41,7 +42,11 @@ export default boot(({ app }) => {
         }
 
         console.error(error);
-        if (error instanceof CanceledError) return;
+        if (error instanceof CanceledError) {
+            const env = process.env.NODE_ENV;
+            if (env && env !== 'development') return;
+            message = 'Duplicate request';
+        }
 
         notify(message ?? 'globals.error', 'negative', 'error');
     };

From 0c9c01b6e9f2ea6fa3674301039eed2f6501e65d Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 13:53:01 +0200
Subject: [PATCH 52/87] test: refs #8039 fix ZoneWarehouse e2e

---
 src/pages/Zone/Card/ZoneWarehouses.vue           | 16 ++++------------
 .../worker/workerNotificationsManager.spec.js    |  5 +----
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/src/pages/Zone/Card/ZoneWarehouses.vue b/src/pages/Zone/Card/ZoneWarehouses.vue
index 6b2933224..98e446797 100644
--- a/src/pages/Zone/Card/ZoneWarehouses.vue
+++ b/src/pages/Zone/Card/ZoneWarehouses.vue
@@ -34,21 +34,13 @@ const columns = computed(() => [
 ]);
 
 const deleteWarehouse = async (row) => {
-    try {
-        await axios.delete(`${urlPath.value}/${row.id}`);
-        fetchWarehouses();
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.delete(`${urlPath.value}/${row.id}`);
+    fetchWarehouses();
 };
 
 const createZoneWarehouse = async (ZoneWarehouseFormData) => {
-    try {
-        await axios.post(urlPath.value, ZoneWarehouseFormData);
-        fetchWarehouses();
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.post(urlPath.value, ZoneWarehouseFormData);
+    fetchWarehouses();
 };
 
 watch(
diff --git a/test/cypress/integration/worker/workerNotificationsManager.spec.js b/test/cypress/integration/worker/workerNotificationsManager.spec.js
index ac452c4ff..367287a5a 100644
--- a/test/cypress/integration/worker/workerNotificationsManager.spec.js
+++ b/test/cypress/integration/worker/workerNotificationsManager.spec.js
@@ -17,10 +17,7 @@ describe('WorkerNotificationsManager', () => {
         cy.login('developer');
         cy.visit(`/#/worker/${salesPersonId}/notifications`);
         cy.get(firstAvailableNotification).click();
-        cy.notificationHas(
-            '.q-notification__message',
-            'The notification subscription of this worker cant be modified'
-        );
+        cy.hasNotify('The notification subscription of this worker cant be modified');
     });
 
     it('should active a notification that is yours', () => {

From cd00a3c67f0fe72a4437f3a2eae3e7eae5266ebf Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 13:55:35 +0200
Subject: [PATCH 53/87] test: refs #8039 fix WorkerNotification e2e

---
 src/pages/Worker/Card/WorkerNotificationsManager.vue | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/pages/Worker/Card/WorkerNotificationsManager.vue b/src/pages/Worker/Card/WorkerNotificationsManager.vue
index 731e073cd..53571fb93 100644
--- a/src/pages/Worker/Card/WorkerNotificationsManager.vue
+++ b/src/pages/Worker/Card/WorkerNotificationsManager.vue
@@ -44,8 +44,9 @@ async function toggleNotification(notification) {
                 `worker.notificationsManager.${notification.active ? '' : 'un'}subscribed`
             ),
         });
-    } catch {
+    } catch (e) {
         notification.active = !notification.active;
+        throw e;
     }
 }
 

From dd2dc86eea3d035aa6ee6845a1dd0047fb653db0 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 14:05:15 +0200
Subject: [PATCH 54/87] fix: refs #8039 o not handle unnecessary errors

---
 src/pages/Account/Alias/Card/AliasUsers.vue   |  10 +-
 src/pages/Account/Card/AccountMailAlias.vue   |  20 +--
 src/pages/Account/Role/Card/SubRoles.vue      |  26 +--
 .../Card/BasicData/TicketBasicDataForm.vue    |  28 +--
 .../Card/BasicData/TicketBasicDataView.vue    |  85 ++++-----
 src/pages/Ticket/Card/ExpeditionNewTicket.vue |  32 ++--
 src/pages/Ticket/Card/TicketComponents.vue    |  26 +--
 src/pages/Ticket/Card/TicketExpedition.vue    |  58 +++----
 .../Ticket/Card/TicketSaleMoreActions.vue     |  12 +-
 src/pages/Ticket/Card/TicketSaleTracking.vue  | 164 +++++++-----------
 src/pages/Ticket/Card/TicketService.vue       |  52 +++---
 src/pages/Ticket/Card/TicketVolume.vue        |  22 +--
 src/pages/Ticket/TicketAdvanceFilter.vue      |  24 ++-
 src/pages/Ticket/TicketFutureFilter.vue       |  40 ++---
 14 files changed, 228 insertions(+), 371 deletions(-)

diff --git a/src/pages/Account/Alias/Card/AliasUsers.vue b/src/pages/Account/Alias/Card/AliasUsers.vue
index 4a9c449e4..4aad68f1a 100644
--- a/src/pages/Account/Alias/Card/AliasUsers.vue
+++ b/src/pages/Account/Alias/Card/AliasUsers.vue
@@ -46,13 +46,9 @@ const columns = computed(() => [
 ]);
 
 const deleteAlias = async (row) => {
-    try {
-        await axios.delete(`${urlPath.value}/${row.id}`);
-        notify(t('User removed'), 'positive');
-        fetchAliases();
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.delete(`${urlPath.value}/${row.id}`);
+    notify(t('User removed'), 'positive');
+    fetchAliases();
 };
 
 watch(
diff --git a/src/pages/Account/Card/AccountMailAlias.vue b/src/pages/Account/Card/AccountMailAlias.vue
index 15d03c665..8d3bd3b67 100644
--- a/src/pages/Account/Card/AccountMailAlias.vue
+++ b/src/pages/Account/Card/AccountMailAlias.vue
@@ -61,23 +61,15 @@ const fetchAccountExistence = async () => {
 };
 
 const deleteMailAlias = async (row) => {
-    try {
-        await axios.delete(`${urlPath}/${row.id}`);
-        fetchMailAliases();
-        notify(t('Unsubscribed from alias!'), 'positive');
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.delete(`${urlPath}/${row.id}`);
+    fetchMailAliases();
+    notify(t('Unsubscribed from alias!'), 'positive');
 };
 
 const createMailAlias = async (mailAliasFormData) => {
-    try {
-        await axios.post(urlPath, mailAliasFormData);
-        notify(t('Subscribed to alias!'), 'positive');
-        fetchMailAliases();
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.post(urlPath, mailAliasFormData);
+    notify(t('Subscribed to alias!'), 'positive');
+    fetchMailAliases();
 };
 
 const fetchMailAliases = async () => {
diff --git a/src/pages/Account/Role/Card/SubRoles.vue b/src/pages/Account/Role/Card/SubRoles.vue
index d17f96dd8..6cac94667 100644
--- a/src/pages/Account/Role/Card/SubRoles.vue
+++ b/src/pages/Account/Role/Card/SubRoles.vue
@@ -46,29 +46,15 @@ const columns = computed(() => [
 ]);
 
 const deleteSubRole = async (row) => {
-    try {
-        await axios.delete(`${urlPath.value}/${row.id}`);
-        fetchSubRoles();
-        notify(
-            t('Role removed. Changes will take a while to fully propagate.'),
-            'positive'
-        );
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.delete(`${urlPath.value}/${row.id}`);
+    fetchSubRoles();
+    notify(t('Role removed. Changes will take a while to fully propagate.'), 'positive');
 };
 
 const createSubRole = async (subRoleFormData) => {
-    try {
-        await axios.post(urlPath.value, subRoleFormData);
-        notify(
-            t('Role added! Changes will take a while to fully propagate.'),
-            'positive'
-        );
-        fetchSubRoles();
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.post(urlPath.value, subRoleFormData);
+    notify(t('Role added! Changes will take a while to fully propagate.'), 'positive');
+    fetchSubRoles();
 };
 
 watch(
diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
index f5ce8a0f3..f6c20c514 100644
--- a/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
+++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataForm.vue
@@ -112,32 +112,20 @@ const getShipped = async (params) => {
 };
 
 const onChangeZone = async (zoneId) => {
-    try {
-        formData.value.agencyModeFk = null;
-        const { data } = await axios.get(`Zones/${zoneId}`);
-        formData.value.agencyModeFk = data.agencyModeFk;
-    } catch (error) {
-        console.error(error);
-    }
+    formData.value.agencyModeFk = null;
+    const { data } = await axios.get(`Zones/${zoneId}`);
+    formData.value.agencyModeFk = data.agencyModeFk;
 };
 
 const onChangeAddress = async (addressId) => {
-    try {
-        formData.value.nickname = null;
-        const { data } = await axios.get(`Addresses/${addressId}`);
-        formData.value.nickname = data.nickname;
-    } catch (error) {
-        console.error(error);
-    }
+    formData.value.nickname = null;
+    const { data } = await axios.get(`Addresses/${addressId}`);
+    formData.value.nickname = data.nickname;
 };
 
 const getClientDefaultAddress = async (clientId) => {
-    try {
-        const { data } = await axios.get(`Clients/${clientId}`);
-        if (data) addressId.value = data.defaultAddressFk;
-    } catch (error) {
-        console.error(error);
-    }
+    const { data } = await axios.get(`Clients/${clientId}`);
+    if (data) addressId.value = data.defaultAddressFk;
 };
 
 const clientAddressesList = async (value) => {
diff --git a/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue b/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue
index 92640f898..fb7881403 100644
--- a/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue
+++ b/src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue
@@ -70,60 +70,51 @@ const isFormInvalid = () => {
 };
 
 const getPriceDifference = async () => {
-    try {
-        const params = {
-            landed: formData.value.landed,
-            addressId: formData.value.addressFk,
-            agencyModeId: formData.value.agencyModeFk,
-            zoneId: formData.value.zoneFk,
-            warehouseId: formData.value.warehouseFk,
-            shipped: formData.value.shipped,
-        };
-        const { data } = await axios.post(
-            `tickets/${formData.value.id}/priceDifference`,
-            params
-        );
-        formData.value.sale = data;
-    } catch (error) {
-        console.error(error);
-    }
+    const params = {
+        landed: formData.value.landed,
+        addressId: formData.value.addressFk,
+        agencyModeId: formData.value.agencyModeFk,
+        zoneId: formData.value.zoneFk,
+        warehouseId: formData.value.warehouseFk,
+        shipped: formData.value.shipped,
+    };
+    const { data } = await axios.post(
+        `tickets/${formData.value.id}/priceDifference`,
+        params
+    );
+    formData.value.sale = data;
 };
 
 const submit = async () => {
-    try {
-        if (!formData.value.option)
-            return notify(t('basicData.chooseAnOption'), 'negative');
+    if (!formData.value.option) return notify(t('basicData.chooseAnOption'), 'negative');
 
-        const params = {
-            clientFk: formData.value.clientFk,
-            nickname: formData.value.nickname,
-            agencyModeFk: formData.value.agencyModeFk,
-            addressFk: formData.value.addressFk,
-            zoneFk: formData.value.zoneFk,
-            warehouseFk: formData.value.warehouseFk,
-            companyFk: formData.value.companyFk,
-            shipped: formData.value.shipped,
-            landed: formData.value.landed,
-            isDeleted: formData.value.isDeleted,
-            option: formData.value.option,
-            isWithoutNegatives: formData.value.withoutNegatives,
-            withWarningAccept: formData.value.withWarningAccept,
-            keepPrice: false,
-        };
+    const params = {
+        clientFk: formData.value.clientFk,
+        nickname: formData.value.nickname,
+        agencyModeFk: formData.value.agencyModeFk,
+        addressFk: formData.value.addressFk,
+        zoneFk: formData.value.zoneFk,
+        warehouseFk: formData.value.warehouseFk,
+        companyFk: formData.value.companyFk,
+        shipped: formData.value.shipped,
+        landed: formData.value.landed,
+        isDeleted: formData.value.isDeleted,
+        option: formData.value.option,
+        isWithoutNegatives: formData.value.withoutNegatives,
+        withWarningAccept: formData.value.withWarningAccept,
+        keepPrice: false,
+    };
 
-        const { data } = await axios.post(
-            `tickets/${formData.value.id}/componentUpdate`,
-            params
-        );
+    const { data } = await axios.post(
+        `tickets/${formData.value.id}/componentUpdate`,
+        params
+    );
 
-        if (!data) return;
+    if (!data) return;
 
-        const ticketToMove = data.id;
-        notify(t('basicData.unroutedTicket'), 'positive');
-        router.push({ name: 'TicketSummary', params: { id: ticketToMove } });
-    } catch (error) {
-        console.error(error);
-    }
+    const ticketToMove = data.id;
+    notify(t('basicData.unroutedTicket'), 'positive');
+    router.push({ name: 'TicketSummary', params: { id: ticketToMove } });
 };
 
 const submitWithNegatives = async () => {
diff --git a/src/pages/Ticket/Card/ExpeditionNewTicket.vue b/src/pages/Ticket/Card/ExpeditionNewTicket.vue
index 9183ae405..c288f6cc2 100644
--- a/src/pages/Ticket/Card/ExpeditionNewTicket.vue
+++ b/src/pages/Ticket/Card/ExpeditionNewTicket.vue
@@ -34,26 +34,20 @@ const newTicketFormData = reactive({});
 const date = new Date();
 
 const createTicket = async () => {
-    try {
-        const expeditionIds = $props.selectedExpeditions.map(
-            (expedition) => expedition.id
-        );
-        const params = {
-            clientId: $props.ticket.clientFk,
-            landed: newTicketFormData.landed,
-            warehouseId: $props.ticket.warehouseFk,
-            addressId: $props.ticket.addressFk,
-            agencyModeId: $props.ticket.agencyModeFk,
-            routeId: newTicketFormData.routeFk,
-            expeditionIds: expeditionIds,
-        };
+    const expeditionIds = $props.selectedExpeditions.map((expedition) => expedition.id);
+    const params = {
+        clientId: $props.ticket.clientFk,
+        landed: newTicketFormData.landed,
+        warehouseId: $props.ticket.warehouseFk,
+        addressId: $props.ticket.addressFk,
+        agencyModeId: $props.ticket.agencyModeFk,
+        routeId: newTicketFormData.routeFk,
+        expeditionIds: expeditionIds,
+    };
 
-        const { data } = await axios.post('Expeditions/moveExpeditions', params);
-        notify(t('globals.dataSaved'), 'positive');
-        router.push({ name: 'TicketSummary', params: { id: data.id } });
-    } catch (error) {
-        console.error(error);
-    }
+    const { data } = await axios.post('Expeditions/moveExpeditions', params);
+    notify(t('globals.dataSaved'), 'positive');
+    router.push({ name: 'TicketSummary', params: { id: data.id } });
 };
 </script>
 
diff --git a/src/pages/Ticket/Card/TicketComponents.vue b/src/pages/Ticket/Card/TicketComponents.vue
index 0bccdaacd..b5b3c430c 100644
--- a/src/pages/Ticket/Card/TicketComponents.vue
+++ b/src/pages/Ticket/Card/TicketComponents.vue
@@ -150,31 +150,19 @@ const getTotal = computed(() => {
 });
 
 const getComponentsSum = async () => {
-    try {
-        const { data } = await axios.get(`Tickets/${route.params.id}/getComponentsSum`);
-        componentsList.value = data;
-    } catch (error) {
-        console.error(error);
-    }
+    const { data } = await axios.get(`Tickets/${route.params.id}/getComponentsSum`);
+    componentsList.value = data;
 };
 
 const getTheoricalCost = async () => {
-    try {
-        const { data } = await axios.get(`Tickets/${route.params.id}/freightCost`);
-        theoricalCost.value = data;
-    } catch (error) {
-        console.error(error);
-    }
+    const { data } = await axios.get(`Tickets/${route.params.id}/freightCost`);
+    theoricalCost.value = data;
 };
 
 const getTicketVolume = async () => {
-    try {
-        if (!ticketData.value) return;
-        const { data } = await axios.get(`Tickets/${ticketData.value.id}/getVolume`);
-        ticketVolume.value = data[0].volume;
-    } catch (error) {
-        console.error(error);
-    }
+    if (!ticketData.value) return;
+    const { data } = await axios.get(`Tickets/${ticketData.value.id}/getVolume`);
+    ticketVolume.value = data[0].volume;
 };
 
 onMounted(() => {
diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 4becb3db3..b4a2ca732 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -187,18 +187,12 @@ const showNewTicketDialog = (withRoute = false) => {
 };
 
 const deleteExpedition = async () => {
-    try {
-        const expeditionIds = selectedExpeditions.value.map(
-            (expedition) => expedition.id
-        );
-        const params = { expeditionIds };
-        await axios.post('Expeditions/deleteExpeditions', params);
-        await refetchExpeditions();
-        selectedExpeditions.value = [];
-        notify(t('expedition.expeditionRemoved'), 'positive');
-    } catch (error) {
-        console.error(error);
-    }
+    const expeditionIds = selectedExpeditions.value.map((expedition) => expedition.id);
+    const params = { expeditionIds };
+    await axios.post('Expeditions/deleteExpeditions', params);
+    await refetchExpeditions();
+    selectedExpeditions.value = [];
+    notify(t('expedition.expeditionRemoved'), 'positive');
 };
 
 const showLog = async (expedition) => {
@@ -207,29 +201,25 @@ const showLog = async (expedition) => {
 };
 
 const getExpeditionState = async (expedition) => {
-    try {
-        const filter = {
-            where: { expeditionFk: expedition.id },
-            order: ['created DESC'],
+    const filter = {
+        where: { expeditionFk: expedition.id },
+        order: ['created DESC'],
+    };
+
+    const { data: expeditionStates } = await axios.get(`ExpeditionStates/filter`, {
+        params: { filter: JSON.stringify(filter) },
+    });
+    const { data: scannedStates } = await axios.get(`ExpeditionStates`, {
+        params: { filter: JSON.stringify(filter), fields: ['id', 'isScanned'] },
+    });
+
+    expeditionsLogsData.value = expeditionStates.map((state) => {
+        const scannedState = scannedStates.find((s) => s.id === state.id);
+        return {
+            ...state,
+            isScanned: scannedState ? scannedState.isScanned : false,
         };
-
-        const { data: expeditionStates } = await axios.get(`ExpeditionStates/filter`, {
-            params: { filter: JSON.stringify(filter) },
-        });
-        const { data: scannedStates } = await axios.get(`ExpeditionStates`, {
-            params: { filter: JSON.stringify(filter), fields: ['id', 'isScanned'] },
-        });
-
-        expeditionsLogsData.value = expeditionStates.map((state) => {
-            const scannedState = scannedStates.find((s) => s.id === state.id);
-            return {
-                ...state,
-                isScanned: scannedState ? scannedState.isScanned : false,
-            };
-        });
-    } catch (error) {
-        console.error(error);
-    }
+    });
 };
 
 onMounted(async () => {
diff --git a/src/pages/Ticket/Card/TicketSaleMoreActions.vue b/src/pages/Ticket/Card/TicketSaleMoreActions.vue
index 2ec519d2d..588f78a7b 100644
--- a/src/pages/Ticket/Card/TicketSaleMoreActions.vue
+++ b/src/pages/Ticket/Card/TicketSaleMoreActions.vue
@@ -165,14 +165,10 @@ const createRefund = async (withWarehouse) => {
         negative: true,
     };
 
-    try {
-        const { data } = await axios.post('Tickets/cloneAll', params);
-        const [refundTicket] = data;
-        notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
-        push({ name: 'TicketSale', params: { id: refundTicket.id } });
-    } catch (error) {
-        console.error(error);
-    }
+    const { data } = await axios.post('Tickets/cloneAll', params);
+    const [refundTicket] = data;
+    notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
+    push({ name: 'TicketSale', params: { id: refundTicket.id } });
 };
 </script>
 
diff --git a/src/pages/Ticket/Card/TicketSaleTracking.vue b/src/pages/Ticket/Card/TicketSaleTracking.vue
index e7830bf37..1083393c4 100644
--- a/src/pages/Ticket/Card/TicketSaleTracking.vue
+++ b/src/pages/Ticket/Card/TicketSaleTracking.vue
@@ -150,18 +150,14 @@ const shelvingsTableColumns = computed(() => [
 ]);
 
 const getSaleTrackings = async (sale) => {
-    try {
-        const filter = {
-            where: { saleFk: sale.saleFk },
-            order: ['itemFk DESC'],
-        };
-        const { data } = await axios.get(`SaleTrackings/listSaleTracking`, {
-            params: { filter: JSON.stringify(filter) },
-        });
-        saleTrackings.value = data;
-    } catch (error) {
-        console.error(error);
-    }
+    const filter = {
+        where: { saleFk: sale.saleFk },
+        order: ['itemFk DESC'],
+    };
+    const { data } = await axios.get(`SaleTrackings/listSaleTracking`, {
+        params: { filter: JSON.stringify(filter) },
+    });
+    saleTrackings.value = data;
 };
 
 const showLog = async (sale) => {
@@ -170,17 +166,13 @@ const showLog = async (sale) => {
 };
 
 const getItemShelvingSales = async (sale) => {
-    try {
-        const filter = {
-            where: { saleFk: sale.saleFk },
-        };
-        const { data } = await axios.get(`ItemShelvingSales/filter`, {
-            params: { filter: JSON.stringify(filter) },
-        });
-        itemShelvingsSales.value = data;
-    } catch (error) {
-        console.error(error);
-    }
+    const filter = {
+        where: { saleFk: sale.saleFk },
+    };
+    const { data } = await axios.get(`ItemShelvingSales/filter`, {
+        params: { filter: JSON.stringify(filter) },
+    });
+    itemShelvingsSales.value = data;
 };
 
 const showShelving = async (sale) => {
@@ -189,36 +181,28 @@ const showShelving = async (sale) => {
 };
 
 const updateQuantity = async (sale) => {
-    try {
-        if (oldQuantity.value === sale.quantity) return;
-        const params = {
-            quantity: sale.quantity,
-        };
-        await axios.patch(`ItemShelvingSales/${sale.id}`, params);
-        oldQuantity.value = null;
-    } catch (error) {
-        console.error(error);
-    }
+    if (oldQuantity.value === sale.quantity) return;
+    const params = {
+        quantity: sale.quantity,
+    };
+    await axios.patch(`ItemShelvingSales/${sale.id}`, params);
+    oldQuantity.value = null;
 };
 
 const updateParking = async (sale) => {
-    try {
-        const filter = {
-            fields: ['id'],
-            where: {
-                code: sale.shelvingFk,
-            },
-        };
-        const { data } = await axios.get(`Shelvings/findOne`, {
-            params: { filter: JSON.stringify(filter) },
-        });
-        const params = {
-            parkingFk: sale.parkingFk,
-        };
-        await axios.patch(`Shelvings/${data.id}`, params);
-    } catch (error) {
-        console.error(error);
-    }
+    const filter = {
+        fields: ['id'],
+        where: {
+            code: sale.shelvingFk,
+        },
+    };
+    const { data } = await axios.get(`Shelvings/findOne`, {
+        params: { filter: JSON.stringify(filter) },
+    });
+    const params = {
+        parkingFk: sale.parkingFk,
+    };
+    await axios.patch(`Shelvings/${data.id}`, params);
 };
 
 const updateShelving = async (sale) => {
@@ -241,61 +225,41 @@ const updateShelving = async (sale) => {
 };
 
 const saleTrackingNew = async (sale, stateCode, isChecked) => {
-    try {
-        const params = {
-            saleFk: sale.saleFk,
-            isChecked,
-            quantity: sale.quantity,
-            stateCode,
-        };
-        await axios.post(`SaleTrackings/new`, params);
-        notify(t('globals.dataSaved'), 'positive');
-    } catch (error) {
-        console.error(error);
-    }
+    const params = {
+        saleFk: sale.saleFk,
+        isChecked,
+        quantity: sale.quantity,
+        stateCode,
+    };
+    await axios.post(`SaleTrackings/new`, params);
+    notify(t('globals.dataSaved'), 'positive');
 };
 
 const saleTrackingDel = async ({ saleFk }, stateCode) => {
-    try {
-        const params = {
-            saleFk,
-            stateCodes: [stateCode],
-        };
-        await axios.post(`SaleTrackings/delete`, params);
-        notify(t('globals.dataSaved'), 'positive');
-    } catch (error) {
-        console.error(error);
-    }
+    const params = {
+        saleFk,
+        stateCodes: [stateCode],
+    };
+    await axios.post(`SaleTrackings/delete`, params);
+    notify(t('globals.dataSaved'), 'positive');
 };
 
 const clickSaleGroupDetail = async (sale) => {
-    try {
-        if (!sale.saleGroupDetailFk) return;
+    if (!sale.saleGroupDetailFk) return;
 
-        await axios.delete(`SaleGroupDetails/${sale.saleGroupDetailFk}`);
-        sale.hasSaleGroupDetail = false;
-        notify(t('globals.dataSaved'), 'positive');
-    } catch (error) {
-        console.error(error);
-    }
+    await axios.delete(`SaleGroupDetails/${sale.saleGroupDetailFk}`);
+    sale.hasSaleGroupDetail = false;
+    notify(t('globals.dataSaved'), 'positive');
 };
 
 const clickPreviousSelected = (sale) => {
-    try {
-        qCheckBoxController(sale, 'isPreviousSelected');
-        if (!sale.isPreviousSelected) sale.isPrevious = false;
-    } catch (error) {
-        console.error(error);
-    }
+    qCheckBoxController(sale, 'isPreviousSelected');
+    if (!sale.isPreviousSelected) sale.isPrevious = false;
 };
 
 const clickPrevious = (sale) => {
-    try {
-        qCheckBoxController(sale, 'isPrevious');
-        if (sale.isPrevious) sale.isPreviousSelected = true;
-    } catch (error) {
-        console.error(error);
-    }
+    qCheckBoxController(sale, 'isPrevious');
+    if (sale.isPrevious) sale.isPreviousSelected = true;
 };
 
 const qCheckBoxController = (sale, action) => {
@@ -306,16 +270,12 @@ const qCheckBoxController = (sale, action) => {
         isPreviousSelected: 'PREVIOUS_PREPARATION',
     };
     const stateCode = STATE_CODES[action];
-    try {
-        if (!sale[action]) {
-            saleTrackingNew(sale, stateCode, true);
-            sale[action] = true;
-        } else {
-            saleTrackingDel(sale, stateCode);
-            sale[action] = false;
-        }
-    } catch (error) {
-        console.error(error);
+    if (!sale[action]) {
+        saleTrackingNew(sale, stateCode, true);
+        sale[action] = true;
+    } else {
+        saleTrackingDel(sale, stateCode);
+        sale[action] = false;
     }
 };
 </script>
diff --git a/src/pages/Ticket/Card/TicketService.vue b/src/pages/Ticket/Card/TicketService.vue
index 45a870f7f..47c28a422 100644
--- a/src/pages/Ticket/Card/TicketService.vue
+++ b/src/pages/Ticket/Card/TicketService.vue
@@ -46,40 +46,32 @@ watch(
 onMounted(async () => await getDefaultTaxClass());
 
 const createRefund = async () => {
-    try {
-        if (!selected.value.length) return;
+    if (!selected.value.length) return;
 
-        const params = {
-            servicesIds: selected.value.map((s) => +s.id),
-            withWarehouse: false,
-            negative: true,
-        };
-        const { data } = await axios.post('Sales/clone', params);
-        const [refundTicket] = data;
-        notify(
-            t('service.createRefundSuccess', {
-                ticketId: refundTicket.id,
-            }),
-            'positive'
-        );
-        router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
-    } catch (error) {
-        console.error(error);
-    }
+    const params = {
+        servicesIds: selected.value.map((s) => +s.id),
+        withWarehouse: false,
+        negative: true,
+    };
+    const { data } = await axios.post('Sales/clone', params);
+    const [refundTicket] = data;
+    notify(
+        t('service.createRefundSuccess', {
+            ticketId: refundTicket.id,
+        }),
+        'positive'
+    );
+    router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
 };
 
 const getDefaultTaxClass = async () => {
-    try {
-        let filter = {
-            where: { code: 'G' },
-        };
-        const { data } = await axios.get('TaxClasses/findOne', {
-            params: { filter: JSON.stringify(filter) },
-        });
-        defaultTaxClass.value = data;
-    } catch (error) {
-        console.error(error);
-    }
+    let filter = {
+        where: { code: 'G' },
+    };
+    const { data } = await axios.get('TaxClasses/findOne', {
+        params: { filter: JSON.stringify(filter) },
+    });
+    defaultTaxClass.value = data;
 };
 
 const columns = computed(() => [
diff --git a/src/pages/Ticket/Card/TicketVolume.vue b/src/pages/Ticket/Card/TicketVolume.vue
index 2cf7ffc42..edfe489d9 100644
--- a/src/pages/Ticket/Card/TicketVolume.vue
+++ b/src/pages/Ticket/Card/TicketVolume.vue
@@ -75,22 +75,18 @@ const columns = computed(() => [
 ]);
 
 const applyVolumes = async (salesData) => {
-    try {
-        if (!salesData.length) return;
+    if (!salesData.length) return;
 
-        sales.value = salesData;
-        const ticket = sales.value[0].ticketFk;
-        const { data } = await axios.get(`Tickets/${ticket}/getVolume`);
-        const volumes = new Map(data.saleVolume.map((volume) => [volume.saleFk, volume]));
+    sales.value = salesData;
+    const ticket = sales.value[0].ticketFk;
+    const { data } = await axios.get(`Tickets/${ticket}/getVolume`);
+    const volumes = new Map(data.saleVolume.map((volume) => [volume.saleFk, volume]));
 
-        sales.value.forEach((sale) => {
-            sale.saleVolume = volumes.get(sale.id);
-        });
+    sales.value.forEach((sale) => {
+        sale.saleVolume = volumes.get(sale.id);
+    });
 
-        packingTypeVolume.value = data.packingTypeVolume;
-    } catch (error) {
-        console.error(error);
-    }
+    packingTypeVolume.value = data.packingTypeVolume;
 };
 
 onMounted(() => (stateStore.rightDrawer = true));
diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index b25ebdea6..27cacd80a 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -27,20 +27,16 @@ const warehousesOptions = ref([]);
 const itemPackingTypes = ref([]);
 
 const getItemPackingTypes = async () => {
-    try {
-        const filter = {
-            where: { isActive: true },
-        };
-        const { data } = await axios.get('ItemPackingTypes', {
-            params: { filter: JSON.stringify(filter) },
-        });
-        itemPackingTypes.value = data.map((ipt) => ({
-            description: t(ipt.description),
-            code: ipt.code,
-        }));
-    } catch (error) {
-        console.error(error);
-    }
+    const filter = {
+        where: { isActive: true },
+    };
+    const { data } = await axios.get('ItemPackingTypes', {
+        params: { filter: JSON.stringify(filter) },
+    });
+    itemPackingTypes.value = data.map((ipt) => ({
+        description: t(ipt.description),
+        code: ipt.code,
+    }));
 };
 
 onMounted(async () => await getItemPackingTypes());
diff --git a/src/pages/Ticket/TicketFutureFilter.vue b/src/pages/Ticket/TicketFutureFilter.vue
index 6345f62b3..ffe967272 100644
--- a/src/pages/Ticket/TicketFutureFilter.vue
+++ b/src/pages/Ticket/TicketFutureFilter.vue
@@ -24,33 +24,25 @@ const itemPackingTypes = ref([]);
 const stateOptions = ref([]);
 
 const getItemPackingTypes = async () => {
-    try {
-        const filter = {
-            where: { isActive: true },
-        };
-        const { data } = await axios.get('ItemPackingTypes', {
-            params: { filter: JSON.stringify(filter) },
-        });
-        itemPackingTypes.value = data.map((ipt) => ({
-            description: t(ipt.description),
-            code: ipt.code,
-        }));
-    } catch (error) {
-        console.error(error);
-    }
+    const filter = {
+        where: { isActive: true },
+    };
+    const { data } = await axios.get('ItemPackingTypes', {
+        params: { filter: JSON.stringify(filter) },
+    });
+    itemPackingTypes.value = data.map((ipt) => ({
+        description: t(ipt.description),
+        code: ipt.code,
+    }));
 };
 
 const getGroupedStates = async () => {
-    try {
-        const { data } = await axios.get('AlertLevels');
-        stateOptions.value = data.map((state) => ({
-            id: state.id,
-            name: t(`futureTickets.${state.code}`),
-            code: state.code,
-        }));
-    } catch (error) {
-        console.error(error);
-    }
+    const { data } = await axios.get('AlertLevels');
+    stateOptions.value = data.map((state) => ({
+        id: state.id,
+        name: t(`futureTickets.${state.code}`),
+        code: state.code,
+    }));
 };
 
 onMounted(async () => {

From ee31bc8262d511bc659316d7046b5f9d0228034d Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 14:07:27 +0200
Subject: [PATCH 55/87] chore: refs #8039 not required

---
 src/boot/axios.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/boot/axios.js b/src/boot/axios.js
index b084b835d..aee38e887 100644
--- a/src/boot/axios.js
+++ b/src/boot/axios.js
@@ -3,7 +3,6 @@ import { useSession } from 'src/composables/useSession';
 import { Router } from 'src/router';
 import useNotify from 'src/composables/useNotify.js';
 import { useStateQueryStore } from 'src/stores/useStateQueryStore';
-import { CanceledError } from 'axios';
 
 const session = useSession();
 const { notify } = useNotify();

From b1a511ff6f7aee7fb218e78f909d7b73a4e98ac3 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Tue, 22 Oct 2024 14:21:03 +0200
Subject: [PATCH 56/87] fix: refs #8083 delete btn & redirect

---
 src/pages/Ticket/Card/TicketExpedition.vue | 47 +++++++---------------
 1 file changed, 14 insertions(+), 33 deletions(-)

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 987862c22..61cedc1bf 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { onMounted, ref, computed, onUnmounted, watch } from 'vue';
+import { onMounted, ref, computed, onUnmounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
 
@@ -34,42 +34,15 @@ const selectedRows = ref([]);
 const hasSelectedRows = computed(() => selectedRows.value.length > 0);
 const expeditionStateTypes = ref([]);
 
-const exprBuilder = (param, value) => {
-    switch (param) {
-        case 'expeditionFk':
-            return { id: value };
-        case 'packageItemName':
-            return { packagingItemFk: value };
-    }
-};
-
 const expeditionsFilter = computed(() => ({
     where: { ticketFk: route.params.id },
     order: ['created DESC'],
 }));
 
-const expeditionsArrayData = useArrayData('ticketExpeditions', {
-    url: 'Expeditions/filter',
-    filter: expeditionsFilter.value,
-    exprBuilder: exprBuilder,
-});
-
 const ticketArrayData = useArrayData('ticketData');
 const ticketStore = ticketArrayData.store;
 const ticketData = computed(() => ticketStore.data);
 
-const refetchExpeditions = async () => {
-    await expeditionsArrayData.applyFilter({
-        filter: expeditionsFilter.value,
-    });
-};
-
-watch(
-    () => route.params.id,
-    async () => await refetchExpeditions(),
-    { immediate: true }
-);
-
 const columns = computed(() => [
     {
         align: 'left',
@@ -191,12 +164,10 @@ const showNewTicketDialog = (withRoute = false) => {
 
 const deleteExpedition = async () => {
     try {
-        const expeditionIds = selectedExpeditions.value.map(
-            (expedition) => expedition.id
-        );
+        const expeditionIds = selectedRows.value.map((expedition) => expedition.id);
         const params = { expeditionIds };
         await axios.post('Expeditions/deleteExpeditions', params);
-        await refetchExpeditions();
+        vnTableRef.value.reload();
         selectedExpeditions.value = [];
         notify(t('expedition.expeditionRemoved'), 'positive');
     } catch (error) {
@@ -330,6 +301,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         ref="vnTableRef"
         data-key="TicketExpedition"
         url="Expeditions/filter"
+        search-url="expeditions"
         :columns="columns"
         :filter="expeditionsFilter"
         v-model:selected="selectedRows"
@@ -339,7 +311,16 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         }"
         save-url="Expeditions/crud"
         auto-load
-        order="created DESC"
+        :expr-builder="
+            (param, value) => {
+                switch (param) {
+                    case 'expeditionFk':
+                        return { id: value };
+                    case 'packageItemName':
+                        return { packagingItemFk: value };
+                }
+            }
+        "
     >
         <template #column-packagingItemFk="{ row }">
             <span class="link" @click.stop>

From da4c1e9c12fab1a686df8866d3b8c2e3d41f75af Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Tue, 22 Oct 2024 14:36:30 +0200
Subject: [PATCH 57/87] fix: refs #8083 add order

---
 src/pages/Ticket/Card/TicketExpedition.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 61cedc1bf..307c42645 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -321,6 +321,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
                 }
             }
         "
+        order="created DESC"
     >
         <template #column-packagingItemFk="{ row }">
             <span class="link" @click.stop>

From 033d6bddbee60806a5311f48ad5719639db6e844 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Tue, 22 Oct 2024 14:43:43 +0200
Subject: [PATCH 58/87] fix: refs #8083 move expeditions

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

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 307c42645..93749ebec 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -334,7 +334,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         <ExpeditionNewTicket
             :ticket="ticketData"
             :with-route="newTicketWithRoute"
-            :selected-expeditions="selectedExpeditions"
+            :selected-expeditions="selectedRows"
         />
     </QDialog>
     <QDialog ref="logsTableDialogRef" transition-show="scale" transition-hide="scale">

From 81a55a9e7a9960dcb7f66dac86add05f3d3107f2 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 14:55:47 +0200
Subject: [PATCH 59/87] chore: test gitea

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

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 9d64591e9..9209eaf7b 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -794,6 +794,7 @@ es:
         top: 0;
     }
 }
+
 .vnTable {
     thead tr th {
         position: sticky;

From 735ee09ef8a8d9c46b0e812ba9020dc52813af5d Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Tue, 22 Oct 2024 15:08:20 +0200
Subject: [PATCH 60/87] Merge branch 'master' of
 https://gitea.verdnatura.es/verdnatura/salix-front into test

---
 src/i18n/locale/en.yml | 1 -
 src/i18n/locale/es.yml | 1 -
 2 files changed, 2 deletions(-)

diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index dd0d3292f..aa8df17e2 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -304,7 +304,6 @@ globals:
         from: From
         To: To
         stateFk: State
-        departmentFk: Department
         email: Email
         SSN: SSN
         fi: FI
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 4e67ecdaa..575e2c6c7 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -313,7 +313,6 @@ globals:
         SSN: NSS
         fi: NIF
         myTeam: Mi equipo
-        departmentFk: Departamento
     changePass: Cambiar contraseña
     deleteConfirmTitle: Eliminar los elementos seleccionados
     changeState: Cambiar estado

From ae56c06628010c4197c0b5fa9f858df99711800f Mon Sep 17 00:00:00 2001
From: jgallego <jgallego@verdnatura.es>
Date: Wed, 23 Oct 2024 07:45:00 +0200
Subject: [PATCH 61/87] feat: refs #7349 usa back con permisos

---
 src/pages/Item/ItemRequest.vue                | 23 ++++++++++++++----
 src/pages/Item/ItemTypeCreate.vue             | 24 ++++++++++++++-----
 src/pages/ItemType/Card/ItemTypeBasicData.vue | 22 +++++++++++++----
 3 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 82c3b48e0..25082697d 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -258,15 +258,28 @@ onBeforeMount(() => {
             <template #body-cell-attender="{ row }">
                 <QTd>
                     <VnSelect
+                        url="Workers/search"
                         v-model="row.attenderFk"
-                        :where="{ role: 'buyer' }"
-                        sort-by="id"
-                        url="Workers"
+                        :params="{ departmentCodes: ['shopping'] }"
+                        :fields="['id', 'nickname']"
+                        sort-by="nickname ASC"
                         hide-selected
-                        option-label="firstName"
+                        option-label="nickname"
                         option-value="id"
                         dense
-                    />
+                    >
+                        <template #option="scope">
+                            <QItem v-bind="scope.itemProps">
+                                <QItemSection>
+                                    <QItemLabel>{{ scope.opt?.name }}</QItemLabel>
+                                    <QItemLabel caption
+                                        >{{ scope.opt?.nickname }},
+                                        {{ scope.opt?.code }}</QItemLabel
+                                    >
+                                </QItemSection>
+                            </QItem>
+                        </template>
+                    </VnSelect>
                 </QTd>
             </template>
             <template #body-cell-item="{ row }">
diff --git a/src/pages/Item/ItemTypeCreate.vue b/src/pages/Item/ItemTypeCreate.vue
index 290a40389..60c037510 100644
--- a/src/pages/Item/ItemTypeCreate.vue
+++ b/src/pages/Item/ItemTypeCreate.vue
@@ -52,15 +52,27 @@ const redirectToItemTypeBasicData = (_, { id }) => {
                 </VnRow>
                 <VnRow>
                     <VnSelect
+                        url="Workers/search"
                         v-model="data.workerFk"
-                        :label="t('itemType.shared.worker')"
-                        url="Workers"
-                        sort-by="firstName ASC"
-                        :fields="['id', 'firstName']"
+                        :label="t('shared.worker')"
+                        sort-by="nickname ASC"
+                        :fields="['id', 'nickname']"
+                        :params="{ departmentCodes: ['shopping'] }"
+                        option-label="nickname"
                         option-value="id"
-                        option-label="firstName"
                         hide-selected
-                    />
+                        ><template #option="scope">
+                            <QItem v-bind="scope.itemProps">
+                                <QItemSection>
+                                    <QItemLabel>{{ scope.opt?.name }}</QItemLabel>
+                                    <QItemLabel caption
+                                        >{{ scope.opt?.nickname }},
+                                        {{ scope.opt?.code }}</QItemLabel
+                                    >
+                                </QItemSection>
+                            </QItem>
+                        </template>
+                    </VnSelect>
                     <VnSelect
                         v-model="data.categoryFk"
                         :label="t('itemType.shared.category')"
diff --git a/src/pages/ItemType/Card/ItemTypeBasicData.vue b/src/pages/ItemType/Card/ItemTypeBasicData.vue
index d35fbb17d..1d4a5cf94 100644
--- a/src/pages/ItemType/Card/ItemTypeBasicData.vue
+++ b/src/pages/ItemType/Card/ItemTypeBasicData.vue
@@ -41,15 +41,27 @@ const temperaturesOptions = ref([]);
             </VnRow>
             <VnRow>
                 <VnSelect
+                    url="Workers/search"
                     v-model="data.workerFk"
                     :label="t('shared.worker')"
-                    url="Workers"
-                    sort-by="firstName ASC"
-                    :fields="['id', 'firstName']"
+                    sort-by="nickname ASC"
+                    :fields="['id', 'nickname']"
+                    :params="{ departmentCodes: ['shopping'] }"
+                    option-label="nickname"
                     option-value="id"
-                    option-label="firstName"
                     hide-selected
-                />
+                    ><template #option="scope">
+                        <QItem v-bind="scope.itemProps">
+                            <QItemSection>
+                                <QItemLabel>{{ scope.opt?.name }}</QItemLabel>
+                                <QItemLabel caption
+                                    >{{ scope.opt?.nickname }},
+                                    {{ scope.opt?.code }}</QItemLabel
+                                >
+                            </QItemSection>
+                        </QItem>
+                    </template></VnSelect
+                >
                 <VnSelect
                     v-model="data.categoryFk"
                     :label="t('shared.category')"

From 1bf1844c8f9edf13b8c0a6f414510a184e70edf0 Mon Sep 17 00:00:00 2001
From: jgallego <jgallego@verdnatura.es>
Date: Wed, 23 Oct 2024 07:46:52 +0200
Subject: [PATCH 62/87] fix: refs #7349 dependencia no usada

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

diff --git a/src/components/VnSelectProvince.vue b/src/components/VnSelectProvince.vue
index 606799e50..9fcbef11e 100644
--- a/src/components/VnSelectProvince.vue
+++ b/src/components/VnSelectProvince.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, watch } from 'vue';
+import { ref } from 'vue';
 import { useValidator } from 'src/composables/useValidator';
 import { useI18n } from 'vue-i18n';
 

From b40af0ce7bb73660464db2b2b945261920528ece Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Wed, 23 Oct 2024 09:49:48 +0200
Subject: [PATCH 63/87] fix: refs #7283 fix pr

---
 src/pages/Item/Card/ItemBasicData.vue  |  8 ++-
 src/pages/Item/Card/ItemBotanical.vue  |  7 ---
 src/pages/Item/Card/ItemDescriptor.vue | 13 ++++
 src/pages/Item/Card/ItemTax.vue        |  4 +-
 src/pages/Item/ItemRequest.vue         | 34 ++++++++++-
 src/pages/Item/ItemTypeList.vue        | 85 +++++++++-----------------
 6 files changed, 84 insertions(+), 67 deletions(-)

diff --git a/src/pages/Item/Card/ItemBasicData.vue b/src/pages/Item/Card/ItemBasicData.vue
index 6b6d89c6d..1b0342668 100644
--- a/src/pages/Item/Card/ItemBasicData.vue
+++ b/src/pages/Item/Card/ItemBasicData.vue
@@ -85,13 +85,19 @@ const onIntrastatCreated = (response, formData) => {
                 <VnInput :label="t('item.basicData.reference')" v-model="data.comment" />
                 <VnInput
                     :label="t('item.basicData.relevancy')"
+                    type="number"
                     v-model="data.relevancy"
                 />
             </VnRow>
             <VnRow class="row q-gutter-md q-mb-md">
-                <VnInput :label="t('item.basicData.stems')" v-model="data.stems" />
+                <VnInput
+                    :label="t('item.basicData.stems')"
+                    type="number"
+                    v-model="data.stems"
+                />
                 <VnInput
                     :label="t('item.basicData.multiplier')"
+                    type="number"
                     v-model="data.stemMultiplier"
                 />
                 <VnSelectDialog
diff --git a/src/pages/Item/Card/ItemBotanical.vue b/src/pages/Item/Card/ItemBotanical.vue
index 5f7f3a5e4..1aa6faed1 100644
--- a/src/pages/Item/Card/ItemBotanical.vue
+++ b/src/pages/Item/Card/ItemBotanical.vue
@@ -20,15 +20,8 @@ let itemBotanicalsForm = reactive({ itemFk: null });
 const entityId = computed(() => {
     return route.params.id;
 });
-// onMounted(async () => {
-//     itemBotanicalsForm.itemFk = entityId.value;
-//     // itemBotanicals.value = await itemBotanicalsRef.value.fetch();
-//     if (itemBotanicals.value.length > 0)
-//         Object.assign(itemBotanicalsForm, itemBotanicals.value[0]);
-// });
 async function handleItemBotanical(data) {
     itemBotanicalsForm = data;
-    // if (data.length > 0) Object.assign(itemBotanicalsForm, itemBotanicals.value[0]);
 }
 </script>
 <template>
diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index 09d6a8a4f..aa9795a74 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -189,6 +189,18 @@ const openCloneDialog = async () => {
                 :value="entity.value7"
             />
         </template>
+        <template #icons="{ entity }">
+            <QCardActions v-if="entity" class="q-gutter-x-md">
+                <QIcon
+                    v-if="!entity.isActive"
+                    name="vn:unavailable"
+                    color="primary"
+                    size="xs"
+                >
+                    <QTooltip>{{ t('Inactive article') }}</QTooltip>
+                </QIcon>
+            </QCardActions>
+        </template>
         <template #actions="{}">
             <QCardActions class="row justify-center">
                 <QBtn
@@ -213,6 +225,7 @@ es:
     Regularize stock: Regularizar stock
     All its properties will be copied: Todas sus propiedades serán copiadas
     Do you want to clone this item?: ¿Desea clonar este artículo?
+    Inactive article: Artículo inactivo
 </i18n>
 
 <style lang="scss" scoped>
diff --git a/src/pages/Item/Card/ItemTax.vue b/src/pages/Item/Card/ItemTax.vue
index 489a2c7b2..9050db42e 100644
--- a/src/pages/Item/Card/ItemTax.vue
+++ b/src/pages/Item/Card/ItemTax.vue
@@ -22,7 +22,7 @@ const taxesFilter = {
         {
             relation: 'country',
             scope: {
-                fields: ['country'],
+                fields: ['name'],
             },
         },
     ],
@@ -73,7 +73,7 @@ const submitTaxes = async (data) => {
                 >
                     <VnInput
                         :label="t('tax.country')"
-                        v-model="row.country.country"
+                        v-model="row.country.name"
                         disable
                     />
                     <VnSelect
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 0eba6f9a4..ea265e706 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -5,7 +5,7 @@ import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.v
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 import { useStateStore } from 'stores/useStateStore';
 import { useArrayData } from 'composables/useArrayData';
-import { toCurrency } from 'filters/index';
+import { dashIfEmpty, toCurrency } from 'filters/index';
 import useNotify from 'src/composables/useNotify.js';
 import axios from 'axios';
 import ItemRequestDenyForm from './ItemRequestDenyForm.vue';
@@ -134,6 +134,20 @@ const columns = computed(() => [
     },
 ]);
 
+const getBadgeColor = (date) => {
+    const today = Date.vnNew();
+    today.setHours(0, 0, 0, 0);
+
+    const orderLanded = new Date(date);
+    orderLanded.setHours(0, 0, 0, 0);
+
+    const difference = today - orderLanded;
+
+    if (difference == 0) return 'warning';
+    if (difference < 0) return 'success';
+    if (difference > 0) return 'alert';
+};
+
 const changeQuantity = async (request) => {
     try {
         if (request.saleFk) {
@@ -212,6 +226,24 @@ onMounted(async () => {
         auto-load
         :disable-option="{ card: true }"
     >
+        <template #column-ticketFk="{ row }">
+            <span class="link">
+                {{ row.ticketFk }}
+                <TicketDescriptorProxy :id="row.ticketFk" />
+            </span>
+        </template>
+        <template #column-shipped="{ row }">
+            <QTd>
+                <QBadge
+                    :color="getBadgeColor(row.shipped)"
+                    text-color="black"
+                    class="q-pa-sm"
+                    style="font-size: 14px"
+                >
+                    {{ toDate(row.shipped) }}
+                </QBadge>
+            </QTd>
+        </template>
         <template #column-attenderName="{ row }">
             <span class="link" @click.stop>
                 {{ row.attenderName }}
diff --git a/src/pages/Item/ItemTypeList.vue b/src/pages/Item/ItemTypeList.vue
index 5ebbec62b..9981a0d68 100644
--- a/src/pages/Item/ItemTypeList.vue
+++ b/src/pages/Item/ItemTypeList.vue
@@ -1,54 +1,14 @@
 <script setup>
 import { useI18n } from 'vue-i18n';
-import { useRouter } from 'vue-router';
+import { useRoute } from 'vue-router';
 import { ref, computed } from 'vue';
 import ItemTypeSearchbar from '../ItemType/ItemTypeSearchbar.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 
-const router = useRouter();
+const route = useRoute();
 const { t } = useI18n();
 const tableRef = ref();
-const redirectToItemTypeSummary = (id) => {
-    router.push({ name: 'ItemTypeSummary', params: { id } });
-};
-
-const redirectToCreateView = () => {
-    router.push({ name: 'ItemTypeCreate' });
-};
-
-const exprBuilder = (param, value) => {
-    switch (param) {
-        case 'name':
-            return {
-                name: { like: `%${value}%` },
-            };
-        case 'code':
-            return {
-                code: { like: `%${value}%` },
-            };
-        case 'search':
-            if (value) {
-                if (!isNaN(value)) {
-                    return { id: value };
-                } else {
-                    return {
-                        or: [
-                            {
-                                name: {
-                                    like: `%${value}%`,
-                                },
-                            },
-                            {
-                                code: {
-                                    like: `%${value}%`,
-                                },
-                            },
-                        ],
-                    };
-                }
-            }
-    }
-};
+const entityId = computed(() => route.params.id);
 
 const columns = computed(() => [
     {
@@ -75,20 +35,21 @@ const columns = computed(() => [
     },
     {
         align: 'left',
-        name: 'worker',
+        name: 'workerFk',
         label: t('worker'),
         create: true,
         component: 'select',
         attrs: {
             url: 'Workers',
-            fields: ['id', 'firstName'],
+            optionLabel: 'firstName',
+            optionValue: 'id',
         },
-        cardVisible: true,
+        cardVisible: false,
         visible: false,
     },
     {
         align: 'left',
-        name: 'ItemCategory',
+        name: 'categoryFk',
         label: t('ItemCategory'),
         create: true,
         component: 'select',
@@ -96,7 +57,7 @@ const columns = computed(() => [
             url: 'ItemCategories',
             fields: ['id', 'name'],
         },
-        cardVisible: true,
+        cardVisible: false,
         visible: false,
     },
     {
@@ -109,7 +70,7 @@ const columns = computed(() => [
             url: 'Temperatures',
             fields: ['id', 'name'],
         },
-        cardVisible: true,
+        cardVisible: false,
         visible: false,
     },
 ]);
@@ -121,18 +82,13 @@ const columns = computed(() => [
         ref="tableRef"
         data-key="ItemTypeList"
         :url="`ItemTypes`"
-        :url-create="`ItemTypes`"
-        save-url="ItemTypes/crud"
-        :filter="courseFilter"
         :create="{
             urlCreate: 'ItemTypes',
             title: 'Create ItemTypes',
             onDataSaved: () => tableRef.reload(),
-            formInitialData: {
-                workerFk: entityId,
-            },
+            formInitialData: {},
         }"
-        order="id DESC"
+        order="code ASC"
         :columns="columns"
         auto-load
         :right-search="false"
@@ -140,3 +96,20 @@ const columns = computed(() => [
         :use-model="true"
     />
 </template>
+
+<i18n>
+    es:
+        id: Id
+        code: Código
+        name: Nombre
+        worker: Encargado
+        ItemCategory: Categoría
+        Temperature: Temperatura
+        Create ItemTypes: Crear familia
+    en:
+        code: Code
+        name: Name
+        worker: Worker
+        ItemCategory: ItemCategory
+        Temperature: Temperature
+</i18n>

From e7acdfd4f7844c5f4696d9caaaf767463aad27b7 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 23 Oct 2024 10:48:30 +0200
Subject: [PATCH 64/87] fix: refs #8010 footer class

---
 src/components/VnTable/VnTable.vue | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index b9c6edf50..42d6b82a6 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -417,6 +417,7 @@ function handleScroll() {
                 ref="tableRef"
                 v-bind="table"
                 class="vnTable"
+                :class="{ lastRowSticky: $props.footer }"
                 :columns="splittedColumns.columns"
                 :rows="rows"
                 v-model:selected="selected"
@@ -855,6 +856,9 @@ es:
     table tbody th {
         position: relative;
     }
+}
+
+.lastRowSticky {
     tbody:nth-last-child(1) {
         @extend .bg-header;
         position: sticky;

From d8b80cfa6d31087bee361d9b48a999b3f199e59a Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Wed, 23 Oct 2024 12:30:04 +0200
Subject: [PATCH 65/87] fix: refs #7283 fix pr

---
 src/pages/Item/Card/ItemBotanical.vue  | 5 +----
 src/pages/Item/Card/ItemDescriptor.vue | 2 --
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/src/pages/Item/Card/ItemBotanical.vue b/src/pages/Item/Card/ItemBotanical.vue
index 1aa6faed1..c4b561772 100644
--- a/src/pages/Item/Card/ItemBotanical.vue
+++ b/src/pages/Item/Card/ItemBotanical.vue
@@ -20,9 +20,6 @@ let itemBotanicalsForm = reactive({ itemFk: null });
 const entityId = computed(() => {
     return route.params.id;
 });
-async function handleItemBotanical(data) {
-    itemBotanicalsForm = data;
-}
 </script>
 <template>
     <FetchData
@@ -41,7 +38,7 @@ async function handleItemBotanical(data) {
         :filter="{
             where: { itemFk: entityId },
         }"
-        @on-fetch="handleItemBotanical"
+        @on-fetch="(data) => (itemBotanicalsForm = data)"
     >
         <template #form="{ data }">
             <VnRow>
diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index aa9795a74..635dd17c8 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -50,7 +50,6 @@ const entityId = computed(() => {
 });
 
 const regularizeStockFormDialog = ref(null);
-const salixUrl = ref();
 const mounted = ref();
 
 const arrayDataStock = useArrayData('descriptorStock', {
@@ -58,7 +57,6 @@ const arrayDataStock = useArrayData('descriptorStock', {
 });
 
 onMounted(async () => {
-    salixUrl.value = await getUrl('getVisibleAvailable');
     await getItemConfigs();
     mounted.value = true;
 });

From 0528474250fdbbad7a6137467f532ac7ebcee710 Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Wed, 23 Oct 2024 13:13:00 +0200
Subject: [PATCH 66/87] chore: refs #8010 kebab-case

---
 src/components/VnTable/VnTable.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 42d6b82a6..47323da95 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -417,7 +417,7 @@ function handleScroll() {
                 ref="tableRef"
                 v-bind="table"
                 class="vnTable"
-                :class="{ lastRowSticky: $props.footer }"
+                :class="{ 'last-row-sticky': $props.footer }"
                 :columns="splittedColumns.columns"
                 :rows="rows"
                 v-model:selected="selected"
@@ -858,7 +858,7 @@ es:
     }
 }
 
-.lastRowSticky {
+.last-row-sticky {
     tbody:nth-last-child(1) {
         @extend .bg-header;
         position: sticky;

From 9673f7be1edf10b9606327415118411a03380670 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Wed, 23 Oct 2024 15:17:06 +0200
Subject: [PATCH 67/87] fix: refs #8083 update rightly

---
 src/pages/Ticket/Card/TicketExpedition.vue | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 93749ebec..9f592bd89 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -231,14 +231,14 @@ onUnmounted(() => (stateStore.rightDrawer = false));
                     :select-props="{
                         options: expeditionStateTypes,
                         optionLabel: 'description',
+                        optionValue: 'code',
                     }"
                     :promise="
-                        async (stateTypeFk) => {
-                            await vnTableRef.CrudModelRef.saveChanges({
-                                updates: selectedRows.map(({ id }) => ({
-                                    data: { stateTypeFk },
-                                    where: { id },
-                                })),
+                        async (stateCode) => {
+                            await axios.post('ExpeditionStates/addExpeditionState', {
+                                expeditions: selectedRows.map(({ id }) => {
+                                    return { expeditionFk: id, stateCode };
+                                }),
                             });
                             vnTableRef.tableRef.clearSelection();
                         }
@@ -309,7 +309,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
             'row-key': 'id',
             selection: 'multiple',
         }"
-        save-url="Expeditions/crud"
+        save-url="ExpeditionStates/crud"
         auto-load
         :expr-builder="
             (param, value) => {

From 126bb3f039160460b528042f30788096c81cd7c2 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Wed, 23 Oct 2024 16:10:14 +0200
Subject: [PATCH 68/87] feat: refs #8083 insert

---
 src/pages/Ticket/Card/TicketExpedition.vue | 24 ++++++++--------------
 src/pages/Ticket/locale/en.yml             |  1 +
 src/pages/Ticket/locale/es.yml             |  1 +
 3 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 9f592bd89..436e9678e 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -26,6 +26,7 @@ const { openConfirmationModal } = useVnConfirm();
 const newTicketDialogRef = ref(null);
 const logsTableDialogRef = ref(null);
 const vnTableRef = ref();
+const btnSelectRef = ref();
 const expeditionsLogsData = ref([]);
 const selectedExpeditions = ref([]);
 const allColumnNames = ref([]);
@@ -190,17 +191,11 @@ const getExpeditionState = async (expedition) => {
         const { data: expeditionStates } = await axios.get(`ExpeditionStates/filter`, {
             params: { filter: JSON.stringify(filter) },
         });
-        const { data: scannedStates } = await axios.get(`ExpeditionStates`, {
-            params: { filter: JSON.stringify(filter), fields: ['id', 'isScanned'] },
-        });
 
-        expeditionsLogsData.value = expeditionStates.map((state) => {
-            const scannedState = scannedStates.find((s) => s.id === state.id);
-            return {
-                ...state,
-                isScanned: scannedState ? scannedState.isScanned : false,
-            };
-        });
+        expeditionsLogsData.value = expeditionStates.map((state) => ({
+            ...state,
+            isScanned: !!state.isScanned,
+        }));
     } catch (error) {
         console.error(error);
     }
@@ -225,6 +220,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         <template #st-actions>
             <QBtnGroup push class="q-gutter-x-sm" flat>
                 <VnBtnSelect
+                    ref="btnSelectRef"
                     :disable="!hasSelectedRows"
                     color="primary"
                     :label="t('globals.changeState')"
@@ -241,6 +237,8 @@ onUnmounted(() => (stateStore.rightDrawer = false));
                                 }),
                             });
                             vnTableRef.tableRef.clearSelection();
+                            vnTableRef.reload();
+                            btnSelectRef.hidePopup();
                         }
                     "
                 />
@@ -355,11 +353,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
             </template>
             <template #body-cell-isScanned="{ row }">
                 <QTd style="text-align: center">
-                    <QCheckbox disable v-model="row.isScanned">
-                        {{
-                            row.isScanned === 1 ? t('expedition.yes') : t('expedition.no')
-                        }}
-                    </QCheckbox>
+                    <QCheckbox disable v-model="row.isScanned" />
                 </QTd>
             </template>
         </QTable>
diff --git a/src/pages/Ticket/locale/en.yml b/src/pages/Ticket/locale/en.yml
index 06699e00b..bae290b5d 100644
--- a/src/pages/Ticket/locale/en.yml
+++ b/src/pages/Ticket/locale/en.yml
@@ -118,6 +118,7 @@ expedition:
     removeExpeditionSubtitle: Are you sure you want to delete this expedition?
     worker: Worker
     move: Move
+    isScanned: Scanned
 basicData:
     next: Next
     back: Back
diff --git a/src/pages/Ticket/locale/es.yml b/src/pages/Ticket/locale/es.yml
index d4ba1f26a..4dca7253c 100644
--- a/src/pages/Ticket/locale/es.yml
+++ b/src/pages/Ticket/locale/es.yml
@@ -207,6 +207,7 @@ expedition:
     removeExpeditionSubtitle: ¿Está seguro de eliminar esta expedición?
     worker: Trabajador
     move: Mover
+    isScanned: Escaneado
 package:
     package: Embalaje
     quantity: Cantidad

From 33ee1ea01bca4c715a70ad6f6c6bf4ff23bcea08 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Wed, 23 Oct 2024 16:11:58 +0200
Subject: [PATCH 69/87] fix: refs #8083 drop useless code

---
 src/pages/Ticket/Card/TicketExpedition.vue | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 436e9678e..979854ad5 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -238,7 +238,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
                             });
                             vnTableRef.tableRef.clearSelection();
                             vnTableRef.reload();
-                            btnSelectRef.hidePopup();
                         }
                     "
                 />

From 4e31566dddcbd2f1f073be202d3cbdb4cbcc96ef Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Wed, 23 Oct 2024 16:13:04 +0200
Subject: [PATCH 70/87] fix: refs #8083 drop useless code

---
 src/pages/Ticket/Card/TicketExpedition.vue | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 979854ad5..27f78e728 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -26,7 +26,6 @@ const { openConfirmationModal } = useVnConfirm();
 const newTicketDialogRef = ref(null);
 const logsTableDialogRef = ref(null);
 const vnTableRef = ref();
-const btnSelectRef = ref();
 const expeditionsLogsData = ref([]);
 const selectedExpeditions = ref([]);
 const allColumnNames = ref([]);
@@ -220,7 +219,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
         <template #st-actions>
             <QBtnGroup push class="q-gutter-x-sm" flat>
                 <VnBtnSelect
-                    ref="btnSelectRef"
                     :disable="!hasSelectedRows"
                     color="primary"
                     :label="t('globals.changeState')"

From 1bfede4a554f6565843134396e8663793dad5355 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Wed, 23 Oct 2024 16:13:32 +0200
Subject: [PATCH 71/87] fix: refs #8083 drop useless code

---
 src/pages/Ticket/Card/TicketExpedition.vue | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/pages/Ticket/Card/TicketExpedition.vue b/src/pages/Ticket/Card/TicketExpedition.vue
index 27f78e728..bd63f259c 100644
--- a/src/pages/Ticket/Card/TicketExpedition.vue
+++ b/src/pages/Ticket/Card/TicketExpedition.vue
@@ -304,7 +304,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
             'row-key': 'id',
             selection: 'multiple',
         }"
-        save-url="ExpeditionStates/crud"
         auto-load
         :expr-builder="
             (param, value) => {

From 1c8eabe2936e8a109a3580d3b3552b51d5f1712e Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Thu, 24 Oct 2024 00:39:35 +0200
Subject: [PATCH 72/87] perf: refs #7283 #7283 declare composable inst4ead code
 duplicated

---
 src/pages/Item/Card/ItemDescriptor.vue  | 34 +++-------------------
 src/pages/Item/ItemList.vue             | 34 +++-------------------
 src/pages/Item/composables/cloneItem.js | 38 +++++++++++++++++++++++++
 3 files changed, 46 insertions(+), 60 deletions(-)
 create mode 100644 src/pages/Item/composables/cloneItem.js

diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index 635dd17c8..6fbc5a4bd 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -1,20 +1,18 @@
 <script setup>
 import { computed, ref, onMounted } from 'vue';
-import { useRoute, useRouter } from 'vue-router';
+import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
-import { useQuasar } from 'quasar';
 
 import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
 import VnLv from 'src/components/ui/VnLv.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
-import VnConfirm from 'components/ui/VnConfirm.vue';
 import RegularizeStockForm from 'components/RegularizeStockForm.vue';
 import ItemDescriptorImage from 'src/pages/Item/Card/ItemDescriptorImage.vue';
 import useCardDescription from 'src/composables/useCardDescription';
 import axios from 'axios';
-import { getUrl } from 'src/composables/getUrl';
 import { dashIfEmpty } from 'src/filters';
 import { useArrayData } from 'src/composables/useArrayData';
+import { cloneItem } from 'src/pages/Item/composables/cloneItem';
 
 const $props = defineProps({
     id: {
@@ -40,9 +38,8 @@ const $props = defineProps({
     },
 });
 
-const quasar = useQuasar();
+const { openCloneDialog } = cloneItem();
 const route = useRoute();
-const router = useRouter();
 const { t } = useI18n();
 const warehouseConfig = ref(null);
 const entityId = computed(() => {
@@ -96,29 +93,6 @@ const updateStock = async () => {
 const openRegularizeStockForm = () => {
     regularizeStockFormDialog.value.show();
 };
-
-const cloneItem = async () => {
-    try {
-        const { data } = await axios.post(`Items/${entityId.value}/clone`);
-        router.push({ name: 'ItemTags', params: { id: data.id } });
-    } catch (err) {
-        console.error('Error cloning item');
-    }
-};
-
-const openCloneDialog = async () => {
-    quasar
-        .dialog({
-            component: VnConfirm,
-            componentProps: {
-                title: t('All its properties will be copied'),
-                message: t('Do you want to clone this item?'),
-            },
-        })
-        .onOk(async () => {
-            await cloneItem();
-        });
-};
 </script>
 
 <template>
@@ -144,7 +118,7 @@ const openCloneDialog = async () => {
                     </QDialog>
                 </QItemSection>
             </QItem>
-            <QItem v-ripple clickable @click="openCloneDialog()">
+            <QItem v-ripple clickable @click="openCloneDialog(entityId)">
                 <QItemSection>
                     {{ t('globals.clone') }}
                 </QItemSection>
diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 92c9d188b..30b86bc11 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -1,27 +1,24 @@
 <script setup>
 import { ref, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { useRouter, useRoute } from 'vue-router';
+import { useRoute } from 'vue-router';
 import VnImg from 'src/components/ui/VnImg.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
 import { toDate } from 'src/filters';
-import axios from 'axios';
 import FetchedTags from 'src/components/ui/FetchedTags.vue';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import { useSummaryDialog } from 'src/composables/useSummaryDialog';
 import ItemSummary from '../Item/Card/ItemSummary.vue';
 import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
 import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
-import VnConfirm from 'src/components/ui/VnConfirm.vue';
-import { useQuasar } from 'quasar';
-const entityId = computed(() => route.params.id);
+import { cloneItem } from 'src/pages/Item/composables/cloneItem';
 
+const entityId = computed(() => route.params.id);
+const { openCloneDialog } = cloneItem();
 const { viewSummary } = useSummaryDialog();
-const router = useRouter();
 const { t } = useI18n();
 const tableRef = ref();
 const route = useRoute();
-const quasar = useQuasar();
 
 const itemFilter = {
     include: [
@@ -297,29 +294,6 @@ const columns = computed(() => [
         ],
     },
 ]);
-
-const cloneItem = async () => {
-    try {
-        const { data } = await axios.post(`Items/${entityId.value}/clone`);
-        router.push({ name: 'ItemTags', params: { id: data.id } });
-    } catch (err) {
-        console.error('Error cloning item');
-    }
-};
-
-const openCloneDialog = async () => {
-    quasar
-        .dialog({
-            component: VnConfirm,
-            componentProps: {
-                title: t('All its properties will be copied'),
-                message: t('Do you want to clone this item?'),
-            },
-        })
-        .onOk(async () => {
-            await cloneItem();
-        });
-};
 </script>
 
 <template>
diff --git a/src/pages/Item/composables/cloneItem.js b/src/pages/Item/composables/cloneItem.js
new file mode 100644
index 000000000..f1114c779
--- /dev/null
+++ b/src/pages/Item/composables/cloneItem.js
@@ -0,0 +1,38 @@
+import axios from 'axios';
+import { computed, ref, onMounted } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+import { useQuasar } from 'quasar';
+import VnConfirm from 'components/ui/VnConfirm.vue';
+
+export function cloneItem() {
+    const { t } = useI18n();
+
+    const quasar = useQuasar();
+    const route = useRoute();
+    const router = useRouter();
+    const cloneItem = async (entityId) => {
+        const { id } = entityId;
+        try {
+            const { data } = await axios.post(`Items/${id ?? entityId}/clone`);
+            router.push({ name: 'ItemTags', params: { id: data.id } });
+        } catch (err) {
+            console.error('Error cloning item');
+        }
+    };
+
+    const openCloneDialog = async (entityId) => {
+        quasar
+            .dialog({
+                component: VnConfirm,
+                componentProps: {
+                    title: t('All its properties will be copied'),
+                    message: t('Do you want to clone this item?'),
+                },
+            })
+            .onOk(async () => {
+                await cloneItem(entityId);
+            });
+    };
+    return { openCloneDialog };
+}

From 56ef811584970ae0c53f04f35604be941cd5a3ef Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 24 Oct 2024 07:47:26 +0200
Subject: [PATCH 73/87] fix: refs #7283 order translation

---
 src/pages/Item/ItemTypeList.vue |  4 +--
 src/router/modules/item.js      | 45 +++++++++++++++++----------------
 2 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/src/pages/Item/ItemTypeList.vue b/src/pages/Item/ItemTypeList.vue
index 9981a0d68..d9f7bba85 100644
--- a/src/pages/Item/ItemTypeList.vue
+++ b/src/pages/Item/ItemTypeList.vue
@@ -84,11 +84,11 @@ const columns = computed(() => [
         :url="`ItemTypes`"
         :create="{
             urlCreate: 'ItemTypes',
-            title: 'Create ItemTypes',
+            title: t('Create ItemTypes'),
             onDataSaved: () => tableRef.reload(),
             formInitialData: {},
         }"
-        order="code ASC"
+        order="name ASC"
         :columns="columns"
         auto-load
         :right-search="false"
diff --git a/src/router/modules/item.js b/src/router/modules/item.js
index 48e19dd54..2838c3be7 100644
--- a/src/router/modules/item.js
+++ b/src/router/modules/item.js
@@ -48,6 +48,28 @@ export default {
                     },
                     component: () => import('src/pages/Item/ItemList.vue'),
                 },
+                {
+                    path: 'request',
+                    name: 'ItemRequest',
+                    meta: {
+                        title: 'buyRequest',
+                        icon: 'vn:buyrequest',
+                    },
+                    component: () => import('src/pages/Item/ItemRequest.vue'),
+                },
+                {
+                    path: 'waste-breakdown',
+                    name: 'WasteBreakdown',
+                    meta: {
+                        title: 'wasteBreakdown',
+                        icon: 'vn:claims',
+                    },
+                    beforeEnter: (to, from, next) => {
+                        next({ name: 'ItemList' });
+                        window.location.href =
+                            'https://grafana.verdnatura.es/d/TTNXQAxVk';
+                    },
+                },
                 {
                     path: 'fixed-price',
                     name: 'ItemFixedPrice',
@@ -65,19 +87,7 @@ export default {
                     },
                     component: () => import('src/pages/Item/ItemCreate.vue'),
                 },
-                {
-                    path: 'waste-breakdown',
-                    name: 'WasteBreakdown',
-                    meta: {
-                        title: 'wasteBreakdown',
-                        icon: 'vn:claims',
-                    },
-                    beforeEnter: (to, from, next) => {
-                        next({ name: 'ItemList' });
-                        window.location.href =
-                            'https://grafana.verdnatura.es/d/TTNXQAxVk';
-                    },
-                },
+
                 {
                     path: 'item-type-list',
                     name: 'ItemTypeList',
@@ -95,15 +105,6 @@ export default {
                     },
                     component: () => import('src/pages/Item/ItemTypeCreate.vue'),
                 },
-                {
-                    path: 'request',
-                    name: 'ItemRequest',
-                    meta: {
-                        title: 'buyRequest',
-                        icon: 'vn:buyrequest',
-                    },
-                    component: () => import('src/pages/Item/ItemRequest.vue'),
-                },
             ],
         },
         {

From 6f57d9e4906f7c74b50545a3271574b942efeac4 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Thu, 24 Oct 2024 10:21:25 +0200
Subject: [PATCH 74/87] refactor: refs #7524 use VnTable

---
 src/components/VnTable/VnTable.vue       |   6 +-
 src/pages/Ticket/TicketAdvance.vue       | 605 +++++++++--------------
 src/pages/Ticket/TicketAdvanceFilter.vue |   3 +
 3 files changed, 234 insertions(+), 380 deletions(-)

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 9209eaf7b..0afc5e8cf 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -447,7 +447,11 @@ function handleOnDataSaved(_) {
                     />
                 </template>
                 <template #header-cell="{ col }">
-                    <QTh v-if="col.visible ?? true">
+                    <QTh
+                        v-if="col.visible ?? true"
+                        :style="col.headerStyle"
+                        :class="col.headerClass"
+                    >
                         <div
                             class="column self-start q-ml-xs ellipsis"
                             :class="`text-${col?.align ?? 'left'}`"
diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index 2cce1dba8..8b109d778 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -1,24 +1,20 @@
 <script setup>
-import { onMounted, ref, computed, reactive } from 'vue';
+import { ref, computed, reactive, watch, h } from 'vue';
 import { useI18n } from 'vue-i18n';
-
 import FetchData from 'components/FetchData.vue';
-import VnInput from 'src/components/common/VnInput.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
 import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
 import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
 import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
 import VnProgress from 'src/components/common/VnProgressModal.vue';
 import RightMenu from 'src/components/common/RightMenu.vue';
 import TicketAdvanceFilter from './TicketAdvanceFilter.vue';
-
 import { dashIfEmpty, toCurrency } from 'src/filters';
 import { useVnConfirm } from 'composables/useVnConfirm';
-import { useArrayData } from 'composables/useArrayData';
 import useNotify from 'src/composables/useNotify.js';
 import { useState } from 'src/composables/useState';
 import { toDateFormat } from 'src/filters/date.js';
 import axios from 'axios';
+import VnTable from 'src/components/VnTable/VnTable.vue';
 
 const state = useState();
 const { t } = useI18n();
@@ -29,109 +25,58 @@ const user = state.getUser();
 const itemPackingTypesOptions = ref([]);
 const zonesOptions = ref([]);
 const selectedTickets = ref([]);
-
-const exprBuilder = (param, value) => {
-    switch (param) {
-        case 'id':
-        case 'futureId':
-        case 'liters':
-        case 'futureLiters':
-        case 'lines':
-        case 'futureLines':
-        case 'totalWithVat':
-        case 'futureTotalWithVat':
-        case 'futureZone':
-        case 'notMovableLines':
-        case 'futureZoneFk':
-            return { [param]: value };
-        case 'iptColFilter':
-            return { ipt: { like: `%${value}%` } };
-        case 'futureIptColFilter':
-            return { futureIpt: { like: `%${value}%` } };
-    }
-};
-
-const userParams = reactive({});
-
-const arrayData = useArrayData('AdvanceTickets', {
-    url: 'Tickets/getTicketsAdvance',
-    userParams: userParams,
-    exprBuilder: exprBuilder,
-    limit: 0,
+const vnTableRef = ref({});
+const originElRef = ref(null);
+const destinationElRef = ref(null);
+let today = Date.vnNew().toISOString();
+const tomorrow = new Date(today);
+tomorrow.setDate(tomorrow.getDate() + 1);
+const userParams = reactive({
+    dateFuture: tomorrow,
+    dateToAdvance: today,
+    warehouseFk: user.value.warehouseFk,
+    ipt: 'H',
+    futureIpt: 'H',
+    isFullMovable: true,
 });
-const { store } = arrayData;
-const tickets = computed(() =>
-    (store.data || []).map((ticket, index) => ({ ...ticket, index: index }))
-);
-
-const applyColumnFilter = async (col) => {
-    try {
-        const paramKey = col.columnFilter?.filterParamKey || col.field;
-        userParams[paramKey] = col.columnFilter.filterValue;
-        await arrayData.addFilter({ params: userParams });
-    } catch (err) {
-        console.error('Error applying column filter', err);
-    }
-};
-
-const getInputEvents = (col) => {
-    return col.columnFilter.type === 'select'
-        ? { 'update:modelValue': () => applyColumnFilter(col) }
-        : {
-              'keyup.enter': () => applyColumnFilter(col),
-          };
-};
 
 const ticketColumns = computed(() => [
     {
         label: '',
         name: 'icons',
-        align: 'left',
-        columnFilter: null,
+        hidden: true,
+        headerClass: 'horizontal-separator',
     },
     {
-        label: t('advanceTickets.ticketId'),
-        name: 'ticketId',
         align: 'center',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            filterParamKey: 'id',
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
+        label: t('advanceTickets.ticketId'),
+        name: 'id',
+        headerClass: 'horizontal-separator',
     },
     {
+        align: 'left',
         label: t('advanceTickets.ipt'),
         name: 'ipt',
-        field: 'ipt',
-        align: 'left',
-        sortable: true,
         columnFilter: {
-            component: VnSelect,
-            filterParamKey: 'iptColFilter',
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
+            component: 'select',
             attrs: {
-                options: itemPackingTypesOptions.value,
-                'option-value': 'code',
-                'option-label': 'description',
-                dense: true,
+                url: 'itemPackingTypes',
+                fields: ['code', 'description'],
+                where: { isActive: true },
+                optionValue: 'code',
+                optionLabel: 'description',
+                inWhere: false,
             },
         },
-        format: (val) => dashIfEmpty(val),
+        format: (row, dashIfEmpty) => dashIfEmpty(row.ipt),
+        headerClass: 'horizontal-separator',
     },
     {
+        align: 'left',
         label: t('advanceTickets.state'),
         name: 'state',
-        align: 'left',
-        sortable: true,
-        columnFilter: null,
+        headerClass: 'horizontal-separator',
+        hidden: true,
     },
     {
         label: t('advanceTickets.preparation'),
@@ -139,171 +84,105 @@ const ticketColumns = computed(() => [
         field: 'preparation',
         align: 'left',
         sortable: true,
-        columnFilter: null,
+        headerClass: 'horizontal-separator',
+        columnFilter: false,
     },
     {
-        label: t('advanceTickets.liters'),
-        name: 'liters',
-        field: 'liters',
         align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
+        label: t('advanceTickets.liters'),
+        headerClass: 'horizontal-separator',
+        name: 'liters',
     },
     {
+        align: 'left',
         label: t('advanceTickets.lines'),
         name: 'lines',
-        field: 'lines',
-        align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
-        format: (val) => dashIfEmpty(val),
+        headerClass: 'horizontal-separator',
+        format: (row, dashIfEmpty) => dashIfEmpty(row.lines),
     },
     {
+        align: 'left',
         label: t('advanceTickets.import'),
-        field: 'import',
-        name: 'import',
-        align: 'left',
-        sortable: true,
+        name: 'totalWithVat',
+        hidden: true,
+        headerClass: 'horizontal-separator',
+        format: (row) => toCurrency(row.totalWithVat),
     },
     {
+        align: 'left',
         label: t('advanceTickets.futureId'),
         name: 'futureId',
-        align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            filterParamKey: 'futureId',
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
+        headerClass: 'vertical-separator horizontal-separator',
+        columnClass: 'vertical-separator',
     },
     {
+        align: 'left',
         label: t('advanceTickets.futureIpt'),
         name: 'futureIpt',
-        field: 'futureIpt',
-        align: 'left',
-        sortable: true,
         columnFilter: {
-            component: VnSelect,
-            filterParamKey: 'futureIptColFilter',
-            type: 'select',
-            filterValue: null,
-            event: getInputEvents,
+            component: 'select',
             attrs: {
-                options: itemPackingTypesOptions.value,
-                'option-value': 'code',
-                'option-label': 'description',
-                dense: true,
+                url: 'itemPackingTypes',
+                fields: ['code', 'description'],
+                where: { isActive: true },
+                optionValue: 'code',
+                optionLabel: 'description',
             },
         },
-        format: (val) => dashIfEmpty(val),
+        headerClass: 'horizontal-separator',
+        format: (row, dashIfEmpty) => dashIfEmpty(row.futureIpt),
     },
     {
+        align: 'left',
         label: t('advanceTickets.futureState'),
         name: 'futureState',
-        align: 'left',
-        sortable: true,
-        columnFilter: null,
-        format: (val) => dashIfEmpty(val),
+        headerClass: 'horizontal-separator',
+        hidden: true,
     },
     {
+        align: 'left',
         label: t('advanceTickets.futureLiters'),
+        headerClass: 'horizontal-separator',
         name: 'futureLiters',
-        field: 'futureLiters',
-        align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
-        format: (val) => dashIfEmpty(val),
     },
     {
+        align: 'left',
         label: t('advanceTickets.futureZone'),
-        name: 'futureZoneName',
-        field: 'futureZoneName',
-        align: 'left',
-        sortable: true,
+        name: 'futureZoneFk',
+        columnClass: 'expand',
         columnFilter: {
-            component: VnSelect,
-            type: 'select',
-            filterValue: null,
-            filterParamKey: 'futureZoneFk',
-            event: getInputEvents,
+            component: 'select',
+            inWhere: true,
             attrs: {
-                options: zonesOptions.value,
-                'option-value': 'id',
-                'option-label': 'name',
-                dense: true,
+                url: 'Zones',
+                fields: ['id', 'name'],
             },
         },
-        format: (val) => dashIfEmpty(val),
+        columnField: {
+            component: null,
+        },
+        headerClass: 'horizontal-separator',
+        format: (row, dashIfEmpty) => dashIfEmpty(row.futureZoneName),
     },
     {
+        align: 'left',
         label: t('advanceTickets.notMovableLines'),
+        headerClass: 'horizontal-separator',
         name: 'notMovableLines',
-        field: 'notMovableLines',
-        align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
-        format: (val) => dashIfEmpty(val),
     },
     {
+        align: 'left',
         label: t('advanceTickets.futureLines'),
+        headerClass: 'horizontal-separator',
         name: 'futureLines',
-        field: 'futureLines',
-        align: 'left',
-        sortable: true,
-        columnFilter: {
-            component: VnInput,
-            type: 'text',
-            filterValue: null,
-            event: getInputEvents,
-            attrs: {
-                dense: true,
-            },
-        },
-        format: (val) => dashIfEmpty(val),
     },
     {
-        label: t('advanceTickets.futureImport'),
-        name: 'futureImport',
         align: 'left',
-        sortable: true,
-        columnFilter: null,
+        label: t('advanceTickets.futureImport'),
+        name: 'futureTotalWithVat',
+        hidden: true,
+        headerClass: 'horizontal-separator',
+        format: (row) => toCurrency(row.futureTotalWithVat),
     },
 ]);
 
@@ -329,7 +208,7 @@ const requestComponentUpdate = async (ticket, isWithoutNegatives) => {
     const query = `tickets/${ticket.futureId}/componentUpdate`;
     if (!ticket.landed) {
         const newLanded = await getLanded({
-            shipped: userParams.dateToAdvance,
+            shipped: vnTableRef.value.params.dateToAdvance,
             addressFk: ticket.futureAddressFk,
             agencyModeFk: ticket.agencyModeFk ?? ticket.futureAgencyModeFk,
             warehouseFk: ticket.futureWarehouseFk,
@@ -352,7 +231,7 @@ const requestComponentUpdate = async (ticket, isWithoutNegatives) => {
         zoneFk: ticket.zoneFk ?? ticket.futureZoneFk,
         warehouseFk: ticket.futureWarehouseFk,
         companyFk: ticket.futureCompanyFk,
-        shipped: userParams.dateToAdvance,
+        shipped: vnTableRef.value.params.dateToAdvance,
         landed: ticket.landed,
         isDeleted: false,
         isWithoutNegatives,
@@ -387,7 +266,7 @@ const moveTicketsAdvance = async () => {
 
         const params = { tickets: ticketsToMove };
         await axios.post('Tickets/merge', params);
-        arrayData.fetch({ append: false });
+        vnTableRef.value.reload();
         selectedTickets.value = [];
         if (ticketsToMove.length)
             notify(t('advanceTickets.moveTicketSuccess'), 'positive');
@@ -437,7 +316,7 @@ const splitTickets = async () => {
     } catch (error) {
         console.error('Error splitting tickets', error);
     } finally {
-        arrayData.fetch({ append: false });
+        vnTableRef.value.reload();
     }
 };
 
@@ -455,21 +334,52 @@ const handleCloseProgressDialog = () => {
 
 const handleCancelProgress = () => (cancelProgress.value = true);
 
-onMounted(async () => {
-    let today = Date.vnNew().toISOString();
-    const tomorrow = new Date(today);
-    tomorrow.setDate(tomorrow.getDate() + 1);
-    userParams.dateFuture = tomorrow;
-    userParams.dateToAdvance = today;
-    userParams.warehouseFk = user.value.warehouseFk;
-    userParams.ipt = 'H';
-    userParams.futureIpt = 'H';
-    userParams.isFullMovable = true;
-    const filter = { limit: 0 };
-    await arrayData.addFilter({ filter, userParams });
-});
-</script>
+watch(
+    () => vnTableRef.value.tableRef?.$el,
+    ($el) => {
+        if (!$el) return;
+        const head = $el.querySelector('thead');
+        const firstRow = $el.querySelector('thead > tr');
 
+        const newRow = document.createElement('tr');
+        destinationElRef.value = document.createElement('th');
+        originElRef.value = document.createElement('th');
+
+        newRow.classList.add('bg-header');
+        destinationElRef.value.classList.add('text-uppercase', 'color-vn-label');
+        originElRef.value.classList.add('text-uppercase', 'color-vn-label');
+
+        destinationElRef.value.setAttribute('colspan', '7');
+        originElRef.value.setAttribute('colspan', '9');
+
+        destinationElRef.value.textContent = `${t(
+            'advanceTickets.destination'
+        )} ${toDateFormat(vnTableRef.value.params.dateToAdvance)}`;
+        originElRef.value.textContent = `${t('advanceTickets.origin')} ${toDateFormat(
+            vnTableRef.value.params.dateFuture
+        )}`;
+
+        newRow.append(destinationElRef.value, originElRef.value);
+        head.insertBefore(newRow, firstRow);
+    },
+    { once: true, inmmediate: true }
+);
+
+watch(
+    () => vnTableRef.value.params,
+    () => {
+        if (originElRef.value && destinationElRef.value) {
+            destinationElRef.value.textContent = `${t(
+                'advanceTickets.destination'
+            )} ${toDateFormat(vnTableRef.value.params.dateToAdvance)}`;
+            originElRef.value.textContent = `${t('advanceTickets.origin')} ${toDateFormat(
+                vnTableRef.value.params.dateFuture
+            )}`;
+        }
+    },
+    { deep: true }
+);
+</script>
 <template>
     <FetchData
         url="itemPackingTypes"
@@ -490,8 +400,9 @@ onMounted(async () => {
         auto-load
         @on-fetch="(data) => (zonesOptions = data)"
     />
+    <!-- Fix searchbar #8154 -->
     <VnSearchbar
-        data-key="WeeklyTickets"
+        data-key="advanceTickets"
         :label="t('weeklyTickets.search')"
         :info="t('weeklyTickets.searchInfo')"
     />
@@ -538,173 +449,109 @@ onMounted(async () => {
     </VnSubToolbar>
     <RightMenu>
         <template #right-panel>
-            <TicketAdvanceFilter data-key="AdvanceTickets" />
+            <TicketAdvanceFilter data-key="advanceTickets" />
         </template>
     </RightMenu>
     <QPage class="column items-center q-pa-md">
-        <QTable
-            :rows="tickets"
+        <VnTable
+            data-key="advanceTickets"
+            ref="vnTableRef"
+            url="Tickets/getTicketsAdvance"
+            search-url="advanceTickets"
+            :user-params="userParams"
+            :limit="0"
             :columns="ticketColumns"
-            row-key="index"
-            selection="multiple"
+            :table="{
+                'row-key': '$index',
+                selection: 'multiple',
+            }"
             v-model:selected="selectedTickets"
             :pagination="{ rowsPerPage: 0 }"
             :no-data-label="t('globals.noResults')"
-            style="max-width: 99%"
+            :right-search="false"
+            auto-load
+            :disable-option="{ card: true }"
         >
-            <template #header="props">
-                <QTr :props="props">
-                    <QTh
-                        class="horizontal-separator text-uppercase color-vn-label"
-                        colspan="7"
-                        translate
-                    >
-                        {{ t('advanceTickets.destination') }}
-                        {{ toDateFormat(userParams.dateToAdvance) }}
-                    </QTh>
-                    <QTh
-                        class="horizontal-separator text-uppercase color-vn-label"
-                        colspan="9"
-                        translate
-                    >
-                        {{ t('advanceTickets.origin') }}
-                        {{ toDateFormat(userParams.dateFuture) }}
-                    </QTh>
-                </QTr>
-                <QTr>
-                    <QTh>
-                        <QCheckbox v-model="props.selected" />
-                    </QTh>
-                    <QTh
-                        v-for="(col, index) in ticketColumns"
-                        :key="index"
-                        :class="{ 'vertical-separator': col.name === 'futureId' }"
-                    >
-                        {{ col.label }}
-                    </QTh>
-                </QTr>
+            <template #column-icons="{ row }">
+                <QIcon
+                    v-if="row.futureAgency !== row.agency && row.agency"
+                    color="primary"
+                    name="vn:agency-term"
+                    size="xs"
+                >
+                    <QTooltip class="column">
+                        <span>
+                            {{
+                                t('advanceTickets.originAgency', {
+                                    agency: row.futureAgency,
+                                })
+                            }}
+                        </span>
+                        <span>
+                            {{
+                                t('advanceTickets.destinationAgency', {
+                                    agency: row.agency,
+                                })
+                            }}
+                        </span>
+                    </QTooltip>
+                </QIcon>
             </template>
-            <template #top-row="{ cols }">
-                <QTr>
-                    <QTd />
-                    <QTd
-                        v-for="(col, index) in cols"
-                        :key="index"
-                        style="max-width: 100px"
-                    >
-                        <component
-                            :is="col.columnFilter.component"
-                            v-if="col.columnFilter"
-                            v-model="col.columnFilter.filterValue"
-                            v-bind="col.columnFilter.attrs"
-                            v-on="col.columnFilter.event(col)"
-                            dense
-                        />
-                    </QTd>
-                </QTr>
+            <template #column-id="{ row }">
+                <QBtn flat class="link">
+                    {{ row.id }}
+                    <TicketDescriptorProxy :id="row.id" />
+                </QBtn>
             </template>
-            <template #header-cell-availableLines="{ col }">
-                <QTh class="vertical-separator">
-                    {{ col.label }}
-                </QTh>
+            <template #column-state="{ row }">
+                <QBadge
+                    v-if="row.state"
+                    text-color="black"
+                    :color="row.classColor"
+                    class="q-ma-none"
+                    dense
+                >
+                    {{ row.state }}
+                </QBadge>
+                <span v-else> {{ dashIfEmpty(row.state) }}</span>
             </template>
-            <template #body-cell-icons="{ row }">
-                <QTd class="q-gutter-x-xs">
-                    <QIcon
-                        v-if="row.futureAgency !== row.agency && row.agency"
-                        color="primary"
-                        name="vn:agency-term"
-                        size="xs"
-                    >
-                        <QTooltip class="column">
-                            <span>
-                                {{
-                                    t('advanceTickets.originAgency', {
-                                        agency: row.futureAgency,
-                                    })
-                                }}
-                            </span>
-                            <span>
-                                {{
-                                    t('advanceTickets.destinationAgency', {
-                                        agency: row.agency,
-                                    })
-                                }}
-                            </span>
-                        </QTooltip>
-                    </QIcon>
-                </QTd>
+            <template #column-import="{ row }">
+                <QBadge
+                    :text-color="isLessThan50(row.totalWithVat) ? 'black' : 'white'"
+                    :color="totalPriceColor(row.totalWithVat)"
+                    class="q-ma-none"
+                    dense
+                >
+                    {{ toCurrency(row.totalWithVat || 0) }}
+                </QBadge>
             </template>
-
-            <template #body-cell-ticketId="{ row }">
-                <QTd>
-                    <QBtn flat class="link">
-                        {{ row.id }}
-                        <TicketDescriptorProxy :id="row.id" />
-                    </QBtn>
-                </QTd>
+            <template #column-futureId="{ row }">
+                <QBtn flat class="link" dense>
+                    {{ row.futureId }}
+                    <TicketDescriptorProxy :id="row.futureId" />
+                </QBtn>
             </template>
-            <template #body-cell-state="{ row }">
-                <QTd>
-                    <QBadge
-                        v-if="row.state"
-                        text-color="black"
-                        :color="row.classColor"
-                        class="q-ma-none"
-                        dense
-                    >
-                        {{ row.state }}
-                    </QBadge>
-                    <span v-else> {{ dashIfEmpty(row.state) }}</span>
-                </QTd>
+            <template #column-futureState="{ row }">
+                <QBadge
+                    text-color="black"
+                    :color="row.futureClassColor"
+                    class="q-ma-none"
+                    dense
+                >
+                    {{ row.futureState }}
+                </QBadge>
             </template>
-            <template #body-cell-import="{ row }">
-                <QTd>
-                    <QBadge
-                        :text-color="isLessThan50(row.totalWithVat) ? 'black' : 'white'"
-                        :color="totalPriceColor(row.totalWithVat)"
-                        class="q-ma-none"
-                        dense
-                    >
-                        {{ toCurrency(row.totalWithVat || 0) }}
-                    </QBadge>
-                </QTd>
+            <template #column-futureImport="{ row }">
+                <QBadge
+                    :text-color="isLessThan50(row.futureTotalWithVat) ? 'black' : 'white'"
+                    :color="totalPriceColor(row.futureTotalWithVat)"
+                    class="q-ma-none"
+                    dense
+                >
+                    {{ toCurrency(row.futureTotalWithVat || 0) }}
+                </QBadge>
             </template>
-            <template #body-cell-futureId="{ row }">
-                <QTd class="vertical-separator">
-                    <QBtn flat class="link" dense>
-                        {{ row.futureId }}
-                        <TicketDescriptorProxy :id="row.futureId" />
-                    </QBtn>
-                </QTd>
-            </template>
-            <template #body-cell-futureState="{ row }">
-                <QTd>
-                    <QBadge
-                        text-color="black"
-                        :color="row.futureClassColor"
-                        class="q-ma-none"
-                        dense
-                    >
-                        {{ row.futureState }}
-                    </QBadge>
-                </QTd>
-            </template>
-            <template #body-cell-futureImport="{ row }">
-                <QTd>
-                    <QBadge
-                        :text-color="
-                            isLessThan50(row.futureTotalWithVat) ? 'black' : 'white'
-                        "
-                        :color="totalPriceColor(row.futureTotalWithVat)"
-                        class="q-ma-none"
-                        dense
-                    >
-                        {{ toCurrency(row.futureTotalWithVat || 0) }}
-                    </QBadge>
-                </QTd>
-            </template>
-        </QTable>
+        </VnTable>
         <VnProgress
             :progress="progressPercentage"
             :cancelled="cancelProgress"
@@ -723,11 +570,11 @@ onMounted(async () => {
 </template>
 
 <style scoped lang="scss">
-.vertical-separator {
+:deep(.vertical-separator) {
     border-left: 4px solid white !important;
 }
 
-.horizontal-separator {
-    border-bottom: 4px solid white !important;
+:deep(.horizontal-separator) {
+    border-top: 4px solid white !important;
 }
 </style>
diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index 182f715a3..1d08d1ebf 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -57,6 +57,7 @@ onMounted(async () => await getItemPackingTypes());
         auto-load
     />
     <VnFilterPanel
+        search-url="advanceTickets"
         :data-key="props.dataKey"
         :search-button="true"
         :hidden-tags="['search']"
@@ -100,6 +101,7 @@ onMounted(async () => await getItemPackingTypes());
                         dense
                         outlined
                         rounded
+                        :use-like="false"
                     >
                     </VnSelect>
                 </QItemSection>
@@ -117,6 +119,7 @@ onMounted(async () => await getItemPackingTypes());
                         dense
                         outlined
                         rounded
+                        :use-like="false"
                     >
                     </VnSelect>
                 </QItemSection>

From d918b76010c5ec8efa76cfec1298ba4c5cf0749b Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Thu, 24 Oct 2024 10:24:28 +0200
Subject: [PATCH 75/87] chore: refs #7524 drop useless code

---
 src/pages/Ticket/TicketAdvance.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index 8b109d778..f6fb37e21 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, computed, reactive, watch, h } from 'vue';
+import { ref, computed, reactive, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import FetchData from 'components/FetchData.vue';
 import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';

From 87d2e0a39b1ee2d12e8468a0ca802168d32273f8 Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Thu, 24 Oct 2024 10:36:48 +0200
Subject: [PATCH 76/87] perf: refs #7283 #7283 handle composable i18n

---
 src/i18n/locale/es.yml                  | 108 -----------------------
 src/pages/Item/Card/ItemDescriptor.vue  |   2 -
 src/pages/Item/ItemList.vue             |   2 -
 src/pages/Item/composables/cloneItem.js |   8 +-
 src/pages/Item/locale/en.yml            | 112 ++++++++++++++++++++++++
 src/pages/Item/locale/es.yml            | 112 ++++++++++++++++++++++++
 6 files changed, 227 insertions(+), 117 deletions(-)

diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 7c368b7b7..bd414a793 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -1053,114 +1053,6 @@ travel:
         warehouse: Almacén
         travelFileDescription: 'Id envío { travelId }'
         file: Fichero
-item:
-    searchbar:
-        label: Buscar artículo
-    descriptor:
-        item: Artículo
-        buyer: Comprador
-        color: Color
-        category: Categoría
-        stems: Tallos
-        visible: Visible
-        available: Disponible
-        warehouseText: 'Calculado sobre el almacén de { warehouseName }'
-        itemDiary: Registro de compra-venta
-        producer: Productor
-    list:
-        id: Identificador
-        grouping: Grouping
-        packing: Packing
-        description: Descripción
-        stems: Tallos
-        category: Reino
-        typeName: Tipo
-        intrastat: Intrastat
-        isActive: Activo
-        size: Medida
-        origin: Origen
-        weightByPiece: Peso (gramos)/tallo
-        userName: Comprador
-        stemMultiplier: Multiplicador
-        producer: Productor
-        landed: F. entrega
-    basicData:
-        type: Tipo
-        reference: Referencia
-        relevancy: Relevancia
-        stems: Tallos
-        multiplier: Multiplicador
-        generic: Genérico
-        intrastat: Intrastat
-        expense: Gasto
-        weightByPiece: Peso (gramos)/tallo
-        boxUnits: Unidades/caja
-        recycledPlastic: Plastico reciclado
-        nonRecycledPlastic: Plático no reciclado
-        isActive: Activo
-        hasKgPrice: Precio en kg
-        isFragile: Frágil
-        isFragileTooltip: Se muestra en la web, app que este artículo no puede viajar (coronas, palmas, ...)
-        isPhotoRequested: Hacer foto
-        isPhotoRequestedTooltip: Este artículo necesita una foto
-        description: Descripción
-    fixedPrice:
-        itemFk: ID Artículo
-        groupingPrice: Precio grouping
-        packingPrice: Precio packing
-        hasMinPrice: Tiene precio mínimo
-        minPrice: Precio min
-        started: Inicio
-        ended: Fin
-        warehouse: Almacén
-    create:
-        name: Nombre
-        tag: Etiqueta
-        priority: Prioridad
-        type: Tipo
-        intrastat: Intrastat
-        origin: Origen
-    summary:
-        basicData: 'Datos básicos'
-        otherData: 'Otros datos'
-        description: 'Descripción'
-        tax: 'IVA'
-        tags: 'Etiquetas'
-        botanical: 'Botánico'
-        barcode: 'Código de barras'
-        name: 'Nombre'
-        completeName: 'Nombre completo'
-        family: 'Familia'
-        size: 'Medida'
-        origin: 'Origen'
-        stems: 'Tallos'
-        multiplier: 'Multiplicador'
-        buyer: 'Comprador'
-        doPhoto: 'Hacer foto'
-        intrastatCode: 'Código intrastat'
-        intrastat: 'Intrastat'
-        ref: 'Referencia'
-        relevance: 'Relevancia'
-        weight: 'Peso (gramos)/tallo'
-        units: 'Unidades/caja'
-        expense: 'Gasto'
-        generic: 'Genérico'
-        recycledPlastic: 'Plástico reciclado'
-        nonRecycledPlastic: 'Plástico no reciclado'
-        minSalesQuantity: 'Cantidad mínima de venta'
-        genus: 'Genus'
-        specie: 'Specie'
-    buyRequest:
-        ticketId: 'ID Ticket'
-        shipped: 'F. envío'
-        requester: 'Solicitante'
-        requested: 'Solicitado'
-        price: 'Precio'
-        attender: 'Comprador'
-        item: 'Artículo'
-        achieved: 'Conseguido'
-        concept: 'Concepto'
-        state: 'Estado'
 components:
     topbar: {}
     itemsFilterPanel:
diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index 6fbc5a4bd..243d4c7cb 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -195,8 +195,6 @@ const openRegularizeStockForm = () => {
 <i18n>
 es:
     Regularize stock: Regularizar stock
-    All its properties will be copied: Todas sus propiedades serán copiadas
-    Do you want to clone this item?: ¿Desea clonar este artículo?
     Inactive article: Artículo inactivo
 </i18n>
 
diff --git a/src/pages/Item/ItemList.vue b/src/pages/Item/ItemList.vue
index 30b86bc11..cca5560fe 100644
--- a/src/pages/Item/ItemList.vue
+++ b/src/pages/Item/ItemList.vue
@@ -355,8 +355,6 @@ const columns = computed(() => [
 <i18n>
 es:
     New item: Nuevo artículo
-    All its properties will be copied: Todas sus propiedades serán copiadas
-    Do you want to clone this item?: ¿Desea clonar este artículo?
     Preview: Vista previa
     Regularize stock: Regularizar stock
 </i18n>
diff --git a/src/pages/Item/composables/cloneItem.js b/src/pages/Item/composables/cloneItem.js
index f1114c779..2421c0808 100644
--- a/src/pages/Item/composables/cloneItem.js
+++ b/src/pages/Item/composables/cloneItem.js
@@ -1,6 +1,5 @@
 import axios from 'axios';
-import { computed, ref, onMounted } from 'vue';
-import { useRoute, useRouter } from 'vue-router';
+import { useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { useQuasar } from 'quasar';
 import VnConfirm from 'components/ui/VnConfirm.vue';
@@ -9,7 +8,6 @@ export function cloneItem() {
     const { t } = useI18n();
 
     const quasar = useQuasar();
-    const route = useRoute();
     const router = useRouter();
     const cloneItem = async (entityId) => {
         const { id } = entityId;
@@ -26,8 +24,8 @@ export function cloneItem() {
             .dialog({
                 component: VnConfirm,
                 componentProps: {
-                    title: t('All its properties will be copied'),
-                    message: t('Do you want to clone this item?'),
+                    title: t('item.descriptor.clone.title'),
+                    message: t('item.descriptor.clone.subTitle'),
                 },
             })
             .onOk(async () => {
diff --git a/src/pages/Item/locale/en.yml b/src/pages/Item/locale/en.yml
index c32ee493c..034e39a17 100644
--- a/src/pages/Item/locale/en.yml
+++ b/src/pages/Item/locale/en.yml
@@ -88,3 +88,115 @@ itemType:
         worker: Worker
         category: Category
         temperature: Temperature
+item:
+    searchbar:
+        label: Search item
+    descriptor:
+        item: Item
+        buyer: Buyer
+        color: Color
+        category: Category
+        stems: Stems
+        visible: Visible
+        available: Available
+        warehouseText: 'Calculated on the warehouse of { warehouseName }'
+        itemDiary: Item diary
+        producer: Producer
+        clone:
+            title: All its properties will be copied
+            subTitle: Do you want to clone this item?
+
+    list:
+        id: Identifier
+        grouping: Grouping
+        packing: Packing
+        description: Description
+        stems: Stems
+        category: Category
+        typeName: Type
+        intrastat: Intrastat
+        isActive: Active
+        size: Size
+        origin: Origin
+        userName: Buyer
+        weightByPiece: Weight/Piece
+        stemMultiplier: Multiplier
+        producer: Producer
+        landed: Landed
+    basicData:
+        type: Type
+        reference: Reference
+        relevancy: Relevancy
+        stems: Stems
+        multiplier: Multiplier
+        generic: Generic
+        intrastat: Intrastat
+        expense: Expense
+        weightByPiece: Weight/Piece
+        boxUnits: Units/Box
+        recycledPlastic: Recycled Plastic
+        nonRecycledPlastic: Non recycled plastic
+        isActive: Active
+        hasKgPrice: Price in kg
+        isFragile: Fragile
+        isFragileTooltip: Is shown at website, app that this item cannot travel (wreath, palms, ...)
+        isPhotoRequested: Do photo
+        isPhotoRequestedTooltip: This item does need a photo
+        description: Description
+    fixedPrice:
+        itemFk: Item ID
+        groupingPrice: Grouping price
+        packingPrice: Packing price
+        hasMinPrice: Has min price
+        minPrice: Min price
+        started: Started
+        ended: Ended
+        warehouse: Warehouse
+    create:
+        name: Name
+        tag: Tag
+        priority: Priority
+        type: Type
+        intrastat: Intrastat
+        origin: Origin
+    buyRequest:
+        ticketId: 'Ticket ID'
+        shipped: 'Shipped'
+        requester: 'Requester'
+        requested: 'Requested'
+        price: 'Price'
+        attender: 'Attender'
+        item: 'Item'
+        achieved: 'Achieved'
+        concept: 'Concept'
+        state: 'State'
+    summary:
+        basicData: 'Basic data'
+        otherData: 'Other data'
+        description: 'Description'
+        tax: 'Tax'
+        tags: 'Tags'
+        botanical: 'Botanical'
+        barcode: 'Barcode'
+        name: 'Nombre'
+        completeName: 'Nombre completo'
+        family: 'Familia'
+        size: 'Medida'
+        origin: 'Origen'
+        stems: 'Tallos'
+        multiplier: 'Multiplicador'
+        buyer: 'Comprador'
+        doPhoto: 'Do photo'
+        intrastatCode: 'Código intrastat'
+        intrastat: 'Intrastat'
+        ref: 'Referencia'
+        relevance: 'Relevancia'
+        weight: 'Peso (gramos)/tallo'
+        units: 'Unidades/caja'
+        expense: 'Gasto'
+        generic: 'Genérico'
+        recycledPlastic: 'Plástico reciclado'
+        nonRecycledPlastic: 'Plástico no reciclado'
+        minSalesQuantity: 'Cantidad mínima de venta'
+        genus: 'Genus'
+        specie: 'Specie'
diff --git a/src/pages/Item/locale/es.yml b/src/pages/Item/locale/es.yml
index d32cb7885..917bd7e5f 100644
--- a/src/pages/Item/locale/es.yml
+++ b/src/pages/Item/locale/es.yml
@@ -88,3 +88,115 @@ itemType:
         worker: Trabajador
         category: Reino
         temperature: Temperatura
+item:
+    searchbar:
+        label: Buscar artículo
+    descriptor:
+        item: Artículo
+        buyer: Comprador
+        color: Color
+        category: Categoría
+        stems: Tallos
+        visible: Visible
+        available: Disponible
+        warehouseText: 'Calculado sobre el almacén de { warehouseName }'
+        itemDiary: Registro de compra-venta
+        producer: Productor
+        clone:
+            title: Todas sus propiedades serán copiadas
+            subTitle: ¿Desea clonar este artículo?
+
+    list:
+        id: Identificador
+        grouping: Grouping
+        packing: Packing
+        description: Descripción
+        stems: Tallos
+        category: Reino
+        typeName: Tipo
+        intrastat: Intrastat
+        isActive: Activo
+        size: Medida
+        origin: Origen
+        weightByPiece: Peso (gramos)/tallo
+        userName: Comprador
+        stemMultiplier: Multiplicador
+        producer: Productor
+        landed: F. entrega
+    basicData:
+        type: Tipo
+        reference: Referencia
+        relevancy: Relevancia
+        stems: Tallos
+        multiplier: Multiplicador
+        generic: Genérico
+        intrastat: Intrastat
+        expense: Gasto
+        weightByPiece: Peso (gramos)/tallo
+        boxUnits: Unidades/caja
+        recycledPlastic: Plastico reciclado
+        nonRecycledPlastic: Plático no reciclado
+        isActive: Activo
+        hasKgPrice: Precio en kg
+        isFragile: Frágil
+        isFragileTooltip: Se muestra en la web, app que este artículo no puede viajar (coronas, palmas, ...)
+        isPhotoRequested: Hacer foto
+        isPhotoRequestedTooltip: Este artículo necesita una foto
+        description: Descripción
+    fixedPrice:
+        itemFk: ID Artículo
+        groupingPrice: Precio grouping
+        packingPrice: Precio packing
+        hasMinPrice: Tiene precio mínimo
+        minPrice: Precio min
+        started: Inicio
+        ended: Fin
+        warehouse: Almacén
+    create:
+        name: Nombre
+        tag: Etiqueta
+        priority: Prioridad
+        type: Tipo
+        intrastat: Intrastat
+        origin: Origen
+    summary:
+        basicData: 'Datos básicos'
+        otherData: 'Otros datos'
+        description: 'Descripción'
+        tax: 'IVA'
+        tags: 'Etiquetas'
+        botanical: 'Botánico'
+        barcode: 'Código de barras'
+        name: 'Nombre'
+        completeName: 'Nombre completo'
+        family: 'Familia'
+        size: 'Medida'
+        origin: 'Origen'
+        stems: 'Tallos'
+        multiplier: 'Multiplicador'
+        buyer: 'Comprador'
+        doPhoto: 'Hacer foto'
+        intrastatCode: 'Código intrastat'
+        intrastat: 'Intrastat'
+        ref: 'Referencia'
+        relevance: 'Relevancia'
+        weight: 'Peso (gramos)/tallo'
+        units: 'Unidades/caja'
+        expense: 'Gasto'
+        generic: 'Genérico'
+        recycledPlastic: 'Plástico reciclado'
+        nonRecycledPlastic: 'Plástico no reciclado'
+        minSalesQuantity: 'Cantidad mínima de venta'
+        genus: 'Genus'
+        specie: 'Specie'
+    buyRequest:
+        ticketId: 'ID Ticket'
+        shipped: 'F. envío'
+        requester: 'Solicitante'
+        requested: 'Solicitado'
+        price: 'Precio'
+        attender: 'Comprador'
+        item: 'Artículo'
+        achieved: 'Conseguido'
+        concept: 'Concepto'
+        state: 'Estado'

From f1350dece519b9a832656c6434eb910619fd618e Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Thu, 24 Oct 2024 11:43:29 +0200
Subject: [PATCH 77/87] fix: refs #7524 changes

---
 src/pages/Ticket/TicketAdvance.vue | 57 ++++++++++++------------------
 1 file changed, 22 insertions(+), 35 deletions(-)

diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index f6fb37e21..7db2b54b3 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -243,36 +243,31 @@ const requestComponentUpdate = async (ticket, isWithoutNegatives) => {
 };
 
 const moveTicketsAdvance = async () => {
-    try {
-        let ticketsToMove = [];
-        for (const ticket of selectedTickets.value) {
-            if (!ticket.id) {
-                try {
-                    const { query, params } = await requestComponentUpdate(ticket, false);
-                    axios.post(query, params);
-                } catch (e) {
-                    console.error('Error moving ticket', e);
-                }
-                continue;
+    let ticketsToMove = [];
+    for (const ticket of selectedTickets.value) {
+        if (!ticket.id) {
+            try {
+                const { query, params } = await requestComponentUpdate(ticket, false);
+                axios.post(query, params);
+            } catch (e) {
+                console.error('Error moving ticket', e);
             }
-            ticketsToMove.push({
-                originId: ticket.futureId,
-                destinationId: ticket.id,
-                originShipped: ticket.futureShipped,
-                destinationShipped: ticket.shipped,
-                workerFk: ticket.workerFk,
-            });
+            continue;
         }
-
-        const params = { tickets: ticketsToMove };
-        await axios.post('Tickets/merge', params);
-        vnTableRef.value.reload();
-        selectedTickets.value = [];
-        if (ticketsToMove.length)
-            notify(t('advanceTickets.moveTicketSuccess'), 'positive');
-    } catch (error) {
-        console.error('Error moving tickets', error);
+        ticketsToMove.push({
+            originId: ticket.futureId,
+            destinationId: ticket.id,
+            originShipped: ticket.futureShipped,
+            destinationShipped: ticket.shipped,
+            workerFk: ticket.workerFk,
+        });
     }
+
+    const params = { tickets: ticketsToMove };
+    await axios.post('Tickets/merge', params);
+    vnTableRef.value.reload();
+    selectedTickets.value = [];
+    if (ticketsToMove.length) notify(t('advanceTickets.moveTicketSuccess'), 'positive');
 };
 
 const progressLength = ref(0);
@@ -313,8 +308,6 @@ const splitTickets = async () => {
                 progressAdd(ticket.futureId);
             }
         }
-    } catch (error) {
-        console.error('Error splitting tickets', error);
     } finally {
         vnTableRef.value.reload();
     }
@@ -400,12 +393,6 @@ watch(
         auto-load
         @on-fetch="(data) => (zonesOptions = data)"
     />
-    <!-- Fix searchbar #8154 -->
-    <VnSearchbar
-        data-key="advanceTickets"
-        :label="t('weeklyTickets.search')"
-        :info="t('weeklyTickets.searchInfo')"
-    />
     <VnSubToolbar>
         <template #st-data>
             <QBtn

From c9cfb2b1cf38854ca7c7d36217c25776540a8cd5 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Thu, 24 Oct 2024 12:29:46 +0200
Subject: [PATCH 78/87] fix: refs #7524 changes

---
 src/pages/Ticket/TicketAdvance.vue | 57 ++++++++++++------------------
 1 file changed, 22 insertions(+), 35 deletions(-)

diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index f6fb37e21..7db2b54b3 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -243,36 +243,31 @@ const requestComponentUpdate = async (ticket, isWithoutNegatives) => {
 };
 
 const moveTicketsAdvance = async () => {
-    try {
-        let ticketsToMove = [];
-        for (const ticket of selectedTickets.value) {
-            if (!ticket.id) {
-                try {
-                    const { query, params } = await requestComponentUpdate(ticket, false);
-                    axios.post(query, params);
-                } catch (e) {
-                    console.error('Error moving ticket', e);
-                }
-                continue;
+    let ticketsToMove = [];
+    for (const ticket of selectedTickets.value) {
+        if (!ticket.id) {
+            try {
+                const { query, params } = await requestComponentUpdate(ticket, false);
+                axios.post(query, params);
+            } catch (e) {
+                console.error('Error moving ticket', e);
             }
-            ticketsToMove.push({
-                originId: ticket.futureId,
-                destinationId: ticket.id,
-                originShipped: ticket.futureShipped,
-                destinationShipped: ticket.shipped,
-                workerFk: ticket.workerFk,
-            });
+            continue;
         }
-
-        const params = { tickets: ticketsToMove };
-        await axios.post('Tickets/merge', params);
-        vnTableRef.value.reload();
-        selectedTickets.value = [];
-        if (ticketsToMove.length)
-            notify(t('advanceTickets.moveTicketSuccess'), 'positive');
-    } catch (error) {
-        console.error('Error moving tickets', error);
+        ticketsToMove.push({
+            originId: ticket.futureId,
+            destinationId: ticket.id,
+            originShipped: ticket.futureShipped,
+            destinationShipped: ticket.shipped,
+            workerFk: ticket.workerFk,
+        });
     }
+
+    const params = { tickets: ticketsToMove };
+    await axios.post('Tickets/merge', params);
+    vnTableRef.value.reload();
+    selectedTickets.value = [];
+    if (ticketsToMove.length) notify(t('advanceTickets.moveTicketSuccess'), 'positive');
 };
 
 const progressLength = ref(0);
@@ -313,8 +308,6 @@ const splitTickets = async () => {
                 progressAdd(ticket.futureId);
             }
         }
-    } catch (error) {
-        console.error('Error splitting tickets', error);
     } finally {
         vnTableRef.value.reload();
     }
@@ -400,12 +393,6 @@ watch(
         auto-load
         @on-fetch="(data) => (zonesOptions = data)"
     />
-    <!-- Fix searchbar #8154 -->
-    <VnSearchbar
-        data-key="advanceTickets"
-        :label="t('weeklyTickets.search')"
-        :info="t('weeklyTickets.searchInfo')"
-    />
     <VnSubToolbar>
         <template #st-data>
             <QBtn

From 3f640c650b12152f3a086464d3b0140a5bc6198d Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Thu, 24 Oct 2024 12:32:15 +0200
Subject: [PATCH 79/87] perf: refs #7283 #7283 handle i18n

---
 src/i18n/locale/en.yml       | 108 -----------------------------------
 src/pages/Item/locale/en.yml |   1 -
 src/pages/Item/locale/es.yml |   1 -
 3 files changed, 110 deletions(-)

diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index b19363c12..c1748c8ff 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -1055,114 +1055,6 @@ travel:
         warehouse: Warehouse
         travelFileDescription: 'Travel id { travelId }'
         file: File
-item:
-    searchbar:
-        label: Search item
-    descriptor:
-        item: Item
-        buyer: Buyer
-        color: Color
-        category: Category
-        stems: Stems
-        visible: Visible
-        available: Available
-        warehouseText: 'Calculated on the warehouse of { warehouseName }'
-        itemDiary: Item diary
-        producer: Producer
-    list:
-        id: Identifier
-        grouping: Grouping
-        packing: Packing
-        description: Description
-        stems: Stems
-        category: Category
-        typeName: Type
-        intrastat: Intrastat
-        isActive: Active
-        size: Size
-        origin: Origin
-        userName: Buyer
-        weightByPiece: Weight/Piece
-        stemMultiplier: Multiplier
-        producer: Producer
-        landed: Landed
-    basicData:
-        type: Type
-        reference: Reference
-        relevancy: Relevancy
-        stems: Stems
-        multiplier: Multiplier
-        generic: Generic
-        intrastat: Intrastat
-        expense: Expense
-        weightByPiece: Weight/Piece
-        boxUnits: Units/Box
-        recycledPlastic: Recycled Plastic
-        nonRecycledPlastic: Non recycled plastic
-        isActive: Active
-        hasKgPrice: Price in kg
-        isFragile: Fragile
-        isFragileTooltip: Is shown at website, app that this item cannot travel (wreath, palms, ...)
-        isPhotoRequested: Do photo
-        isPhotoRequestedTooltip: This item does need a photo
-        description: Description
-    fixedPrice:
-        itemFk: Item ID
-        groupingPrice: Grouping price
-        packingPrice: Packing price
-        hasMinPrice: Has min price
-        minPrice: Min price
-        started: Started
-        ended: Ended
-        warehouse: Warehouse
-    create:
-        name: Name
-        tag: Tag
-        priority: Priority
-        type: Type
-        intrastat: Intrastat
-        origin: Origin
-    buyRequest:
-        ticketId: 'Ticket ID'
-        shipped: 'Shipped'
-        requester: 'Requester'
-        requested: 'Requested'
-        price: 'Price'
-        attender: 'Attender'
-        item: 'Item'
-        achieved: 'Achieved'
-        concept: 'Concept'
-        state: 'State'
-    summary:
-        basicData: 'Basic data'
-        otherData: 'Other data'
-        description: 'Description'
-        tax: 'Tax'
-        tags: 'Tags'
-        botanical: 'Botanical'
-        barcode: 'Barcode'
-        name: 'Nombre'
-        completeName: 'Nombre completo'
-        family: 'Familia'
-        size: 'Medida'
-        origin: 'Origen'
-        stems: 'Tallos'
-        multiplier: 'Multiplicador'
-        buyer: 'Comprador'
-        doPhoto: 'Do photo'
-        intrastatCode: 'Código intrastat'
-        intrastat: 'Intrastat'
-        ref: 'Referencia'
-        relevance: 'Relevancia'
-        weight: 'Peso (gramos)/tallo'
-        units: 'Unidades/caja'
-        expense: 'Gasto'
-        generic: 'Genérico'
-        recycledPlastic: 'Plástico reciclado'
-        nonRecycledPlastic: 'Plástico no reciclado'
-        minSalesQuantity: 'Cantidad mínima de venta'
-        genus: 'Genus'
-        specie: 'Specie'
 components:
     topbar: {}
     itemsFilterPanel:
diff --git a/src/pages/Item/locale/en.yml b/src/pages/Item/locale/en.yml
index 034e39a17..53310cbd0 100644
--- a/src/pages/Item/locale/en.yml
+++ b/src/pages/Item/locale/en.yml
@@ -105,7 +105,6 @@ item:
         clone:
             title: All its properties will be copied
             subTitle: Do you want to clone this item?
-
     list:
         id: Identifier
         grouping: Grouping
diff --git a/src/pages/Item/locale/es.yml b/src/pages/Item/locale/es.yml
index 917bd7e5f..1ade9b955 100644
--- a/src/pages/Item/locale/es.yml
+++ b/src/pages/Item/locale/es.yml
@@ -105,7 +105,6 @@ item:
         clone:
             title: Todas sus propiedades serán copiadas
             subTitle: ¿Desea clonar este artículo?
-
     list:
         id: Identificador
         grouping: Grouping

From f52b4c9a598dc400c3379f800b2f1157f339159f Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Thu, 24 Oct 2024 13:24:45 +0200
Subject: [PATCH 80/87] fix: refs #7524 vnProgressModal

---
 src/components/common/VnProgressModal.vue | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/src/components/common/VnProgressModal.vue b/src/components/common/VnProgressModal.vue
index cfd948d5f..99bf15a7e 100644
--- a/src/components/common/VnProgressModal.vue
+++ b/src/components/common/VnProgressModal.vue
@@ -9,10 +9,6 @@ const $props = defineProps({
         type: Number, //Progress value (1.0 > x > 0.0)
         required: true,
     },
-    showDialog: {
-        type: Boolean,
-        required: true,
-    },
     cancelled: {
         type: Boolean,
         required: false,
@@ -24,25 +20,17 @@ const emit = defineEmits(['cancel', 'close']);
 
 const dialogRef = ref(null);
 
-const _showDialog = computed({
-    get: () => $props.showDialog,
-    set: (value) => {
-        if (value) dialogRef.value.show();
-    },
+const showDialog = defineModel('showDialog', {
+    type: Boolean,
+    default: false,
 });
 
 const _progress = computed(() => $props.progress);
-
 const progressLabel = computed(() => `${Math.round($props.progress * 100)}%`);
-
-const cancel = () => {
-    dialogRef.value.hide();
-    emit('cancel');
-};
 </script>
 
 <template>
-    <QDialog ref="dialogRef" v-model="_showDialog" @hide="onDialogHide">
+    <QDialog ref="dialogRef" v-model="showDialog" @hide="emit('close')">
         <QCard class="full-width dialog">
             <QCardSection class="row">
                 <span class="text-h6">{{ t('Progress') }}</span>
@@ -80,7 +68,7 @@ const cancel = () => {
                     type="button"
                     flat
                     class="text-primary"
-                    @click="cancel()"
+                    v-close-popup
                 >
                     {{ t('globals.cancel') }}
                 </QBtn>

From 823c354ef1a376b988e34a7f2f50f6f210ee34b7 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Thu, 24 Oct 2024 13:27:08 +0200
Subject: [PATCH 81/87] fix: refs #7524 vnProgressModal

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

diff --git a/src/components/common/VnProgressModal.vue b/src/components/common/VnProgressModal.vue
index 99bf15a7e..23fb8ae70 100644
--- a/src/components/common/VnProgressModal.vue
+++ b/src/components/common/VnProgressModal.vue
@@ -35,7 +35,7 @@ const progressLabel = computed(() => `${Math.round($props.progress * 100)}%`);
             <QCardSection class="row">
                 <span class="text-h6">{{ t('Progress') }}</span>
                 <QSpace />
-                <QBtn icon="close" flat round dense @click="emit('close')" />
+                <QBtn icon="close" flat round dense v-close-popup />
             </QCardSection>
             <QCardSection>
                 <div class="column">

From 671d9fd6fb0f6686ade7b54bfe9e36b6d8a11a8c Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 24 Oct 2024 13:38:13 +0200
Subject: [PATCH 82/87] fix: refs #7283 itemtype fix

---
 src/pages/Item/ItemTypeList.vue | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/src/pages/Item/ItemTypeList.vue b/src/pages/Item/ItemTypeList.vue
index d9f7bba85..2c1153016 100644
--- a/src/pages/Item/ItemTypeList.vue
+++ b/src/pages/Item/ItemTypeList.vue
@@ -1,14 +1,14 @@
 <script setup>
 import { useI18n } from 'vue-i18n';
-import { useRoute } from 'vue-router';
 import { ref, computed } from 'vue';
 import ItemTypeSearchbar from '../ItemType/ItemTypeSearchbar.vue';
 import VnTable from 'components/VnTable/VnTable.vue';
+import FetchData from 'components/FetchData.vue';
 
-const route = useRoute();
 const { t } = useI18n();
 const tableRef = ref();
-const entityId = computed(() => route.params.id);
+const workerOptions = ref([]);
+const ItemCategoriesOptions = ref([]);
 
 const columns = computed(() => [
     {
@@ -40,7 +40,7 @@ const columns = computed(() => [
         create: true,
         component: 'select',
         attrs: {
-            url: 'Workers',
+            options: workerOptions.value,
             optionLabel: 'firstName',
             optionValue: 'id',
         },
@@ -54,8 +54,9 @@ const columns = computed(() => [
         create: true,
         component: 'select',
         attrs: {
-            url: 'ItemCategories',
+            options: ItemCategoriesOptions.value,
             fields: ['id', 'name'],
+            order: 'name ASC',
         },
         cardVisible: false,
         visible: false,
@@ -77,6 +78,18 @@ const columns = computed(() => [
 </script>
 
 <template>
+    <FetchData
+        url="Workers"
+        :filter="{ fields: ['id', 'firstName'], order: ['firstName ASC'] }"
+        @on-fetch="(data) => (workerOptions = data)"
+        auto-load
+    />
+    <FetchData
+        url="ItemCategories"
+        :filter="{ fields: ['id', 'name'], order: ['name ASC'] }"
+        @on-fetch="(data) => (ItemCategoriesOptions = data)"
+        auto-load
+    />
     <ItemTypeSearchbar />
     <VnTable
         ref="tableRef"
@@ -102,8 +115,8 @@ const columns = computed(() => [
         id: Id
         code: Código
         name: Nombre
-        worker: Encargado
-        ItemCategory: Categoría
+        worker: Trabajador
+        ItemCategory: Reino
         Temperature: Temperatura
         Create ItemTypes: Crear familia
     en:

From c2043902f8f77a6f4957b82d7f7576f540bf8f1e Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Thu, 24 Oct 2024 14:08:11 +0200
Subject: [PATCH 83/87] fix: refs #7283 fix required

---
 src/pages/Item/ItemRequestDenyForm.vue | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/pages/Item/ItemRequestDenyForm.vue b/src/pages/Item/ItemRequestDenyForm.vue
index be70fb799..c9a4cbe9c 100644
--- a/src/pages/Item/ItemRequestDenyForm.vue
+++ b/src/pages/Item/ItemRequestDenyForm.vue
@@ -10,6 +10,7 @@ defineProps({
     requestId: {
         type: Number,
         default: null,
+        required: true,
     },
 });
 
@@ -43,6 +44,7 @@ onMounted(async () => {
                         type="textarea"
                         v-model="data.observation"
                         fill-input
+                        :required="true"
                         autogrow
                     />
                 </div>

From 4828e32c9eec24cb349bb5c39cae075653d08538 Mon Sep 17 00:00:00 2001
From: jorgep <jorgep@verdnatura.es>
Date: Thu, 24 Oct 2024 14:26:16 +0200
Subject: [PATCH 84/87] fix: refs #7652 datakey

---
 src/pages/Worker/Card/WorkerDescriptor.vue      | 7 ++++++-
 src/pages/Worker/Card/WorkerDescriptorProxy.vue | 7 ++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue
index 3675d40f8..b9ccedbfc 100644
--- a/src/pages/Worker/Card/WorkerDescriptor.vue
+++ b/src/pages/Worker/Card/WorkerDescriptor.vue
@@ -17,6 +17,11 @@ const $props = defineProps({
         required: false,
         default: null,
     },
+    dataKey: {
+        type: String,
+        required: false,
+        default: 'workerData',
+    },
 });
 const image = ref(null);
 
@@ -70,7 +75,7 @@ const refetch = async () => await cardDescriptorRef.value.getData();
     <CardDescriptor
         ref="cardDescriptorRef"
         module="Worker"
-        data-key="workerData"
+        :data-key="dataKey"
         url="Workers/descriptor"
         :filter="{ where: { id: entityId } }"
         title="user.nickname"
diff --git a/src/pages/Worker/Card/WorkerDescriptorProxy.vue b/src/pages/Worker/Card/WorkerDescriptorProxy.vue
index a142570f9..43deb7821 100644
--- a/src/pages/Worker/Card/WorkerDescriptorProxy.vue
+++ b/src/pages/Worker/Card/WorkerDescriptorProxy.vue
@@ -12,6 +12,11 @@ const $props = defineProps({
 
 <template>
     <QPopupProxy>
-        <WorkerDescriptor v-if="$props.id" :id="$props.id" :summary="WorkerSummary" />
+        <WorkerDescriptor
+            v-if="$props.id"
+            :id="$props.id"
+            :summary="WorkerSummary"
+            data-key="workerDescriptorProxy"
+        />
     </QPopupProxy>
 </template>

From 855979d22d3397182210a661717880e7bb04ab2d Mon Sep 17 00:00:00 2001
From: Javier Segarra <jsegarra@verdnatura.es>
Date: Thu, 24 Oct 2024 14:59:14 +0200
Subject: [PATCH 85/87] perf: refs #7283 #7283 i18n params

---
 src/pages/Item/ItemRequest.vue |  1 +
 src/pages/Item/locale/en.yml   | 13 +++++++++++++
 src/pages/Item/locale/es.yml   | 15 +++++++++++++++
 3 files changed, 29 insertions(+)

diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index ea265e706..450031a0e 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -225,6 +225,7 @@ onMounted(async () => {
         :is-editable="true"
         auto-load
         :disable-option="{ card: true }"
+        chip-locale="item.params"
     >
         <template #column-ticketFk="{ row }">
             <span class="link">
diff --git a/src/pages/Item/locale/en.yml b/src/pages/Item/locale/en.yml
index 53310cbd0..e99853760 100644
--- a/src/pages/Item/locale/en.yml
+++ b/src/pages/Item/locale/en.yml
@@ -89,6 +89,19 @@ itemType:
         category: Category
         temperature: Temperature
 item:
+    params:
+        daysOnward: Days onward
+        search: General search
+        ticketFk: Ticket id
+        attenderFk: Atender
+        clientFk: Client id
+        warehouseFk: Warehouse
+        requesterFk: Salesperson
+        from: From
+        to: To
+        mine: For me
+        state: State
+        myTeam: My team
     searchbar:
         label: Search item
     descriptor:
diff --git a/src/pages/Item/locale/es.yml b/src/pages/Item/locale/es.yml
index 1ade9b955..56c6ec317 100644
--- a/src/pages/Item/locale/es.yml
+++ b/src/pages/Item/locale/es.yml
@@ -88,7 +88,22 @@ itemType:
         worker: Trabajador
         category: Reino
         temperature: Temperatura
+params:
+    state: asfsdf
 item:
+    params:
+        daysOnward: Días adelante
+        search: Búsqueda general
+        ticketFk: Id ticket
+        attenderFk: Comprador
+        clientFk: Id cliente
+        warehouseFk: Almacén
+        requesterFk: Comercial
+        from: Desde
+        to: Hasta
+        mine: Para mi
+        state: Estado
+        myTeam: Mi equipo
     searchbar:
         label: Buscar artículo
     descriptor:

From 92e147355fea8b083948f544daf608fc8db8734c Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Thu, 24 Oct 2024 15:13:05 +0200
Subject: [PATCH 86/87] fix: better performance

---
 src/components/VnTable/VnTable.vue  |  7 ++++---
 src/pages/Account/AccountAcls.vue   | 28 +++++++++++++++++++++++++---
 src/pages/Account/AccountFilter.vue |  1 +
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 908157610..c1680bf13 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -151,8 +151,8 @@ const tableModes = [
     },
 ];
 onBeforeMount(() => {
-    setUserParams(route.query[$props.searchUrl]);
-    hasParams.value = params.value && Object.keys(params.value).length !== 0;
+    const urlParams = route.query[$props.searchUrl];
+    hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
 });
 
 onMounted(() => {
@@ -185,7 +185,8 @@ watch(
 
 watch(
     () => route.query[$props.searchUrl],
-    (val) => setUserParams(val)
+    (val) => setUserParams(val),
+    { immediate: true, deep: true }
 );
 
 const isTableMode = computed(() => mode.value == TABLE_MODE);
diff --git a/src/pages/Account/AccountAcls.vue b/src/pages/Account/AccountAcls.vue
index dd93a0cb5..63cdac9c7 100644
--- a/src/pages/Account/AccountAcls.vue
+++ b/src/pages/Account/AccountAcls.vue
@@ -9,6 +9,8 @@ import { useQuasar } from 'quasar';
 import VnTable from 'components/VnTable/VnTable.vue';
 import VnSearchbar from 'components/ui/VnSearchbar.vue';
 import VnConfirm from 'components/ui/VnConfirm.vue';
+import FetchData from 'src/components/FetchData.vue';
+import { useValidator } from 'src/composables/useValidator';
 
 defineProps({
     id: {
@@ -23,11 +25,18 @@ const stateStore = useStateStore();
 const quasar = useQuasar();
 
 const tableRef = ref();
-
+const roles = ref();
+const validationsStore = useValidator();
+const { models } = validationsStore;
 const exprBuilder = (param, value) => {
     switch (param) {
         case 'search':
-            return { model: { like: `%${value}%` } };
+            return {
+                or: [
+                    { model: { like: `%${value}%` } },
+                    { property: { like: `%${value}%` } },
+                ],
+            };
         default:
             return { [param]: value };
     }
@@ -47,6 +56,13 @@ const columns = computed(() => [
         label: t('model'),
         cardVisible: true,
         create: true,
+        columnCreate: {
+            label: t('model'),
+            component: 'select',
+            attrs: {
+                options: Object.keys(models),
+            },
+        },
     },
     {
         align: 'left',
@@ -55,9 +71,10 @@ const columns = computed(() => [
         cardVisible: true,
         component: 'select',
         attrs: {
-            url: 'VnRoles',
+            options: roles,
             optionLabel: 'name',
             optionValue: 'name',
+            inputDebounce: 0,
         },
         create: true,
     },
@@ -130,6 +147,11 @@ const deleteAcl = async ({ id }) => {
     />
     <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
     </QDrawer>
+    <FetchData
+        url="VnRoles?fields=['name']"
+        auto-load
+        @on-fetch="(data) => (roles = data)"
+    />
     <VnTable
         ref="tableRef"
         data-key="AccountAcls"
diff --git a/src/pages/Account/AccountFilter.vue b/src/pages/Account/AccountFilter.vue
index 1775aa06b..3c8378d93 100644
--- a/src/pages/Account/AccountFilter.vue
+++ b/src/pages/Account/AccountFilter.vue
@@ -33,6 +33,7 @@ const rolesOptions = ref([]);
         :search-button="true"
         :hidden-tags="['search']"
         :redirect="false"
+        search-url="table"
     >
         <template #tags="{ tag, formatFn }">
             <div class="q-gutter-x-xs">

From e8d2a40dafbc8ccec24957715bf6cfea82e4bc25 Mon Sep 17 00:00:00 2001
From: carlossa <carlossa@verdnatura.es>
Date: Fri, 25 Oct 2024 08:11:31 +0200
Subject: [PATCH 87/87] fix: entryFilters

---
 src/pages/Entry/EntryLatestBuys.vue | 65 ++++++++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/src/pages/Entry/EntryLatestBuys.vue b/src/pages/Entry/EntryLatestBuys.vue
index 61c430b23..119808176 100644
--- a/src/pages/Entry/EntryLatestBuys.vue
+++ b/src/pages/Entry/EntryLatestBuys.vue
@@ -23,7 +23,6 @@ const columns = [
                 return {
                     id: row.id,
                     size: '50x50',
-                    width: '50px',
                 };
             },
         },
@@ -34,21 +33,37 @@ const columns = [
         label: t('entry.latestBuys.tableVisibleColumns.itemFk'),
         name: 'itemFk',
         isTitle: true,
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.packing'),
         name: 'packing',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.grouping'),
         name: 'grouping',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.quantity'),
         name: 'quantity',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
@@ -59,6 +74,10 @@ const columns = [
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.size'),
         name: 'size',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
@@ -84,6 +103,10 @@ const columns = [
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.weightByPiece'),
         name: 'weightByPiece',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
@@ -99,26 +122,46 @@ const columns = [
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.entryFk'),
         name: 'entryFk',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.buyingValue'),
         name: 'buyingValue',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.freightValue'),
         name: 'freightValue',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.comissionValue'),
         name: 'comissionValue',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.packageValue'),
         name: 'packageValue',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
@@ -129,16 +172,28 @@ const columns = [
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.price2'),
         name: 'price2',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.price3'),
         name: 'price3',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.minPrice'),
         name: 'minPrice',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
@@ -149,11 +204,19 @@ const columns = [
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.weight'),
         name: 'weight',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',
         label: t('entry.latestBuys.tableVisibleColumns.packagingFk'),
         name: 'packagingFk',
+        columnFilter: {
+            component: 'number',
+            inWhere: true,
+        },
     },
     {
         align: 'left',