diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index 6a547d95dbc..c6421719833 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -140,7 +140,7 @@ const $props = defineProps({
     },
     dataCy: {
         type: String,
-        default: 'vn-table',
+        default: 'vnTable',
     },
 });
 
@@ -684,7 +684,7 @@ const rowCtrlClickFunction = computed(() => {
                 @update:selected="emit('update:selected', $event)"
                 @selection="(details) => handleSelection(details, rows)"
                 :hide-selected-banner="true"
-                :data-cy="$props.dataCy ?? 'vnTable'"
+                :data-cy
             >
                 <template #top-left v-if="!$props.withoutHeader">
                     <slot name="top-left"> </slot>
@@ -781,6 +781,7 @@ const rowCtrlClickFunction = computed(() => {
                                 text-overflow: ellipsis;
                                 white-space: nowrap;
                             "
+                            :data-cy="`vnTableCell_${col.name}`"
                         >
                             <slot
                                 :name="`column-${col.name}`"
diff --git a/src/components/common/VnCheckbox.vue b/src/components/common/VnCheckbox.vue
index 94e91328b6c..daaf891dce2 100644
--- a/src/components/common/VnCheckbox.vue
+++ b/src/components/common/VnCheckbox.vue
@@ -27,7 +27,11 @@ const checkboxModel = computed({
 </script>
 <template>
     <div>
-        <QCheckbox v-bind="$attrs" v-model="checkboxModel" />
+        <QCheckbox
+            v-bind="$attrs"
+            v-model="checkboxModel"
+            :data-cy="$attrs['data-cy'] ?? `vnCheckbox${$attrs['label'] ?? ''}`"
+        />
         <QIcon
             v-if="info"
             v-bind="$attrs"
diff --git a/src/components/common/VnInputDate.vue b/src/components/common/VnInputDate.vue
index 1f4705faa15..343130f1d92 100644
--- a/src/components/common/VnInputDate.vue
+++ b/src/components/common/VnInputDate.vue
@@ -107,7 +107,7 @@ const manageDate = (date) => {
             @click="isPopupOpen = !isPopupOpen"
             @keydown="isPopupOpen = false"
             hide-bottom-space
-            :data-cy="$attrs.dataCy ?? $attrs.label + '_inputDate'"
+            :data-cy="($attrs['data-cy'] ?? $attrs.label) + '_inputDate'"
         >
             <template #append>
                 <QIcon
diff --git a/src/components/ui/CardDescriptor.vue b/src/components/ui/CardDescriptor.vue
index 57d8b042139..cf74e4485e1 100644
--- a/src/components/ui/CardDescriptor.vue
+++ b/src/components/ui/CardDescriptor.vue
@@ -151,7 +151,7 @@ const toModule = computed(() => {
 </script>
 
 <template>
-    <div class="descriptor">
+    <div class="descriptor" data-cy="cardDescriptor">
         <template v-if="entity && !isLoading">
             <div class="header bg-primary q-pa-sm justify-between">
                 <slot name="header-extra-action">
@@ -213,18 +213,27 @@ const toModule = computed(() => {
                 <QList dense>
                     <QItemLabel header class="ellipsis text-h5" :lines="1">
                         <div class="title">
-                            <span v-if="$props.title" :title="getValueFromPath(title)">
+                            <span
+                                v-if="$props.title"
+                                :title="getValueFromPath(title)"
+                                :data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_title`"
+                            >
                                 {{ getValueFromPath(title) ?? $props.title }}
                             </span>
                             <slot v-else name="description" :entity="entity">
-                                <span :title="entity.name">
-                                    {{ entity.name }}
-                                </span>
+                                <span
+                                    :title="entity.name"
+                                    :data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_description`"
+                                    v-text="entity.name"
+                                />
                             </slot>
                         </div>
                     </QItemLabel>
                     <QItem>
-                        <QItemLabel class="subtitle" data-cy="descriptor_id">
+                        <QItemLabel
+                            class="subtitle"
+                            :data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_subtitle`"
+                        >
                             #{{ getValueFromPath(subtitle) ?? entity.id }}
                         </QItemLabel>
                         <QBtn
@@ -242,7 +251,10 @@ const toModule = computed(() => {
                         </QBtn>
                     </QItem>
                 </QList>
-                <div class="list-box q-mt-xs">
+                <div
+                    class="list-box q-mt-xs"
+                    :data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_listbox`"
+                >
                     <slot name="body" :entity="entity" />
                 </div>
             </div>
diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue
index 93e3a57f21f..85cc8cde2f8 100644
--- a/src/components/ui/VnFilterPanel.vue
+++ b/src/components/ui/VnFilterPanel.vue
@@ -249,7 +249,7 @@ const getLocale = (label) => {
                         :key="chip.label"
                         :removable="!unremovableParams?.includes(chip.label)"
                         @remove="remove(chip.label)"
-                        data-cy="vnFilterPanelChip"
+                        :data-cy="`vnFilterPanelChip_${chip.label}`"
                     >
                         <slot
                             name="tags"
diff --git a/src/components/ui/VnLv.vue b/src/components/ui/VnLv.vue
index a198c9c05c3..50da8a14367 100644
--- a/src/components/ui/VnLv.vue
+++ b/src/components/ui/VnLv.vue
@@ -28,7 +28,7 @@ function copyValueText() {
 const val = computed(() => $props.value);
 </script>
 <template>
-    <div class="vn-label-value">
+    <div class="vn-label-value" :data-cy="`${$attrs['data-cy'] ?? 'vnLv'}${label ?? ''}`">
         <QCheckbox
             v-if="typeof value === 'boolean'"
             v-model="val"
diff --git a/src/components/ui/VnMoreOptions.vue b/src/components/ui/VnMoreOptions.vue
index 8a1c7a0f2ec..984e2b64f62 100644
--- a/src/components/ui/VnMoreOptions.vue
+++ b/src/components/ui/VnMoreOptions.vue
@@ -12,7 +12,7 @@
             {{ $t('components.cardDescriptor.moreOptions') }}
         </QTooltip>
         <QMenu ref="menuRef" data-cy="descriptor-more-opts-menu">
-            <QList>
+            <QList data-cy="descriptor-more-opts_list">
                 <slot name="menu" :menu-ref="$refs.menuRef" />
             </QList>
         </QMenu>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index 905ddebb2b0..dc963a91b7f 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -121,25 +121,40 @@ function deleteFile(dmsFk) {
                     hide-selected
                     :is-clearable="false"
                     :required="true"
+                    data-cy="invoiceInBasicDataSupplier"
                 />
                 <VnInput
                     clearable
                     clear-icon="close"
                     :label="t('invoiceIn.supplierRef')"
                     v-model="data.supplierRef"
+                    data-cy="invoiceInBasicDataSupplierRef"
                 />
             </VnRow>
             <VnRow>
-                <VnInputDate :label="t('Expedition date')" v-model="data.issued" />
+                <VnInputDate
+                    :label="t('Expedition date')"
+                    v-model="data.issued"
+                    data-cy="invoiceInBasicDataIssued"
+                />
                 <VnInputDate
                     :label="t('Operation date')"
                     v-model="data.operated"
                     autofocus
+                    data-cy="invoiceInBasicDataOperated"
                 />
             </VnRow>
             <VnRow>
-                <VnInputDate :label="t('Entry date')" v-model="data.bookEntried" />
-                <VnInputDate :label="t('Accounted date')" v-model="data.booked" />
+                <VnInputDate
+                    :label="t('Entry date')"
+                    v-model="data.bookEntried"
+                    data-cy="invoiceInBasicDatabookEntried"
+                />
+                <VnInputDate
+                    :label="t('Accounted date')"
+                    v-model="data.booked"
+                    data-cy="invoiceInBasicDataBooked"
+                />
             </VnRow>
             <VnRow>
                 <VnSelect
@@ -149,7 +164,7 @@ function deleteFile(dmsFk) {
                     option-value="id"
                     option-label="id"
                     :filter-options="['id', 'name']"
-                    data-cy="UnDeductibleVatSelect"
+                    data-cy="invoiceInBasicDataDeductibleExpenseFk"
                 >
                     <template #option="scope">
                         <QItem v-bind="scope.itemProps">
@@ -182,6 +197,7 @@ function deleteFile(dmsFk) {
                             padding="xs"
                             round
                             @click="downloadFile(data.dmsFk)"
+                            data-cy="invoiceInBasicDataDmsDownload"
                         />
                         <QBtn
                             :class="{
@@ -197,6 +213,7 @@ function deleteFile(dmsFk) {
                                     documentDialogRef.dms = data.dms;
                                 }
                             "
+                            data-cy="invoiceInBasicDataDmsEdit"
                         >
                             <QTooltip>{{ t('Edit document') }}</QTooltip>
                         </QBtn>
@@ -210,6 +227,7 @@ function deleteFile(dmsFk) {
                             padding="xs"
                             round
                             @click="deleteFile(data.dmsFk)"
+                            data-cy="invoiceInBasicDataDmsDelete"
                         />
                     </div>
                     <QBtn
@@ -224,7 +242,7 @@ function deleteFile(dmsFk) {
                                 delete documentDialogRef.dms;
                             }
                         "
-                        data-cy="dms-create"
+                        data-cy="invoiceInBasicDataDmsAdd"
                     >
                         <QTooltip>{{ t('Create document') }}</QTooltip>
                     </QBtn>
@@ -237,9 +255,9 @@ function deleteFile(dmsFk) {
                     :label="t('Currency')"
                     v-model="data.currencyFk"
                     :options="currencies"
-                    option-value="id"
                     option-label="code"
                     sort-by="id"
+                    data-cy="invoiceInBasicDataCurrencyFk"
                 />
 
                 <VnSelect
@@ -249,8 +267,8 @@ function deleteFile(dmsFk) {
                     :label="t('Company')"
                     v-model="data.companyFk"
                     :options="companies"
-                    option-value="id"
                     option-label="code"
+                    data-cy="invoiceInBasicDataCompanyFk"
                 />
             </VnRow>
             <VnRow>
@@ -260,6 +278,7 @@ function deleteFile(dmsFk) {
                     :options="sageWithholdings"
                     option-value="id"
                     option-label="withholding"
+                    data-cy="invoiceInBasicDataWithholdingSageFk"
                 />
             </VnRow>
         </template>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue b/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue
index 1d0a8d078d0..775a2a72b6c 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInCorrective.vue
@@ -1,22 +1,16 @@
 <script setup>
 import { ref, computed, capitalize } from 'vue';
-import { useRoute } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { useArrayData } from 'src/composables/useArrayData';
 import CrudModel from 'src/components/CrudModel.vue';
 import FetchData from 'src/components/FetchData.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 
-const route = useRoute();
 const { t } = useI18n();
 
 const arrayData = useArrayData();
 const invoiceIn = computed(() => arrayData.store.data);
 const invoiceInCorrectionRef = ref();
-const filter = {
-    include: { relation: 'invoiceIn' },
-    where: { correctingFk: route.params.id },
-};
 const columns = computed(() => [
     {
         name: 'origin',
@@ -92,7 +86,8 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
         v-if="invoiceIn"
         data-key="InvoiceInCorrection"
         url="InvoiceInCorrections"
-        :filter="filter"
+        :user-filter="{ include: { relation: 'invoiceIn' } }"
+        :filter="{ where: { correctingFk: $route.params.id } }"
         auto-load
         primary-key="correctingFk"
         :default-remove="false"
@@ -115,6 +110,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
                             :option-label="col.optionLabel"
                             :disable="row.invoiceIn.isBooked"
                             :filter-options="['description']"
+                            data-cy="invoiceInCorrective_type"
                         >
                             <template #option="{ opt, itemProps }">
                                 <QItem v-bind="itemProps">
@@ -137,6 +133,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
                             :rules="[requiredFieldRule]"
                             :filter-options="['code', 'description']"
                             :disable="row.invoiceIn.isBooked"
+                            data-cy="invoiceInCorrective_class"
                         >
                             <template #option="{ opt, itemProps }">
                                 <QItem v-bind="itemProps">
@@ -161,6 +158,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
                             :option-label="col.optionLabel"
                             :rules="[requiredFieldRule]"
                             :disable="row.invoiceIn.isBooked"
+                            data-cy="invoiceInCorrective_reason"
                         />
                     </QTd>
                 </template>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
index 3843f5bf713..eb673c546cb 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
@@ -17,10 +17,6 @@ const { t } = useI18n();
 const cardDescriptorRef = ref();
 const entityId = computed(() => $props.id || +currentRoute.value.params.id);
 const totalAmount = ref();
-const config = ref();
-const cplusRectificationTypes = ref([]);
-const siiTypeInvoiceIns = ref([]);
-const invoiceCorrectionTypes = ref([]);
 const invoiceInCorrection = reactive({ correcting: [], corrected: null });
 const routes = reactive({
     getSupplier: (id) => {
@@ -30,7 +26,7 @@ const routes = reactive({
         return {
             name: 'InvoiceInList',
             query: {
-                params: JSON.stringify({ supplierFk: id }),
+                table: JSON.stringify({ supplierFk: id }),
             },
         };
     },
@@ -39,7 +35,7 @@ const routes = reactive({
             return {
                 name: 'InvoiceInList',
                 query: {
-                    params: JSON.stringify({ correctedFk: entityId.value }),
+                    table: JSON.stringify({ correctedFk: entityId.value }),
                 },
             };
         }
@@ -108,7 +104,7 @@ async function setInvoiceCorrection(id) {
             <VnLv :label="t('invoiceIn.list.amount')" :value="toCurrency(totalAmount)" />
             <VnLv :label="t('invoiceIn.list.supplier')">
                 <template #value>
-                    <span class="link">
+                    <span class="link" data-cy="invoiceInDescriptor_supplier">
                         {{ entity?.supplier?.nickname }}
                         <SupplierDescriptorProxy :id="entity?.supplierFk" />
                     </span>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
index 8b039ec2726..058f17d31b4 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { ref, computed, toRefs, reactive } from 'vue';
+import { ref, computed, toRefs, reactive, onBeforeMount } from 'vue';
 import { useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { useQuasar } from 'quasar';
@@ -111,10 +111,9 @@ async function cloneInvoice() {
 }
 
 const isAgricultural = () => {
-    if (!config.value) return false;
     return (
-        invoiceIn.value?.supplier?.sageFarmerWithholdingFk ===
-        config?.value[0]?.sageWithholdingFk
+        invoiceIn.value?.supplier?.sageWithholdingFk ==
+        config.value?.sageFarmerWithholdingFk
     );
 };
 function showPdfInvoice() {
@@ -153,162 +152,183 @@ const createInvoiceInCorrection = async () => {
     );
     push({ path: `/invoice-in/${correctingId}/summary` });
 };
+
+onBeforeMount(async () => {
+    config.value = (
+        await axios.get('invoiceinConfigs/findOne', {
+            params: { fields: ['sageFarmerWithholdingFk'] },
+        })
+    ).data;
+});
 </script>
-
 <template>
-    <FetchData
-        url="InvoiceCorrectionTypes"
-        @on-fetch="(data) => (invoiceCorrectionTypes = data)"
-        auto-load
-    />
-    <FetchData
-        url="CplusRectificationTypes"
-        @on-fetch="(data) => (cplusRectificationTypes = data)"
-        auto-load
-    />
-    <FetchData
-        url="SiiTypeInvoiceIns"
-        :where="{ code: { like: 'R%' } }"
-        @on-fetch="(data) => (siiTypeInvoiceIns = data)"
-        auto-load
-    />
-    <FetchData
-        url="InvoiceInConfigs"
-        :where="{ fields: ['sageWithholdingFk'] }"
-        auto-load
-        @on-fetch="(data) => (config = data)"
-    />
-    <InvoiceInToBook>
-        <template #content="{ book }">
-            <QItem
-                v-if="!invoice?.isBooked && canEditProp('toBook')"
-                v-ripple
-                clickable
-                @click="book(entityId)"
+    <template v-if="config">
+        <FetchData
+            url="InvoiceCorrectionTypes"
+            @on-fetch="(data) => (invoiceCorrectionTypes = data)"
+            auto-load
+        />
+        <FetchData
+            url="CplusRectificationTypes"
+            @on-fetch="(data) => (cplusRectificationTypes = data)"
+            auto-load
+        />
+        <FetchData
+            url="SiiTypeInvoiceIns"
+            :where="{ code: { like: 'R%' } }"
+            @on-fetch="(data) => (siiTypeInvoiceIns = data)"
+            auto-load
+        />
+        <InvoiceInToBook>
+            <template #content="{ book }">
+                <QItem
+                    v-if="!invoice?.isBooked && canEditProp('toBook')"
+                    v-ripple
+                    clickable
+                    @click="book(entityId)"
+                >
+                    <QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
+                </QItem>
+            </template>
+        </InvoiceInToBook>
+        <QItem
+            v-if="invoice?.isBooked && canEditProp('toUnbook')"
+            v-ripple
+            clickable
+            @click="triggerMenu('unbook')"
+        >
+            <QItemSection>
+                {{ t('invoiceIn.descriptorMenu.unbook') }}
+            </QItemSection>
+        </QItem>
+        <QItem
+            v-if="canEditProp('deleteById')"
+            v-ripple
+            clickable
+            @click="triggerMenu('delete')"
+        >
+            <QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
+        </QItem>
+        <QItem
+            v-if="canEditProp('clone')"
+            v-ripple
+            clickable
+            @click="triggerMenu('clone')"
+        >
+            <QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
+        </QItem>
+        <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
+            <QItemSection>{{
+                t('invoiceIn.descriptorMenu.showAgriculturalPdf')
+            }}</QItemSection>
+        </QItem>
+        <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
+            <QItemSection
+                >{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
             >
-                <QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
-            </QItem>
-        </template>
-    </InvoiceInToBook>
-    <QItem
-        v-if="invoice?.isBooked && canEditProp('toUnbook')"
-        v-ripple
-        clickable
-        @click="triggerMenu('unbook')"
-    >
-        <QItemSection>
-            {{ t('invoiceIn.descriptorMenu.unbook') }}
-        </QItemSection>
-    </QItem>
-    <QItem
-        v-if="canEditProp('deleteById')"
-        v-ripple
-        clickable
-        @click="triggerMenu('delete')"
-    >
-        <QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
-    </QItem>
-    <QItem v-if="canEditProp('clone')" v-ripple clickable @click="triggerMenu('clone')">
-        <QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
-    </QItem>
-    <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
-        <QItemSection>{{
-            t('invoiceIn.descriptorMenu.showAgriculturalPdf')
-        }}</QItemSection>
-    </QItem>
-    <QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
-        <QItemSection
-            >{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
+        </QItem>
+        <QItem
+            v-if="!invoiceInCorrection.corrected"
+            v-ripple
+            clickable
+            @click="triggerMenu('correct')"
+            data-cy="createCorrectiveItem"
         >
-    </QItem>
-    <QItem
-        v-if="!invoiceInCorrection.corrected"
-        v-ripple
-        clickable
-        @click="triggerMenu('correct')"
-        data-cy="createCorrectiveItem"
-    >
-        <QItemSection
-            >{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
+            <QItemSection
+                >{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
+            >
+        </QItem>
+        <QItem
+            v-if="invoice.dmsFk"
+            v-ripple
+            clickable
+            @click="downloadFile(invoice.dmsFk)"
         >
-    </QItem>
-    <QItem v-if="invoice.dmsFk" v-ripple clickable @click="downloadFile(invoice.dmsFk)">
-        <QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
-    </QItem>
-    <QDialog ref="correctionDialogRef">
-        <QCard>
-            <QCardSection>
-                <QItem class="q-px-none">
-                    <span class="text-primary text-h6 full-width">
-                        {{ t('Create rectificative invoice') }}
-                    </span>
-                    <QBtn icon="close" flat round dense v-close-popup />
-                </QItem>
-            </QCardSection>
-            <QCardSection>
-                <QItem>
-                    <QItemSection>
-                        <QInput
-                            :label="t('Original invoice')"
-                            v-model="entityId"
-                            readonly
-                        />
-                        <VnSelect
-                            :label="`${useCapitalize(t('globals.class'))}`"
-                            v-model="correctionFormData.invoiceClass"
-                            :options="siiTypeInvoiceIns"
-                            option-value="id"
-                            option-label="code"
-                            :required="true"
-                        />
-                    </QItemSection>
-                    <QItemSection>
-                        <VnSelect
-                            :label="`${useCapitalize(t('globals.type'))}`"
-                            v-model="correctionFormData.invoiceType"
-                            :options="cplusRectificationTypes"
-                            option-value="id"
-                            option-label="description"
-                            :required="true"
-                        >
-                            <template #option="{ itemProps, opt }">
-                                <QItem v-bind="itemProps">
-                                    <QItemSection>
-                                        <QItemLabel
-                                            >{{ opt.id }} -
-                                            {{ opt.description }}</QItemLabel
-                                        >
-                                    </QItemSection>
-                                </QItem>
-                                <div></div>
-                            </template>
-                        </VnSelect>
+            <QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
+        </QItem>
+        <QDialog ref="correctionDialogRef">
+            <QCard data-cy="correctiveInvoiceDialog">
+                <QCardSection>
+                    <QItem class="q-px-none">
+                        <span class="text-primary text-h6 full-width">
+                            {{ t('Create rectificative invoice') }}
+                        </span>
+                        <QBtn icon="close" flat round dense v-close-popup />
+                    </QItem>
+                </QCardSection>
+                <QCardSection>
+                    <QItem>
+                        <QItemSection>
+                            <QInput
+                                :label="t('Original invoice')"
+                                v-model="entityId"
+                                readonly
+                            />
+                            <VnSelect
+                                :label="`${useCapitalize(t('globals.class'))}`"
+                                v-model="correctionFormData.invoiceClass"
+                                :options="siiTypeInvoiceIns"
+                                option-value="id"
+                                option-label="code"
+                                :required="true"
+                                data-cy="invoiceInDescriptorMenu_class"
+                            />
+                        </QItemSection>
+                        <QItemSection>
+                            <VnSelect
+                                :label="`${useCapitalize(t('globals.type'))}`"
+                                v-model="correctionFormData.invoiceType"
+                                :options="cplusRectificationTypes"
+                                option-value="id"
+                                option-label="description"
+                                :required="true"
+                                data-cy="invoiceInDescriptorMenu_type"
+                            >
+                                <template #option="{ itemProps, opt }">
+                                    <QItem v-bind="itemProps">
+                                        <QItemSection>
+                                            <QItemLabel
+                                                >{{ opt.id }} -
+                                                {{ opt.description }}</QItemLabel
+                                            >
+                                        </QItemSection>
+                                    </QItem>
+                                    <div></div>
+                                </template>
+                            </VnSelect>
 
-                        <VnSelect
-                            :label="`${useCapitalize(t('globals.reason'))}`"
-                            v-model="correctionFormData.invoiceReason"
-                            :options="invoiceCorrectionTypes"
-                            option-value="id"
-                            option-label="description"
-                            :required="true"
-                        />
-                    </QItemSection>
-                </QItem>
-            </QCardSection>
-            <QCardActions class="justify-end q-mr-sm">
-                <QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
-                <QBtn
-                    :label="t('globals.save')"
-                    color="primary"
-                    v-close-popup
-                    @click="createInvoiceInCorrection"
-                    :disable="isNotFilled"
-                />
-            </QCardActions>
-        </QCard>
-    </QDialog>
+                            <VnSelect
+                                :label="`${useCapitalize(t('globals.reason'))}`"
+                                v-model="correctionFormData.invoiceReason"
+                                :options="invoiceCorrectionTypes"
+                                option-value="id"
+                                option-label="description"
+                                :required="true"
+                                data-cy="invoiceInDescriptorMenu_reason"
+                            />
+                        </QItemSection>
+                    </QItem>
+                </QCardSection>
+                <QCardActions class="justify-end q-mr-sm">
+                    <QBtn
+                        flat
+                        :label="t('globals.close')"
+                        color="primary"
+                        v-close-popup
+                    />
+                    <QBtn
+                        :label="t('globals.save')"
+                        color="primary"
+                        v-close-popup
+                        @click="createInvoiceInCorrection"
+                        :disable="isNotFilled"
+                        data-cy="saveCorrectiveInvoice"
+                    />
+                </QCardActions>
+            </QCard>
+        </QDialog>
+    </template>
 </template>
-
 <i18n>
 en:
     isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries
diff --git a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
index 18602f04324..f6beecd3d4a 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
@@ -198,6 +198,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
                         color="orange-11"
                         text-color="black"
                         @click="book(entityId)"
+                        data-cy="invoiceInSummary_book"
                     />
                 </template>
             </InvoiceIntoBook>
@@ -219,7 +220,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
                     :value="entity.supplier?.name"
                 >
                     <template #value>
-                        <span class="link">
+                        <span class="link" data-cy="invoiceInSummary_supplier">
                             {{ entity.supplier?.name }}
                             <SupplierDescriptorProxy :id="entity.supplierFk" />
                         </span>
diff --git a/src/pages/InvoiceIn/Card/InvoiceInVat.vue b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
index eae255120d9..e37cf5b7e57 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInVat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
@@ -202,6 +202,9 @@ function setCursor(ref) {
                             :option-label="col.optionLabel"
                             :filter-options="['id', 'name']"
                             :tooltip="t('Create a new expense')"
+                            :acls="[
+                                { model: 'Expense', props: '*', accessType: 'WRITE' },
+                            ]"
                             @keydown.tab.prevent="
                                 autocompleteExpense(
                                     $event,
diff --git a/src/pages/InvoiceIn/InvoiceInFilter.vue b/src/pages/InvoiceIn/InvoiceInFilter.vue
index e010a1edb39..a4fb0d653a8 100644
--- a/src/pages/InvoiceIn/InvoiceInFilter.vue
+++ b/src/pages/InvoiceIn/InvoiceInFilter.vue
@@ -7,6 +7,7 @@ import VnInputNumber from 'src/components/common/VnInputNumber.vue';
 import { dateRange } from 'src/filters';
 import { date } from 'quasar';
 import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
+import VnCheckbox from 'src/components/common/VnCheckbox.vue';
 
 defineProps({ dataKey: { type: String, required: true } });
 const dateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
@@ -147,13 +148,13 @@ function handleDaysAgo(params, daysAgo) {
             </QItem>
             <QItem>
                 <QItemSection>
-                    <QCheckbox
+                    <VnCheckbox
                         :label="$t('invoiceIn.isBooked')"
                         v-model="params.isBooked"
                         @update:model-value="searchFn()"
                         toggle-indeterminate
                     />
-                    <QCheckbox
+                    <VnCheckbox
                         :label="getLocale('params.correctingFk')"
                         v-model="params.correctingFk"
                         @update:model-value="searchFn()"
diff --git a/src/pages/InvoiceIn/InvoiceInToBook.vue b/src/pages/InvoiceIn/InvoiceInToBook.vue
index 5bdbe197b99..23175f2e735 100644
--- a/src/pages/InvoiceIn/InvoiceInToBook.vue
+++ b/src/pages/InvoiceIn/InvoiceInToBook.vue
@@ -4,7 +4,7 @@ import { useQuasar } from 'quasar';
 import { useI18n } from 'vue-i18n';
 import VnConfirm from 'src/components/ui/VnConfirm.vue';
 import { useArrayData } from 'src/composables/useArrayData';
-import qs from 'qs';
+
 const { notify, dialog } = useQuasar();
 const { t } = useI18n();
 
@@ -61,17 +61,15 @@ async function checkToBook(id) {
 }
 
 async function toBook(id) {
-    let type = 'positive';
-    let message = t('globals.dataSaved');
-
+    let err = false;
     try {
         await axios.post(`InvoiceIns/${id}/toBook`);
         store.data.isBooked = true;
     } catch (e) {
-        type = 'negative';
-        message = t('It was not able to book the invoice');
+        err = true;
+        throw e;
     } finally {
-        notify({ type, message });
+        if (!err) notify({ type: 'positive', message: t('globals.dataSaved') });
     }
 }
 </script>
diff --git a/src/pages/Zone/Card/ZoneEventExclusionForm.vue b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
index 3828c998f2f..582a8bbadd7 100644
--- a/src/pages/Zone/Card/ZoneEventExclusionForm.vue
+++ b/src/pages/Zone/Card/ZoneEventExclusionForm.vue
@@ -1,16 +1,18 @@
 <script setup>
-import { ref, computed, onMounted, reactive } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
+import { useQuasar } from 'quasar';
+import axios from 'axios';
+import moment from 'moment';
 
 import VnRow from 'components/ui/VnRow.vue';
 import FormPopup from 'components/FormPopup.vue';
 import ZoneLocationsTree from './ZoneLocationsTree.vue';
 import VnInputDate from 'src/components/common/VnInputDate.vue';
-
 import { useArrayData } from 'src/composables/useArrayData';
 import { useVnConfirm } from 'composables/useVnConfirm';
-import axios from 'axios';
+import { toDateFormat } from 'src/filters/date';
 
 const props = defineProps({
     date: {
@@ -34,18 +36,25 @@ const props = defineProps({
         type: Array,
         default: () => [],
     },
+    isMasiveEdit: {
+        type: Boolean,
+        default: false,
+    },
+    zoneIds: {
+        type: Array,
+        default: () => [],
+    },
 });
 
 const emit = defineEmits(['onSubmit', 'closeForm']);
-
+const quasar = useQuasar();
 const route = useRoute();
 const { t } = useI18n();
 const { openConfirmationModal } = useVnConfirm();
 
 const isNew = computed(() => props.isNewMode);
-const dated = reactive(props.date);
+const dated = ref(props.date || Date.vnNew());
 const tickedNodes = ref();
-
 const _excludeType = ref('all');
 const excludeType = computed({
     get: () => _excludeType.value,
@@ -63,16 +72,46 @@ const exclusionGeoCreate = async () => {
         geoIds: tickedNodes.value,
     };
     await axios.post('Zones/exclusionGeo', params);
+    quasar.notify({
+        message: t('globals.dataSaved'),
+        type: 'positive',
+    });
     await refetchEvents();
 };
 
 const exclusionCreate = async () => {
-    const url = `Zones/${route.params.id}/exclusions`;
+    const defaultMonths = await axios.get('ZoneConfigs');
+    const nMonths = defaultMonths.data[0].defaultMonths;
     const body = {
-        dated,
+        dated: dated.value,
     };
-    if (isNew.value || props.event?.type) await axios.post(`${url}`, [body]);
-    else await axios.put(`${url}/${props.event?.id}`, body);
+    const zoneIds = props.zoneIds?.length ? props.zoneIds : [route.params.id];
+    for (const id of zoneIds) {
+        const url = `Zones/${id}/exclusions`;
+        let today = moment(dated.value);
+        let lastDay = today.clone().add(nMonths, 'months').endOf('month');
+
+        const { data } = await axios.get(`Zones/getEventsFiltered`, {
+            params: {
+                zoneFk: id,
+                started: today,
+                ended: lastDay,
+            },
+        });
+        const existsEvent = data.events.find(
+            (event) => toDateFormat(event.dated) === toDateFormat(dated.value),
+        );
+        if (existsEvent) {
+            await axios.delete(`Zones/${existsEvent?.zoneFk}/events/${existsEvent?.id}`);
+        }
+
+        if (isNew.value || props.event?.type) await axios.post(`${url}`, [body]);
+        else await axios.put(`${url}/${props.event?.id}`, body);
+    }
+    quasar.notify({
+        message: t('globals.dataSaved'),
+        type: 'positive',
+    });
     await refetchEvents();
 };
 
@@ -129,6 +168,7 @@ onMounted(() => {
                     :label="t('eventsExclusionForm.all')"
                 />
                 <QRadio
+                    v-if="!props.isMasiveEdit"
                     v-model="excludeType"
                     dense
                     val="specificLocations"
diff --git a/src/pages/Zone/Card/ZoneEventInclusionForm.vue b/src/pages/Zone/Card/ZoneEventInclusionForm.vue
index fb552bb9386..8b02c2d841f 100644
--- a/src/pages/Zone/Card/ZoneEventInclusionForm.vue
+++ b/src/pages/Zone/Card/ZoneEventInclusionForm.vue
@@ -2,6 +2,13 @@
 import { ref, computed, onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
+import { useQuasar } from 'quasar';
+import axios from 'axios';
+import moment from 'moment';
+
+import { useArrayData } from 'src/composables/useArrayData';
+import { useWeekdayStore } from 'src/stores/useWeekdayStore';
+import { useVnConfirm } from 'composables/useVnConfirm';
 
 import VnRow from 'components/ui/VnRow.vue';
 import FormPopup from 'components/FormPopup.vue';
@@ -9,11 +16,7 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
 import VnWeekdayPicker from 'src/components/common/VnWeekdayPicker.vue';
 import VnInputTime from 'components/common/VnInputTime.vue';
 import VnInput from 'src/components/common/VnInput.vue';
-
-import { useArrayData } from 'src/composables/useArrayData';
-import { useWeekdayStore } from 'src/stores/useWeekdayStore';
-import { useVnConfirm } from 'composables/useVnConfirm';
-import axios from 'axios';
+import { toDateFormat } from 'src/filters/date';
 
 const props = defineProps({
     date: {
@@ -32,6 +35,14 @@ const props = defineProps({
         type: Boolean,
         default: true,
     },
+    isMasiveEdit: {
+        type: Boolean,
+        default: false,
+    },
+    zoneIds: {
+        type: Array,
+        default: () => [],
+    },
 });
 
 const emit = defineEmits(['onSubmit', 'closeForm']);
@@ -40,10 +51,10 @@ const route = useRoute();
 const { t } = useI18n();
 const weekdayStore = useWeekdayStore();
 const { openConfirmationModal } = useVnConfirm();
-
+const quasar = useQuasar();
 const isNew = computed(() => props.isNewMode);
 const eventInclusionFormData = ref({ wdays: [] });
-
+const dated = ref(props.date || Date.vnNew());
 const _inclusionType = ref('indefinitely');
 const inclusionType = computed({
     get: () => _inclusionType.value,
@@ -56,8 +67,12 @@ const inclusionType = computed({
 const arrayData = useArrayData('ZoneEvents');
 
 const createEvent = async () => {
+    const defaultMonths = await axios.get('ZoneConfigs');
+    const nMonths = defaultMonths.data[0].defaultMonths;
+
     eventInclusionFormData.value.weekDays = weekdayStore.toSet(
         eventInclusionFormData.value.wdays,
+        eventInclusionFormData.value.wdays,
     );
 
     if (inclusionType.value == 'day') eventInclusionFormData.value.weekDays = '';
@@ -68,14 +83,43 @@ const createEvent = async () => {
         eventInclusionFormData.value.ended = null;
     }
 
-    if (isNew.value)
-        await axios.post(`Zones/${route.params.id}/events`, eventInclusionFormData.value);
-    else
-        await axios.put(
-            `Zones/${route.params.id}/events/${props.event?.id}`,
-            eventInclusionFormData.value,
-        );
+    const zoneIds = props.zoneIds?.length ? props.zoneIds : [route.params.id];
+    for (const id of zoneIds) {
+        let today = eventInclusionFormData.value.dated
+            ? moment(eventInclusionFormData.value.dated)
+            : moment(dated.value);
+        let lastDay = today.clone().add(nMonths, 'months').endOf('month');
 
+        const { data } = await axios.get(`Zones/getEventsFiltered`, {
+            params: {
+                zoneFk: id,
+                started: today,
+                ended: lastDay,
+            },
+        });
+        const existsExclusion = data.exclusions.find(
+            (exclusion) =>
+                toDateFormat(exclusion.dated) ===
+                toDateFormat(eventInclusionFormData.value.dated),
+        );
+        if (existsExclusion) {
+            await axios.delete(
+                `Zones/${existsExclusion?.zoneFk}/exclusions/${existsExclusion?.id}`,
+            );
+        }
+
+        if (isNew.value)
+            await axios.post(`Zones/${id}/events`, eventInclusionFormData.value);
+        else
+            await axios.put(
+                `Zones/${id}/events/${props.event?.id}`,
+                eventInclusionFormData.value,
+            );
+    }
+    quasar.notify({
+        message: t('globals.dataSaved'),
+        type: 'positive',
+    });
     await refetchEvents();
     emit('onSubmit');
 };
@@ -97,9 +141,11 @@ const refetchEvents = async () => {
 
 onMounted(() => {
     if (props.event) {
+        dated.value = props.event?.dated;
         eventInclusionFormData.value = { ...props.event };
         inclusionType.value = props.event?.type || 'day';
     } else if (props.date) {
+        dated.value = props.date;
         eventInclusionFormData.value.dated = props.date;
         inclusionType.value = 'day';
     } else inclusionType.value = 'indefinitely';
@@ -125,6 +171,7 @@ onMounted(() => {
                     data-cy="ZoneEventInclusionDayRadio"
                 />
                 <QRadio
+                    v-if="!props.isMasiveEdit"
                     v-model="inclusionType"
                     dense
                     val="indefinitely"
@@ -132,6 +179,7 @@ onMounted(() => {
                     data-cy="ZoneEventInclusionIndefinitelyRadio"
                 />
                 <QRadio
+                    v-if="!props.isMasiveEdit"
                     v-model="inclusionType"
                     dense
                     val="range"
diff --git a/src/pages/Zone/Card/ZoneLocations.vue b/src/pages/Zone/Card/ZoneLocations.vue
index 08b99df60b4..add9f6f5bba 100644
--- a/src/pages/Zone/Card/ZoneLocations.vue
+++ b/src/pages/Zone/Card/ZoneLocations.vue
@@ -34,9 +34,10 @@ const onSelected = async (val, node) => {
                             node.selected
                                 ? '--checked'
                                 : node.selected == false
-                                ? '--unchecked'
-                                : '--indeterminate',
+                                  ? '--unchecked'
+                                  : '--indeterminate',
                         ]"
+                        data-cy="ZoneLocationTreeCheckbox"
                     />
                 </template>
             </ZoneLocationsTree>
diff --git a/src/pages/Zone/ZoneCalendarGrid.vue b/src/pages/Zone/ZoneCalendarGrid.vue
index 91d2cc7ebc8..1ef687b3f19 100644
--- a/src/pages/Zone/ZoneCalendarGrid.vue
+++ b/src/pages/Zone/ZoneCalendarGrid.vue
@@ -42,7 +42,7 @@ const refreshEvents = () => {
     days.value = {};
     if (!data.value) return;
 
-    let day = new Date(firstDay.value.getTime());
+    let day = new Date(firstDay?.value?.getTime());
 
     while (day <= lastDay.value) {
         let stamp = day.getTime();
@@ -156,7 +156,7 @@ watch(
     (value) => {
         data.value = value;
     },
-    { immediate: true }
+    { immediate: true },
 );
 
 const getMonthNameAndYear = (date) => {
diff --git a/src/pages/Zone/ZoneList.vue b/src/pages/Zone/ZoneList.vue
index 869b0c12c94..8d7c4a165ac 100644
--- a/src/pages/Zone/ZoneList.vue
+++ b/src/pages/Zone/ZoneList.vue
@@ -14,7 +14,11 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
 import VnSelect from 'src/components/common/VnSelect.vue';
 import VnInput from 'src/components/common/VnInput.vue';
 import VnInputTime from 'src/components/common/VnInputTime.vue';
+
 import VnSection from 'src/components/common/VnSection.vue';
+import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
+import ZoneEventInclusionForm from './Card/ZoneEventInclusionForm.vue';
+import ZoneEventExclusionForm from './Card/ZoneEventExclusionForm.vue';
 
 const { t } = useI18n();
 const router = useRouter();
@@ -24,6 +28,11 @@ const { openConfirmationModal } = useVnConfirm();
 const tableRef = ref();
 const warehouseOptions = ref([]);
 const dataKey = 'ZoneList';
+const selectedRows = ref([]);
+const hasSelectedRows = computed(() => selectedRows.value.length > 0);
+const openInclusionForm = ref();
+const showZoneEventForm = ref(false);
+const zoneIds = ref({});
 const tableFilter = {
     include: [
         {
@@ -191,6 +200,16 @@ const exprBuilder = (param, value) => {
             };
     }
 };
+
+function openForm(value, rows) {
+    zoneIds.value = rows.map((row) => row.id);
+    openInclusionForm.value = value;
+    showZoneEventForm.value = true;
+}
+
+const closeEventForm = () => {
+    showZoneEventForm.value = false;
+};
 </script>
 
 <template>
@@ -206,6 +225,28 @@ const exprBuilder = (param, value) => {
         }"
     >
         <template #body>
+            <VnSubToolbar>
+                <template #st-actions>
+                    <QBtnGroup style="column-gap: 10px">
+                        <QBtn
+                            color="primary"
+                            icon-right="event_available"
+                            :disable="!hasSelectedRows"
+                            @click="openForm(true, selectedRows)"
+                        >
+                            <QTooltip>{{ t('list.includeEvent') }}</QTooltip>
+                        </QBtn>
+                        <QBtn
+                            color="primary"
+                            icon-right="event_busy"
+                            :disable="!hasSelectedRows"
+                            @click="openForm(false, selectedRows)"
+                        >
+                            <QTooltip>{{ t('list.excludeEvent') }}</QTooltip>
+                        </QBtn>
+                    </QBtnGroup>
+                </template>
+            </VnSubToolbar>
             <div class="table-container">
                 <div class="column items-center">
                     <VnTable
@@ -220,6 +261,11 @@ const exprBuilder = (param, value) => {
                             formInitialData: {},
                         }"
                         table-height="85vh"
+                        v-model:selected="selectedRows"
+                        :table="{
+                            'row-key': 'id',
+                            selection: 'multiple',
+                        }"
                     >
                         <template #column-addressFk="{ row }">
                             {{ dashIfEmpty(formatRow(row)) }}
@@ -271,6 +317,21 @@ const exprBuilder = (param, value) => {
             </div>
         </template>
     </VnSection>
+    <QDialog v-model="showZoneEventForm" @hide="closeEventForm()">
+        <ZoneEventInclusionForm
+            v-if="openInclusionForm"
+            :event="'event'"
+            :is-masive-edit="true"
+            :zone-ids="zoneIds"
+            @close-form="closeEventForm"
+        />
+        <ZoneEventExclusionForm
+            v-else
+            :zone-ids="zoneIds"
+            :is-masive-edit="true"
+            @close-form="closeEventForm"
+        />
+    </QDialog>
 </template>
 
 <style lang="scss" scoped>
diff --git a/src/pages/Zone/locale/en.yml b/src/pages/Zone/locale/en.yml
index 22f4b1ae6ec..f46a98ee63d 100644
--- a/src/pages/Zone/locale/en.yml
+++ b/src/pages/Zone/locale/en.yml
@@ -25,6 +25,7 @@ list:
     agency: Agency
     close: Close
     price: Price
+    priceOptimum: Optimal price
     create: Create zone
     openSummary: Details
     searchZone: Search zones
@@ -37,6 +38,8 @@ list:
     createZone: Create zone
     zoneSummary: Summary
     addressFk: Address
+    includeEvent: Include event
+    excludeEvent: Exclude event
 create:
     name: Name
     closingHour: Closing hour
diff --git a/src/pages/Zone/locale/es.yml b/src/pages/Zone/locale/es.yml
index 777bc1c031f..7a23bdc0227 100644
--- a/src/pages/Zone/locale/es.yml
+++ b/src/pages/Zone/locale/es.yml
@@ -39,6 +39,8 @@ list:
     createZone: Crear zona
     zoneSummary: Resumen
     addressFk: Consignatario
+    includeEvent: Incluir evento
+    excludeEvent: Excluir evento
 create:
     closingHour: Hora de cierre
     itemMaxSize: Medida máxima
diff --git a/src/stores/useWeekdayStore.js b/src/stores/useWeekdayStore.js
index 57a302dc105..bf6b2704d4c 100644
--- a/src/stores/useWeekdayStore.js
+++ b/src/stores/useWeekdayStore.js
@@ -77,14 +77,14 @@ export const useWeekdayStore = defineStore('weekdayStore', () => {
         const locales = {};
         for (let code of localeOrder.es) {
             const weekDay = weekdaysMap[code];
-            const locale = t(`weekdays.${weekdaysMap[code].code}`);
+            const locale = t(`weekdays.${weekDay?.code}`);
             const obj = {
                 ...weekDay,
                 locale,
                 localeChar: locale.substr(0, 1),
                 localeAbr: locale.substr(0, 3),
             };
-            locales[weekDay.code] = obj;
+            locales[weekDay?.code] = obj;
         }
         return locales;
     });
diff --git a/test/cypress/integration/Order/orderCatalog.spec.js b/test/cypress/integration/Order/orderCatalog.spec.js
index 386e3b2aae1..050dd396cac 100644
--- a/test/cypress/integration/Order/orderCatalog.spec.js
+++ b/test/cypress/integration/Order/orderCatalog.spec.js
@@ -55,9 +55,9 @@ describe('OrderCatalog', () => {
     it('removes a secondary tag', () => {
         cy.get(':nth-child(1) > [data-cy="catalogFilterCategory"]').click();
         cy.selectOption('[data-cy="catalogFilterType"]', 'Anthurium');
-        cy.dataCy('vnFilterPanelChip').should('exist');
+        cy.dataCy('vnFilterPanelChip_typeFk').should('exist');
         cy.get('[data-cy="catalogFilterCustomTag"] > .q-chip__icon--remove').click();
-        cy.dataCy('vnFilterPanelChip').should('not.exist');
+        cy.dataCy('vnFilterPanelChip_typeFk').should('not.exist');
     });
 
     it('Removes category tag', () => {
diff --git a/test/cypress/integration/client/clientList.spec.js b/test/cypress/integration/client/clientList.spec.js
index 467c6c37d8b..caf94b8bd58 100644
--- a/test/cypress/integration/client/clientList.spec.js
+++ b/test/cypress/integration/client/clientList.spec.js
@@ -53,7 +53,7 @@ describe.skip('Client list', () => {
     it('Client founded create ticket', () => {
         const search = 'Jessica Jones';
         cy.searchByLabel('Name', search);
-        cy.openActionDescriptor('Create ticket');
+        cy.selectDescriptorOption();
         cy.waitForElement('#formModel');
         cy.waitForElement('.q-form');
         cy.checkValueForm(1, search);
diff --git a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
index 11ca1bb59be..ee4d9fb749b 100644
--- a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
@@ -1,26 +1,40 @@
 /// <reference types="cypress" />
+import moment from 'moment';
 describe('InvoiceInBasicData', () => {
-    const firstFormSelect = '.q-card > .vn-row:nth-child(1) > .q-select';
     const dialogInputs = '.q-dialog input';
-    const resetBtn = '.q-btn-group--push > .q-btn--flat';
     const getDocumentBtns = (opt) => `[data-cy="dms-buttons"]  > :nth-child(${opt})`;
+    const futureDate = moment().add(1, 'days').format('DD-MM-YYYY');
+    const mock = {
+        invoiceInBasicDataSupplier: { val: 'Bros nick', type: 'select' },
+        invoiceInBasicDataSupplierRef_input: 'mockInvoice41',
+        invoiceInBasicDataIssued: { val: futureDate, type: 'date' },
+        invoiceInBasicDataOperated: { val: futureDate, type: 'date' },
+        invoiceInBasicDatabookEntried: { val: futureDate, type: 'date' },
+        invoiceInBasicDataBooked: {
+            val: moment().add(5, 'days').format('DD-MM-YYYY'),
+            type: 'date',
+        },
+        invoiceInBasicDataDeductibleExpenseFk: {
+            val: '4751000000',
+            type: 'select',
+        },
+        invoiceInBasicDataCurrencyFk: { val: 'USD', type: 'select' },
+        invoiceInBasicDataCompanyFk: { val: 'CCs', type: 'select' },
+        invoiceInBasicDataWithholdingSageFk: {
+            val: 'Arrendamiento y subarrendamiento',
+            type: 'select',
+        },
+    };
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/1/basic-data`);
     });
 
-    it('should edit the provideer and supplier ref', () => {
-        cy.dataCy('UnDeductibleVatSelect').type('4751000000');
-        cy.get('.q-menu .q-item').contains('4751000000').click();
-        cy.get(resetBtn).click();
-
-        cy.waitForElement('#formModel').within(() => {
-            cy.dataCy('vnSupplierSelect').type('Bros nick');
-        })
-        cy.get('.q-menu .q-item').contains('Bros nick').click();
+    it('should edit every field', () => {
+        cy.fillInForm(mock, { attr: 'data-cy' });
         cy.saveCard();
-        cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Bros nick');
+        cy.validateForm(mock, { attr: 'data-cy' });
     });
 
     it('should edit, remove and create the dms data', () => {
@@ -44,7 +58,7 @@ describe('InvoiceInBasicData', () => {
         cy.checkNotification('Data saved');
 
         //create
-        cy.get('[data-cy="dms-create"]').eq(0).click();
+        cy.get('[data-cy="invoiceInBasicDataDmsAdd"]').eq(0).click();
         cy.get('[data-cy="VnDms_inputFile"').selectFile(
             'test/cypress/fixtures/image.jpg',
             {
diff --git a/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js b/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js
index 73117404015..275fa135879 100644
--- a/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInCorrective.spec.js
@@ -1,22 +1,59 @@
-/// <reference types="cypress" />
-describe('InvoiceInCorrective', () => {
-    const saveDialog = '.q-card > .q-card__actions > .q-btn--standard ';
+describe('invoiceInCorrective', () => {
+    beforeEach(() => cy.login('administrative'));
 
-    it('should create a correcting invoice', () => {
-        cy.viewport(1280, 720);
-        cy.login('developer');
-        cy.visit(`/#/invoice-in/1/summary`);
+    it('should modify the invoice', () => {
+        cy.visit('/#/invoice-in/1/summary');
         cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
+        cy.intercept('POST', '/api/InvoiceInCorrections/crud').as('crud');
+        cy.intercept('GET', /InvoiceInCorrections\?filter=.+/).as('getCorrective');
 
-        cy.openActionsDescriptor();
+        cy.selectDescriptorOption(4);
+        cy.dataCy('saveCorrectiveInvoice').click();
 
-        cy.dataCy('createCorrectiveItem').click();
-        cy.get(saveDialog).click();
-        cy.wait('@corrective').then((interception) => {
-            const correctingId = interception.response.body;
-            cy.url().should('include', `/invoice-in/${correctingId}/summary`);
-            cy.visit(`/#/invoice-in/${correctingId}/corrective`);
+        cy.wait('@corrective').then(({ response }) => {
+            const correctingFk = response.body;
+            cy.url().should('include', `/invoice-in/${correctingFk}/summary`);
+            cy.visit(`/#/invoice-in/${correctingFk}/corrective`);
+            cy.selectOption('[data-cy="invoiceInCorrective_class"]', 'r4');
+            cy.selectOption('[data-cy="invoiceInCorrective_type"]', 'sustitución');
+            cy.selectOption('[data-cy="invoiceInCorrective_reason"]', 'vat');
+            cy.dataCy('crudModelDefaultSaveBtn').click();
+
+            cy.wait('@crud');
+            cy.reload();
+            cy.wait('@getCorrective');
+            cy.validateRow('tbody > :nth-of-type(1)', [
+                ,
+                'S – Por sustitución',
+                'R4',
+                'Error in VAT calculation',
+            ]);
         });
-        cy.get('tbody > tr:visible').should('have.length', 1);
+    });
+
+    it('should not be able to modify the invoice if the original invoice is booked', () => {
+        cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
+        cy.visit('/#/invoice-in/4/summary');
+        cy.selectDescriptorOption();
+        cy.dataCy('VnConfirm_confirm').click();
+        cy.selectDescriptorOption(4);
+        cy.dataCy('saveCorrectiveInvoice').click();
+
+        cy.wait('@corrective').then(({ response }) => {
+            const correctingFk = response.body;
+            cy.url().should('include', `/invoice-in/${correctingFk}/summary`);
+            cy.visit(`/#/invoice-in/${correctingFk}/corrective`);
+
+            cy.dataCy('invoiceInCorrective_class').should('be.disabled');
+            cy.dataCy('invoiceInCorrective_type').should('be.disabled');
+            cy.dataCy('invoiceInCorrective_reason').should('be.disabled');
+        });
+    });
+
+    it('should show/hide the section if it is a corrective invoice', () => {
+        cy.visit('/#/invoice-in/1/summary');
+        cy.get('[data-cy="InvoiceInCorrective-menu-item"]').should('not.exist');
+        cy.clicDescriptorAction(4);
+        cy.get('[data-cy="InvoiceInCorrective-menu-item"]').should('exist');
     });
 });
diff --git a/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js b/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
index 97a9fe976a2..7058e154ca7 100644
--- a/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
@@ -1,21 +1,147 @@
 describe('InvoiceInDescriptor', () => {
-    const book = '.summaryHeader > .no-wrap > .q-btn';
-    const firstDescritorOpt = '.q-menu > .q-list > :nth-child(5) > .q-item__section';
-    const checkbox = ':nth-child(5) > .q-checkbox';
+    beforeEach(() => cy.login('administrative'));
 
-    it('should booking and unbooking the invoice properly', () => {
-        cy.viewport(1280, 720);
-        cy.login('developer');
-        cy.visit('/#/invoice-in/1/summary');
-        cy.waitForElement('.q-page');
+    describe('more options', () => {
+        it('should booking and unbooking the invoice properly', () => {
+            const checkbox = '[data-cy="vnLvIs booked"] > .q-checkbox';
+            cy.visit('/#/invoice-in/2/summary');
+            cy.selectDescriptorOption();
+            cy.dataCy('VnConfirm_confirm').click();
+            cy.validateCheckbox(checkbox);
+            cy.selectDescriptorOption();
+            cy.dataCy('VnConfirm_confirm').click();
+            cy.validateCheckbox(checkbox, false);
+        });
 
-        cy.get(book).click();
-        cy.dataCy('VnConfirm_confirm').click();
-        cy.get(checkbox).invoke('attr', 'aria-checked').should('eq', 'true');
+        it('should delete the invoice properly', () => {
+            cy.visit('/#/invoice-in/2/summary');
+            cy.selectDescriptorOption(2);
+            cy.clickConfirm();
+            cy.checkNotification('invoice deleted');
+        });
 
-        cy.dataCy('descriptor-more-opts').first().click();
-        cy.get(firstDescritorOpt).click();
-        cy.dataCy('VnConfirm_confirm').click();
-        cy.get(checkbox).invoke('attr', 'aria-checked').should('eq', 'false');
+        it('should clone the invoice properly', () => {
+            cy.visit('/#/invoice-in/3/summary');
+            cy.selectDescriptorOption(3);
+            cy.clickConfirm();
+            cy.checkNotification('Invoice cloned');
+        });
+
+        it('should show the agricultural PDF properly', () => {
+            cy.visit('/#/invoice-in/6/summary');
+            cy.validatePdfDownload(
+                /api\/InvoiceIns\/6\/invoice-in-pdf\?access_token=.*/,
+                () => cy.selectDescriptorOption(4),
+            );
+        });
+
+        it('should send the agricultural PDF properly', () => {
+            cy.intercept('POST', 'api/InvoiceIns/6/invoice-in-email').as('sendEmail');
+            cy.visit('/#/invoice-in/6/summary');
+            cy.selectDescriptorOption(5);
+
+            cy.dataCy('SendEmailNotifiactionDialogInput_input').type(
+                '{selectall}jorgito@gmail.mx',
+            );
+            cy.clickConfirm();
+            cy.checkNotification('Notification sent');
+            cy.wait('@sendEmail').then(({ request, response }) => {
+                expect(request.body).to.deep.equal({
+                    recipientId: 2,
+                    recipient: 'jorgito@gmail.mx',
+                });
+                expect(response.statusCode).to.equal(200);
+            });
+        });
+        // https://redmine.verdnatura.es/issues/8767
+        it.skip('should download the file properly', () => {
+            cy.visit('/#/invoice-in/1/summary');
+            cy.validateDownload(() => cy.selectDescriptorOption(5));
+        });
+    });
+
+    describe('buttons', () => {
+        beforeEach(() => cy.visit('/#/invoice-in/1/summary'));
+
+        it('should navigate to the supplier summary', () => {
+            cy.clicDescriptorAction(1);
+            cy.url().should('to.match', /supplier\/\d+\/summary/);
+        });
+
+        it('should navigate to the entry summary', () => {
+            cy.clicDescriptorAction(2);
+            cy.url().should('to.match', /entry\/\d+\/summary/);
+        });
+
+        it('should navigate to the invoiceIn list', () => {
+            cy.clicDescriptorAction(3);
+            cy.url().should('to.match', /invoice-in\/list\?table=\{.*supplierFk.+\}/);
+        });
+    });
+
+    describe('corrective', () => {
+        const originalId = 4;
+
+        beforeEach(() => cy.visit(`/#/invoice-in/${originalId}/summary`));
+
+        it('should create a correcting invoice and redirect to original invoice', () => {
+            createCorrective();
+            redirect(originalId);
+        });
+
+        it('should create a correcting invoice and navigate to list filtered by corrective', () => {
+            createCorrective();
+            redirect(originalId);
+
+            cy.clicDescriptorAction(4);
+            cy.validateVnTableRows({
+                cols: [
+                    {
+                        name: 'supplierRef',
+                        val: '1237',
+                        operation: 'include',
+                    },
+                ],
+            });
+        });
+    });
+
+    describe('link', () => {
+        it('should open the supplier descriptor popup', () => {
+            cy.visit('/#/invoice-in/1/summary');
+            cy.intercept('GET', /Suppliers\/\d+/).as('getSupplier');
+
+            cy.dataCy('invoiceInDescriptor_supplier').then(($el) => {
+                const alias = $el.text().trim();
+                $el.click();
+                cy.wait('@getSupplier').then(() =>
+                    cy.validateDescriptor({ listbox: { 1: alias }, popup: true }),
+                );
+            });
+        });
     });
 });
+
+function createCorrective() {
+    cy.intercept('POST', '/api/InvoiceIns/corrective').as('corrective');
+
+    cy.selectDescriptorOption(4);
+    cy.dataCy('saveCorrectiveInvoice').click();
+
+    cy.wait('@corrective').then(({ response }) => {
+        const correctingId = response.body;
+        cy.url().should('include', `/invoice-in/${correctingId}/summary`);
+        cy.visit(`/#/invoice-in/${correctingId}/corrective`);
+        cy.dataCy('invoiceInCorrective_class').should('contain.value', 'R2');
+        cy.dataCy('invoiceInCorrective_type').should('contain.value', 'diferencias');
+        cy.dataCy('invoiceInCorrective_reason').should('contain.value', 'sales details');
+    });
+}
+
+function redirect(subtitle) {
+    const regex = new RegExp(`InvoiceIns/${subtitle}\\?filter=.*`);
+    cy.intercept('GET', regex).as('getOriginal');
+    cy.clicDescriptorAction(4);
+    cy.wait('@getOriginal');
+    cy.validateDescriptor({ subtitle });
+}
diff --git a/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js b/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
index 5a5becd222d..2fc34a7aec2 100644
--- a/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
@@ -4,7 +4,7 @@ describe('InvoiceInDueDay', () => {
     const addBtn = '.q-page-sticky > div > .q-btn > .q-btn__content';
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/6/due-day`);
     });
 
diff --git a/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js b/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
index 4c255054843..6a1c187858f 100644
--- a/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInIntrastat.spec.js
@@ -6,7 +6,7 @@ describe('InvoiceInIntrastat', () => {
     const firstRowAmount = `${firstRow} > :nth-child(3)`;
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/1/intrastat`);
     });
 
diff --git a/test/cypress/integration/invoiceIn/invoiceInList.spec.js b/test/cypress/integration/invoiceIn/invoiceInList.spec.js
index d9ab3f7e790..44a61609e5f 100644
--- a/test/cypress/integration/invoiceIn/invoiceInList.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInList.spec.js
@@ -1,13 +1,21 @@
 /// <reference types="cypress" />
+
 describe('InvoiceInList', () => {
     const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)';
     const firstId = `${firstRow} > td:nth-child(2) span`;
     const firstDetailBtn = `${firstRow} .q-btn:nth-child(1)`;
     const summaryHeaders = '.summaryBody .header-link';
+    const mockInvoiceRef = `createMockInvoice${Math.floor(Math.random() * 100)}`;
+    const mock = {
+        vnSupplierSelect: { val: 'farmer king', type: 'select' },
+        'Invoice nº_input': mockInvoiceRef,
+        Company_select: { val: 'orn', type: 'select' },
+        'Expedition date_inputDate': '16-11-2001',
+    };
 
     beforeEach(() => {
         cy.viewport(1920, 1080);
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/list`);
         cy.get('#searchbar input').type('{enter}');
     });
@@ -27,4 +35,18 @@ describe('InvoiceInList', () => {
         cy.get(summaryHeaders).eq(1).contains('Basic data');
         cy.get(summaryHeaders).eq(4).contains('Vat');
     });
+
+    it('should create a new Invoice', () => {
+        cy.dataCy('vnTableCreateBtn').click();
+        cy.fillInForm({ ...mock }, { attr: 'data-cy' });
+        cy.dataCy('FormModelPopup_save').click();
+        cy.intercept('GET', /\/api\/InvoiceIns\/\d+\/getTotals$/).as('invoice');
+        cy.wait('@invoice').then(() =>
+            cy.validateDescriptor({
+                title: mockInvoiceRef,
+                listBox: { 0: '11/16/2001', 3: 'The farmer' },
+            }),
+        );
+        cy.get('[data-cy="vnLvCompany"]').should('contain.text', 'ORN');
+    });
 });
diff --git a/test/cypress/integration/invoiceIn/invoiceInSerial.spec.js b/test/cypress/integration/invoiceIn/invoiceInSerial.spec.js
new file mode 100644
index 00000000000..faad22f1254
--- /dev/null
+++ b/test/cypress/integration/invoiceIn/invoiceInSerial.spec.js
@@ -0,0 +1,23 @@
+describe('InvoiceInSerial', () => {
+    beforeEach(() => {
+        cy.login('administrative');
+        cy.visit('#/invoice-in/serial');
+    });
+
+    it('should filter by serial number', () => {
+        cy.dataCy('serial_input').type('R{enter}');
+        cy.validateVnTableRows({ cols: [{ name: 'serial', val: 'r' }] });
+    });
+
+    it('should filter by last days ', () => {
+        let before;
+        cy.dataCy('vnTableCell_total')
+            .invoke('text')
+            .then((total) => (before = +total));
+
+        cy.dataCy('Last days_input').type('{selectall}1{enter}');
+        cy.dataCy('vnTableCell_total')
+            .invoke('text')
+            .then((total) => expect(+total).to.be.lessThan(before));
+    });
+});
diff --git a/test/cypress/integration/invoiceIn/invoiceInSummary.spec.js b/test/cypress/integration/invoiceIn/invoiceInSummary.spec.js
new file mode 100644
index 00000000000..72dbdd9a843
--- /dev/null
+++ b/test/cypress/integration/invoiceIn/invoiceInSummary.spec.js
@@ -0,0 +1,24 @@
+describe('InvoiceInSummary', () => {
+    beforeEach(() => {
+        cy.login('administrative');
+        cy.visit('/#/invoice-in/3/summary');
+    });
+
+    it('should booking and unbooking the invoice properly', () => {
+        const checkbox = '[data-cy="vnLvIs booked"] > .q-checkbox';
+        cy.dataCy('invoiceInSummary_book').click();
+        cy.dataCy('VnConfirm_confirm').click();
+        cy.validateCheckbox(checkbox);
+    });
+
+    it('should open the supplier descriptor popup', () => {
+        cy.intercept('GET', /Suppliers\/\d+/).as('getSupplier');
+        cy.dataCy('invoiceInSummary_supplier').then(($el) => {
+            const description = $el.text().trim();
+            $el.click();
+            cy.wait('@getSupplier').then(() =>
+                cy.validateDescriptor({ description, popup: true }),
+            );
+        });
+    });
+});
diff --git a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
index 3e9997a74ff..e9412244f11 100644
--- a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
@@ -8,7 +8,7 @@ describe('InvoiceInVat', () => {
     const randomInt = Math.floor(Math.random() * 100);
 
     beforeEach(() => {
-        cy.login('developer');
+        cy.login('administrative');
         cy.visit(`/#/invoice-in/1/vat`);
     });
 
diff --git a/test/cypress/integration/vnComponent/VnLog.spec.js b/test/cypress/integration/vnComponent/VnLog.spec.js
index 496b1cd12d9..88edabb2e9c 100644
--- a/test/cypress/integration/vnComponent/VnLog.spec.js
+++ b/test/cypress/integration/vnComponent/VnLog.spec.js
@@ -25,7 +25,7 @@ describe('VnLog', () => {
 
     it('should show claimDescriptor', () => {
         cy.dataCy('iconLaunch-claimFk').first().click();
-        cy.dataCy('descriptor_id').contains('1');
+        cy.dataCy('cardDescriptor_subtitle').contains('1');
         cy.dataCy('iconLaunch-claimFk').first().click();
     });
 });
diff --git a/test/cypress/integration/zone/zoneCalendar.spec.js b/test/cypress/integration/zone/zoneCalendar.spec.js
index 07661a17de2..68b85d1d21f 100644
--- a/test/cypress/integration/zone/zoneCalendar.spec.js
+++ b/test/cypress/integration/zone/zoneCalendar.spec.js
@@ -1,11 +1,10 @@
 describe('ZoneCalendar', () => {
     const addEventBtn = '.q-page-sticky > div > .q-btn';
     const submitBtn = '.q-mt-lg > .q-btn--standard';
-    const deleteBtn = '[data-cy="ZoneEventsPanelDeleteBtn"]';
+    const deleteBtn = 'ZoneEventsPanelDeleteBtn';
 
     beforeEach(() => {
         cy.login('developer');
-        cy.viewport(1920, 1080);
         cy.visit(`/#/zone/13/events`);
     });
 
@@ -14,7 +13,7 @@ describe('ZoneCalendar', () => {
         cy.dataCy('ZoneEventInclusionDayRadio').click();
         cy.get('.q-card > :nth-child(5)').type('01/01/2001');
         cy.get(submitBtn).click();
-        cy.get(deleteBtn).click();
+        cy.dataCy(deleteBtn).click();
         cy.dataCy('VnConfirm_confirm').click();
     });
 
@@ -23,7 +22,7 @@ describe('ZoneCalendar', () => {
         cy.get('.flex > .q-gutter-x-sm > :nth-child(1)').click();
         cy.get('.flex > .q-gutter-x-sm > :nth-child(2)').click();
         cy.get(submitBtn).click();
-        cy.get(deleteBtn).click();
+        cy.dataCy(deleteBtn).click();
         cy.dataCy('VnConfirm_confirm').click();
     });
 
@@ -34,7 +33,7 @@ describe('ZoneCalendar', () => {
         cy.dataCy('From_inputDate').type('01/01/2001');
         cy.dataCy('To_inputDate').type('31/01/2001');
         cy.get(submitBtn).click();
-        cy.get(deleteBtn).click();
+        cy.dataCy(deleteBtn).click();
         cy.dataCy('VnConfirm_confirm').click();
     });
 
diff --git a/test/cypress/integration/zone/zoneDeliveryDays.spec.js b/test/cypress/integration/zone/zoneDeliveryDays.spec.js
index 291c20ce320..a89def12d31 100644
--- a/test/cypress/integration/zone/zoneDeliveryDays.spec.js
+++ b/test/cypress/integration/zone/zoneDeliveryDays.spec.js
@@ -37,7 +37,6 @@ describe('ZoneDeliveryDays', () => {
                 cy.get('@focusedElement').blur();
             }
         });
-        cy.get('.q-menu').should('not.exist');
 
         cy.dataCy('ZoneDeliveryDaysAgencySelect').type(agency);
         cy.get('.q-menu .q-item').contains(agency).click();
@@ -49,7 +48,6 @@ describe('ZoneDeliveryDays', () => {
                 cy.get('@focusedElement').blur();
             }
         });
-        cy.get('.q-menu').should('not.exist');
 
         cy.get(submitForm).click();
         cy.wait('@events').then((interception) => {
diff --git a/test/cypress/integration/zone/zoneLocations.spec.js b/test/cypress/integration/zone/zoneLocations.spec.js
index 3a52d276c54..dabd3eb2bf8 100644
--- a/test/cypress/integration/zone/zoneLocations.spec.js
+++ b/test/cypress/integration/zone/zoneLocations.spec.js
@@ -1,26 +1,59 @@
-describe.skip('ZoneLocations', () => {
-    const data = {
-        Warehouse: { val: 'Warehouse One', type: 'select' },
-    };
-
-    const postalCode =
-        '[style=""] > :nth-child(1) > :nth-child(1) > :nth-child(2) > :nth-child(1) > :nth-child(1) > :nth-child(2) > :nth-child(1) > .q-tree__node--parent > .q-tree__node-collapsible > .q-tree__children';
-
+describe('ZoneLocations', () => {
+    const cp = 46680;
+    const searchIcon = '.router-link-active > .q-icon';
     beforeEach(() => {
-        cy.viewport(1280, 720);
         cy.login('developer');
         cy.visit(`/#/zone/2/location`);
     });
 
-    it('should show all locations on entry', () => {
+    it('should be able to search by postal code', () => {
         cy.get('.q-tree > :nth-child(1) > :nth-child(2) > :nth-child(1)')
-            .children()
-            .should('have.length', 9);
+            .should('exist')
+            .should('be.visible');
+
+        cy.intercept('GET', '**/api/Zones/2/getLeaves*', (req) => {
+            req.headers['cache-control'] = 'no-cache';
+            req.headers['pragma'] = 'no-cache';
+            req.headers['expires'] = '0';
+
+            req.on('response', (res) => {
+                delete res.headers['if-none-match'];
+                delete res.headers['if-modified-since'];
+            });
+        }).as('location');
+        cy.get('#searchbarForm').type(cp);
+        cy.get(searchIcon).click();
+        cy.wait('@location').then((interception) => {
+            const data = interception.response.body;
+            expect(data).to.include(cp);
+        });
     });
 
-    it('should be able to search by postal code', () => {
-        cy.get('#searchbarForm').type('46680');
-        cy.get('.router-link-active > .q-icon').click();
-        cy.get(postalCode).should('include.text', '46680');
+    it('should check, uncheck, and set a location to mixed state', () => {
+        cy.get('#searchbarForm').type(cp);
+        cy.get(searchIcon).click();
+
+        cy.get('.q-tree > :nth-child(1) > :nth-child(2) > :nth-child(1)')
+            .as('tree')
+            .within(() => {
+                cy.get('[data-cy="ZoneLocationTreeCheckbox"] > .q-checkbox__inner')
+                    .last()
+                    .as('lastCheckbox');
+
+                const verifyCheckboxState = (state) => {
+                    cy.get('@lastCheckbox')
+                        .parents('.q-checkbox')
+                        .should('have.attr', 'aria-checked', state);
+                };
+
+                cy.get('@lastCheckbox').click();
+                verifyCheckboxState('true');
+
+                cy.get('@lastCheckbox').click();
+                verifyCheckboxState('false');
+
+                cy.get('@lastCheckbox').click();
+                verifyCheckboxState('mixed');
+            });
     });
 });
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 45e17654e06..de25959b2ca 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -27,8 +27,9 @@
 // DO NOT REMOVE
 // Imports Quasar Cypress AE predefined commands
 // import { registerCommands } from '@quasar/quasar-app-extension-testing-e2e-cypress';
-
+import moment from 'moment';
 import waitUntil from './waitUntil';
+
 Cypress.Commands.add('waitUntil', { prevSubject: 'optional' }, waitUntil);
 
 Cypress.Commands.add('resetDB', () => {
@@ -122,9 +123,10 @@ function selectItem(selector, option, ariaControl, hasWrite = true) {
     cy.waitSpinner();
 
     getItems(ariaControl).then((items) => {
-        const matchingItem = items
-            .toArray()
-            .find((item) => item.innerText.includes(option));
+        const matchingItem = items.toArray().find((item) => {
+            const val = typeof option == 'string' ? option.toLowerCase() : option;
+            return item.innerText.toLowerCase().includes(val);
+        });
         if (matchingItem) return cy.wrap(matchingItem).click();
 
         if (hasWrite) cy.get(selector).clear().type(option);
@@ -160,14 +162,20 @@ Cypress.Commands.add('countSelectOptions', (selector, option) => {
     cy.get('.q-menu .q-item').should('have.length', option);
 });
 
-Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
+Cypress.Commands.add('fillInForm', (obj, opts = {}) => {
+    cy.waitSpinner();
+    const { form = '.q-form > .q-card', attr = 'aria-label' } = opts;
     cy.waitForElement(form);
     cy.get(`${form} input`).each(([el]) => {
         cy.wrap(el)
-            .invoke('attr', 'aria-label')
-            .then((ariaLabel) => {
-                const field = obj[ariaLabel];
+            .invoke('attr', attr)
+            .then((key) => {
+                const field = obj[key];
                 if (!field) return;
+                if (typeof field == 'string')
+                    return cy
+                        .wrap(el)
+                        .type(`{selectall}{backspace}${field}`, { delay: 0 });
 
                 const { type, val } = field;
                 switch (type) {
@@ -175,7 +183,9 @@ Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
                         cy.selectOption(el, val);
                         break;
                     case 'date':
-                        cy.get(el).type(val.split('-').join(''));
+                        cy.get(el).type(
+                            `{selectall}{backspace}${val.split('-').join('')}`,
+                        );
                         break;
                     case 'time':
                         cy.get(el).click();
@@ -191,6 +201,40 @@ Cypress.Commands.add('fillInForm', (obj, form = '.q-form > .q-card') => {
     });
 });
 
+Cypress.Commands.add('validateForm', (obj, opts = {}) => {
+    const { form = '.q-form > .q-card', attr = 'data-cy' } = opts;
+    cy.waitForElement(form);
+    cy.get(`${form} input`).each(([el]) => {
+        cy.wrap(el)
+            .invoke('attr', attr)
+            .then((key) => {
+                const field = obj[key];
+                if (!field) return;
+
+                const { type, val } = field;
+                cy.get(el)
+                    .invoke('val')
+                    .then((elVal) => {
+                        if (typeof field == 'string')
+                            expect(elVal.toLowerCase()).to.equal(field.toLowerCase());
+                        else
+                            switch (type) {
+                                case 'date':
+                                    const elDate = moment(elVal, 'DD-MM-YYYY');
+                                    const mockDate = moment(val, 'DD-MM-YYYY');
+                                    expect(elDate.isSame(mockDate, 'day')).to.be.true;
+                                    break;
+                                default:
+                                    expect(elVal.toLowerCase()).to.equal(
+                                        val.toLowerCase(),
+                                    );
+                                    break;
+                            }
+                    });
+            });
+    });
+});
+
 Cypress.Commands.add('checkOption', (selector) => {
     cy.get(selector).find('.q-checkbox__inner').click();
 });
@@ -207,14 +251,17 @@ Cypress.Commands.add('saveCard', () => {
 Cypress.Commands.add('resetCard', () => {
     cy.get('[title="Reset"]').click();
 });
+
 Cypress.Commands.add('removeCard', () => {
     cy.get('[title="Remove"]').click();
 });
+
 Cypress.Commands.add('addCard', () => {
     cy.waitForElement('tbody');
     cy.waitForElement('.q-page-sticky > div > .q-btn');
     cy.get('.q-page-sticky > div > .q-btn').click();
 });
+
 Cypress.Commands.add('clickConfirm', () => {
     cy.waitForElement('.q-dialog__inner > .q-card');
     cy.get('.q-card__actions > .q-btn--unelevated > .q-btn__content > .block').click();
@@ -295,6 +342,7 @@ Cypress.Commands.add('removeRow', (rowIndex) => {
             });
         });
 });
+
 Cypress.Commands.add('openListSummary', (row) => {
     cy.get('.card-list-body .actions .q-btn:nth-child(2)').eq(row).click();
 });
@@ -322,20 +370,8 @@ Cypress.Commands.add('validateContent', (selector, expectedValue) => {
     cy.get(selector).should('have.text', expectedValue);
 });
 
-Cypress.Commands.add('openActionDescriptor', (opt) => {
-    cy.openActionsDescriptor();
-    const listItem = '[role="menu"] .q-list .q-item';
-    cy.contains(listItem, opt).click();
-});
-
 Cypress.Commands.add('openActionsDescriptor', () => {
-    cy.get('[data-cy="descriptor-more-opts"]').click();
-});
-
-Cypress.Commands.add('clickButtonDescriptor', (id) => {
-    cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
-        .invoke('removeAttr', 'target')
-        .click();
+    cy.get('[data-cy="cardDescriptor"] [data-cy="descriptor-more-opts"]').click();
 });
 
 Cypress.Commands.add('openUserPanel', () => {
@@ -424,3 +460,137 @@ Cypress.Commands.add('searchBtnFilterPanel', () => {
 Cypress.Commands.add('waitRequest', (alias, cb) => {
     cy.wait(alias).then(cb);
 });
+
+Cypress.Commands.add('validateDescriptor', (toCheck = {}) => {
+    const { title, description, subtitle, listbox = {}, popup = false } = toCheck;
+
+    const popupSelector = popup ? '[role="menu"] ' : '';
+
+    if (title) cy.get(`${popupSelector}[data-cy="cardDescriptor_title"]`).contains(title);
+    if (description)
+        cy.get(`${popupSelector}[data-cy="cardDescriptor_description"]`).contains(
+            description,
+        );
+    if (subtitle)
+        cy.get(`${popupSelector}[data-cy="cardDescriptor_subtitle"]`).contains(subtitle);
+
+    for (const index in listbox)
+        cy.get(`${popupSelector}[data-cy="cardDescriptor_listbox"] > *`)
+            .eq(index)
+            .should('contain.text', listbox[index]);
+});
+
+Cypress.Commands.add('validateVnTableRows', (opts = {}) => {
+    let { cols = [], rows = [] } = opts;
+    if (!Array.isArray(cols)) cols = [cols];
+    const rowSelector = rows.length
+        ? rows.map((row) => `> :nth-child(${row})`).join(', ')
+        : '> *';
+    cy.get(`[data-cy="vnTable"] .q-virtual-scroll__content`).within(() => {
+        cy.get(`${rowSelector}`).each(($el) => {
+            for (const { name, type = 'string', val, operation = 'equal' } of cols) {
+                cy.wrap($el)
+                    .find(`[data-cy="vnTableCell_${name}"]`)
+                    .invoke('text')
+                    .then((text) => {
+                        if (type === 'string')
+                            expect(text.trim().toLowerCase()).to[operation](
+                                val.toLowerCase(),
+                            );
+                        if (type === 'number') cy.checkNumber(text, val, operation);
+                        if (type === 'date') cy.checkDate(text, val, operation);
+                    });
+            }
+        });
+    });
+});
+
+Cypress.Commands.add('checkDate', (rawDate, expectedVal, operation) => {
+    const date = moment(rawDate.trim(), 'MM/DD/YYYY');
+    const compareDate = moment(expectedVal, 'DD/MM/YYYY');
+
+    switch (operation) {
+        case 'equal':
+            expect(text.trim()).to.equal(compareDate);
+            break;
+        case 'before':
+            expect(date.isBefore(compareDate)).to.be.true;
+            break;
+        case 'after':
+            expect(date.isAfter(compareDate)).to.be.true;
+    }
+});
+
+Cypress.Commands.add('selectDescriptorOption', (opt = 1) => {
+    const listItem = '[data-cy="descriptor-more-opts_list"]';
+    cy.get('body').then(($body) => {
+        if (!$body.find(listItem).length) cy.openActionsDescriptor();
+    });
+
+    cy.waitForElement(listItem);
+    cy.get(`${listItem} > :not(template):nth-of-type(${opt})`).click();
+});
+
+Cypress.Commands.add('validateCheckbox', (selector, expectedVal = 'true') => {
+    cy.get(selector).should('have.attr', 'aria-checked', expectedVal.toString());
+});
+
+Cypress.Commands.add('validateDownload', (trigger, opts = {}) => {
+    const {
+        url = /api\/dms\/\d+\/downloadFile\?access_token=.+/,
+        types = ['text/plain', 'image/jpeg'],
+        alias = 'download',
+    } = opts;
+    cy.intercept('GET', url).as(alias);
+    trigger().then(() => {
+        cy.wait(`@${alias}`).then(({ response }) => {
+            expect(response.statusCode).to.equal(200);
+            const isValidType = types.some((type) =>
+                response.headers['content-type'].includes(type),
+            );
+            expect(isValidType).to.be.true;
+        });
+    });
+});
+
+Cypress.Commands.add('validatePdfDownload', (match, trigger) => {
+    cy.window().then((win) => {
+        cy.stub(win, 'open')
+            .callsFake(() => null)
+            .as('pdf');
+    });
+    trigger();
+    cy.get('@pdf')
+        .should('be.calledOnce')
+        .then((stub) => {
+            const [url] = stub.getCall(0).args;
+            expect(url).to.match(match);
+            cy.request(url).then((response) =>
+                expect(response.headers['content-type']).to.include('application/pdf'),
+            );
+        });
+});
+
+Cypress.Commands.add('clicDescriptorAction', (index = 1) => {
+    cy.get(`[data-cy="descriptor_actions"] .q-btn:nth-of-type(${index})`).click();
+});
+
+Cypress.Commands.add('checkQueryParams', (expectedParams = {}) => {
+    cy.url().then((url) => {
+        const urlParams = new URLSearchParams(url.split('?')[1]);
+
+        for (const key in expectedParams) {
+            const expected = expectedParams[key];
+            const param = JSON.parse(decodeURIComponent(urlParams.get(key)));
+
+            if (typeof expected === 'object') {
+                const { subkey, val } = expected;
+                expect(param[subkey]).to.equal(val);
+            } else expect(param).to.equal(expected);
+        }
+    });
+});
+
+Cypress.Commands.add('waitTableScrollLoad', () =>
+    cy.waitForElement('[data-q-vs-anchor]'),
+);