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',