From 7f376c8ea4cfa0b1c7863017e33c5a9457f9491a Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Fri, 19 Jul 2024 14:53:44 +0200 Subject: [PATCH 01/20] fix: refs #7717 fix catalog filter, searchbar redirect and search --- src/pages/Order/{ => Card}/OrderCatalog.vue | 12 ++++++++++++ src/pages/Order/Card/OrderCatalogFilter.vue | 20 +++++++++++++++----- src/pages/Order/{ => Card}/OrderLines.vue | 0 src/pages/Order/{ => Card}/OrderVolume.vue | 0 src/router/modules/order.js | 6 +++--- 5 files changed, 30 insertions(+), 8 deletions(-) rename src/pages/Order/{ => Card}/OrderCatalog.vue (87%) rename src/pages/Order/{ => Card}/OrderLines.vue (100%) rename src/pages/Order/{ => Card}/OrderVolume.vue (100%) diff --git a/src/pages/Order/OrderCatalog.vue b/src/pages/Order/Card/OrderCatalog.vue similarity index 87% rename from src/pages/Order/OrderCatalog.vue rename to src/pages/Order/Card/OrderCatalog.vue index 2cf6e1c29..071827a8b 100644 --- a/src/pages/Order/OrderCatalog.vue +++ b/src/pages/Order/Card/OrderCatalog.vue @@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n'; import VnPaginate from 'components/ui/VnPaginate.vue'; import CatalogItem from 'components/ui/CatalogItem.vue'; import OrderCatalogFilter from 'pages/Order/Card/OrderCatalogFilter.vue'; +import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; const route = useRoute(); const stateStore = useStateStore(); @@ -52,6 +53,17 @@ function extractValueTags(items) { </script> <template> + <Teleport to="#searchbar"> + <VnSearchbar + data-key="OrderCatalogList" + :user-params="catalogParams" + :static-params="['orderFk', 'orderBy']" + :redirect="false" + url="Orders/CatalogFilter" + :label="t('Search items')" + :info="t('You can search orders by reference')" + /> + </Teleport> <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above> <QScrollArea class="fit text-grey-8"> <OrderCatalogFilter diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index c354ec94b..992fe4b3f 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -27,7 +27,6 @@ const props = defineProps({ required: true, }, }); - const categoryList = ref(null); const selectedCategoryFk = ref(null); const typeList = ref(null); @@ -84,7 +83,14 @@ const selectedCategory = computed(() => (category) => category?.id === selectedCategoryFk.value ) ); - +function filterFn(val, update) { + update(() => { + const needle = val.toLowerCase(); + tagOptions.value = props.tagValue.filter( + (v) => v.toLowerCase().indexOf(needle) > -1 + ); + }); +} const selectedType = computed(() => { return (typeList.value || []).find((type) => type?.id === selectedTypeFk.value); }); @@ -352,7 +358,7 @@ const useLang = (values) => { v-if="!selectedTag" :label="t('params.value')" v-model="value.value" - :options="tagValue || []" + :options="tagOptions || []" option-value="value" option-label="value" dense @@ -362,6 +368,8 @@ const useLang = (values) => { use-input class="filter-input" @new-value="createValue" + @filter="filterFn" + @update:model-value="applyTagFilter(params, searchFn)" /> <VnSelect v-else-if="selectedTag === 1" @@ -377,6 +385,7 @@ const useLang = (values) => { use-input class="filter-input" @new-value="createValue" + @update:model-value="applyTagFilter(params, searchFn)" /> <VnInput v-else @@ -386,6 +395,7 @@ const useLang = (values) => { outlined rounded class="filter-input" + @keyup.enter="applyTagFilter(params, searchFn)" /> <QIcon name="delete" @@ -400,7 +410,7 @@ const useLang = (values) => { @click="tagValues.push({})" /> </QItem> - <QItem> + <!-- <QItem> <QItemSection class="q-py-sm"> <QBtn :label="t('Search')" @@ -414,7 +424,7 @@ const useLang = (values) => { @click.stop="applyTagFilter(params, searchFn)" /> </QItemSection> - </QItem> + </QItem> --> <QSeparator /> </template> </VnFilterPanel> diff --git a/src/pages/Order/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue similarity index 100% rename from src/pages/Order/OrderLines.vue rename to src/pages/Order/Card/OrderLines.vue diff --git a/src/pages/Order/OrderVolume.vue b/src/pages/Order/Card/OrderVolume.vue similarity index 100% rename from src/pages/Order/OrderVolume.vue rename to src/pages/Order/Card/OrderVolume.vue diff --git a/src/router/modules/order.js b/src/router/modules/order.js index aa1ca774d..8d1a6e5fe 100644 --- a/src/router/modules/order.js +++ b/src/router/modules/order.js @@ -72,7 +72,7 @@ export default { title: 'catalog', icon: 'vn:basket', }, - component: () => import('src/pages/Order/OrderCatalog.vue'), + component: () => import('src/pages/Order/Card/OrderCatalog.vue'), }, { name: 'OrderVolume', @@ -81,7 +81,7 @@ export default { title: 'volume', icon: 'vn:volume', }, - component: () => import('src/pages/Order/OrderVolume.vue'), + component: () => import('src/pages/Order/Card/OrderVolume.vue'), }, { name: 'OrderLines', @@ -90,7 +90,7 @@ export default { title: 'lines', icon: 'vn:lines', }, - component: () => import('src/pages/Order/OrderLines.vue'), + component: () => import('src/pages/Order/Card/OrderLines.vue'), }, ], }, From 02e1de083a934e1178bef41c67375f844b2e7f7e Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Fri, 19 Jul 2024 15:00:05 +0200 Subject: [PATCH 02/20] fix: duplicate key --- 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 2f1209a3a..6943252c9 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 diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index c5c4fab66..f32562313 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 From def3ca33a26619cb0a38b9d050283c9fc7227125 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Mon, 22 Jul 2024 12:52:58 +0200 Subject: [PATCH 03/20] fix: refs #7717 fixed searchbar filter with rightmenu filters' applied --- src/components/ui/VnSearchbar.vue | 8 +++++--- src/pages/Order/Card/OrderCatalog.vue | 1 + src/pages/Order/OrderList.vue | 8 ++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue index 0c7a8a3f6..6fb204afe 100644 --- a/src/components/ui/VnSearchbar.vue +++ b/src/components/ui/VnSearchbar.vue @@ -100,9 +100,11 @@ onMounted(() => { }); async function search() { - const staticParams = Object.entries(store.userParams).filter( - ([key, value]) => value && (props.staticParams || []).includes(key) - ); + const staticParams = Object.entries(store.userParams); + console.log('staticParams: ', staticParams); + // .filter( + // ([key, value]) => value && (props.staticParams || []).includes(key) + // ); arrayData.reset(['skip', 'page']); if (props.makeFetch) diff --git a/src/pages/Order/Card/OrderCatalog.vue b/src/pages/Order/Card/OrderCatalog.vue index 071827a8b..d1479e3c3 100644 --- a/src/pages/Order/Card/OrderCatalog.vue +++ b/src/pages/Order/Card/OrderCatalog.vue @@ -53,6 +53,7 @@ function extractValueTags(items) { </script> <template> + <!-- TODO Sobreescribir la barra de búsqueda --> <Teleport to="#searchbar"> <VnSearchbar data-key="OrderCatalogList" diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue index 945f61f3b..fa82540e6 100644 --- a/src/pages/Order/OrderList.vue +++ b/src/pages/Order/OrderList.vue @@ -3,12 +3,12 @@ import axios from 'axios'; import { useI18n } from 'vue-i18n'; import { computed, ref } from 'vue'; import { dashIfEmpty, toCurrency, toDate } from 'src/filters'; -import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import OrderSummary from 'pages/Order/Card/OrderSummary.vue'; import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import VnTable from 'src/components/VnTable/VnTable.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnSelect from 'src/components/common/VnSelect.vue'; +import OrderSearchbar from './Card/OrderSearchbar.vue'; const { t } = useI18n(); const { viewSummary } = useSummaryDialog(); @@ -132,11 +132,7 @@ async function fetchClientAddress(id, data) { } </script> <template> - <VnSearchbar - data-key="OrderList" - :label="t('Search order')" - :info="t('You can search orders by reference')" - /> + <OrderSearchbar /> <VnTable ref="tableRef" data-key="OrderList" From 368b8404fa60f9ddca22fa3b8463406d2e5fd004 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Mon, 22 Jul 2024 15:13:03 +0200 Subject: [PATCH 04/20] updates: OrderCatlago --- src/components/common/VnCard.vue | 8 ++++-- src/pages/Order/Card/OrderCard.vue | 32 +++++++++++++++++++-- src/pages/Order/Card/OrderCatalogFilter.vue | 2 +- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue index 17fa74317..4b7a6ba63 100644 --- a/src/components/common/VnCard.vue +++ b/src/components/common/VnCard.vue @@ -31,7 +31,10 @@ const url = computed(() => { if (props.baseUrl) return `${props.baseUrl}/${route.params.id}`; return props.customUrl; }); - +const searchRightDataKey = computed(() => { + if (!props.searchDataKey) return route.name; + else return props.searchDataKey; +}); const arrayData = useArrayData(props.dataKey, { url: url.value, filter: props.filter, @@ -74,10 +77,9 @@ if (props.baseUrl) { :redirect="searchRedirect" /> </slot> - <slot v-else name="searchbar" /> <RightMenu> <template #right-panel v-if="props.filterPanel"> - <component :is="props.filterPanel" :data-key="props.searchDataKey" /> + <component :is="props.filterPanel" :data-key="searchRightDataKey" /> </template> </RightMenu> <QPageContainer> diff --git a/src/pages/Order/Card/OrderCard.vue b/src/pages/Order/Card/OrderCard.vue index 5b6896656..ed4bea2ff 100644 --- a/src/pages/Order/Card/OrderCard.vue +++ b/src/pages/Order/Card/OrderCard.vue @@ -1,16 +1,44 @@ <script setup> +import { useI18n } from 'vue-i18n'; +import { computed } from 'vue'; +import { useRoute } from 'vue-router'; import VnCard from 'components/common/VnCard.vue'; import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue'; import OrderFilter from './OrderFilter.vue'; import OrderSearchbar from './OrderSearchbar.vue'; +import OrderCatalogFilter from './OrderCatalogFilter.vue'; +const config = { + OrderCatalog: OrderCatalogFilter, +}; +const route = useRoute(); + +const routeName = computed(() => route.name); +const customRouteRedirectName = computed(() => { + const route = config[routeName.value]; + if (route) return null; + return 'OrderList'; + //Jon, asi es como lo dejamos + // if (routeName.value === 'OrderCatalog') return null; + // return 'OrderList'; +}); +const customFilterPanel = computed(() => { + const filterPanel = config[routeName.value] ?? OrderFilter; + return filterPanel; + //Jon, asi es como lo dejamos + // if (routeName.value === 'OrderCatalog') return null; + // return 'OrderList'; + // if (routeName.value === 'OrderCatalog') return OrderCatalogFilter; + // return OrderFilter; +}); </script> + <template> <VnCard data-key="Order" base-url="Orders" :descriptor="OrderDescriptor" - :filter-panel="OrderFilter" - search-data-key="OrderList" + :filter-panel="customFilterPanel" + :search-data-key="customRouteRedirectName" > <template #searchbar> <OrderSearchbar /> diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index 992fe4b3f..8d96fe93a 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -205,7 +205,7 @@ const useLang = (values) => { <VnFilterPanel :data-key="props.dataKey" :hidden-tags="['orderFk', 'orderBy']" - :unremovable-params="['orderFk', 'orderBy']" + :un-removable-params="['orderFk', 'orderBy']" :expr-builder="exprBuilder" :custom-tags="['tagGroups']" @remove="clearFilter" From ce6a94bab8a13341adac336a4e1e7d80e5324e16 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Tue, 23 Jul 2024 11:46:21 +0200 Subject: [PATCH 05/20] fix: refs #7717 fix catalog searchbar and worker tests(refs #7323) --- src/components/ui/VnFilterPanel.vue | 72 ++++++++++--------- src/components/ui/VnSearchbar.vue | 4 -- .../InvoiceOutNegativeBasesFilter.vue | 2 +- src/pages/Order/Card/OrderCard.vue | 9 --- .../integration/worker/workerList.spec.js | 10 ++- .../integration/worker/workerLocker.spec.js | 7 +- 6 files changed, 49 insertions(+), 55 deletions(-) diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index 27b6e7b34..f79852a9d 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -106,21 +106,23 @@ watch( const isLoading = ref(false); async function search(evt) { - if (evt && $props.disableSubmitEvent) return; + try { + if (evt && $props.disableSubmitEvent) return; - store.filter.where = {}; - isLoading.value = true; - const filter = { ...userParams.value, ...$props.modelValue }; - store.userParamsChanged = true; - const { params: newParams } = await arrayData.addFilter({ - params: filter, - }); - userParams.value = newParams; + store.filter.where = {}; + isLoading.value = true; + const filter = { ...userParams.value, ...$props.modelValue }; + store.userParamsChanged = true; + const { params: newParams } = await arrayData.addFilter({ + params: filter, + }); + userParams.value = newParams; - if (!$props.showAll && !Object.values(filter).length) store.data = []; - - isLoading.value = false; - emit('search'); + if (!$props.showAll && !Object.values(filter).length) store.data = []; + emit('search'); + } finally { + isLoading.value = false; + } } async function reload() { @@ -135,29 +137,31 @@ async function reload() { } async function clearFilters() { - isLoading.value = true; - store.userParamsChanged = true; - arrayData.reset(['skip', 'filter.skip', 'page']); - // Filtrar los params no removibles - const removableFilters = Object.keys(userParams.value).filter((param) => - $props.unRemovableParams.includes(param) - ); - const newParams = {}; - // Conservar solo los params que no son removibles - for (const key of removableFilters) { - newParams[key] = userParams.value[key]; - } - userParams.value = {}; - userParams.value = { ...newParams }; // Actualizar los params con los removibles - await arrayData.applyFilter({ params: userParams.value }); + try { + isLoading.value = true; + store.userParamsChanged = true; + arrayData.reset(['skip', 'filter.skip', 'page']); + // Filtrar los params no removibles + const removableFilters = Object.keys(userParams.value).filter((param) => + $props.unRemovableParams.includes(param) + ); + const newParams = {}; + // Conservar solo los params que no son removibles + for (const key of removableFilters) { + newParams[key] = userParams.value[key]; + } + userParams.value = {}; + userParams.value = { ...newParams }; // Actualizar los params con los removibles + await arrayData.applyFilter({ params: userParams.value }); - if (!$props.showAll) { - store.data = []; + if (!$props.showAll) { + store.data = []; + } + emit('clear'); + emit('update:modelValue', userParams.value); + } finally { + isLoading.value = false; } - - isLoading.value = false; - emit('clear'); - emit('update:modelValue', userParams.value); } const tagsList = computed(() => { diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue index 6fb204afe..694ce294e 100644 --- a/src/components/ui/VnSearchbar.vue +++ b/src/components/ui/VnSearchbar.vue @@ -101,10 +101,6 @@ onMounted(() => { async function search() { const staticParams = Object.entries(store.userParams); - console.log('staticParams: ', staticParams); - // .filter( - // ([key, value]) => value && (props.staticParams || []).includes(key) - // ); arrayData.reset(['skip', 'page']); if (props.makeFetch) diff --git a/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue b/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue index 9eeac8355..4865a614a 100644 --- a/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue +++ b/src/pages/InvoiceOut/InvoiceOutNegativeBasesFilter.vue @@ -19,7 +19,7 @@ const props = defineProps({ <VnFilterPanel :data-key="props.dataKey" :search-button="true" - :unremovable-params="['from', 'to']" + :un-removable-params="['from', 'to']" :hidden-tags="['from', 'to']" > <template #tags="{ tag, formatFn }"> diff --git a/src/pages/Order/Card/OrderCard.vue b/src/pages/Order/Card/OrderCard.vue index ed4bea2ff..67c0f1de5 100644 --- a/src/pages/Order/Card/OrderCard.vue +++ b/src/pages/Order/Card/OrderCard.vue @@ -1,5 +1,4 @@ <script setup> -import { useI18n } from 'vue-i18n'; import { computed } from 'vue'; import { useRoute } from 'vue-router'; import VnCard from 'components/common/VnCard.vue'; @@ -17,18 +16,10 @@ const customRouteRedirectName = computed(() => { const route = config[routeName.value]; if (route) return null; return 'OrderList'; - //Jon, asi es como lo dejamos - // if (routeName.value === 'OrderCatalog') return null; - // return 'OrderList'; }); const customFilterPanel = computed(() => { const filterPanel = config[routeName.value] ?? OrderFilter; return filterPanel; - //Jon, asi es como lo dejamos - // if (routeName.value === 'OrderCatalog') return null; - // return 'OrderList'; - // if (routeName.value === 'OrderCatalog') return OrderCatalogFilter; - // return OrderFilter; }); </script> diff --git a/test/cypress/integration/worker/workerList.spec.js b/test/cypress/integration/worker/workerList.spec.js index 29df01f3b..16f5430de 100644 --- a/test/cypress/integration/worker/workerList.spec.js +++ b/test/cypress/integration/worker/workerList.spec.js @@ -5,8 +5,14 @@ describe('WorkerList', () => { cy.visit('/#/worker/list'); }); - it('should open the worker summary', () => { - cy.get('.bg-header > :nth-child(2) > .full-width > :nth-child(1) >').type( + it('should opern the worker summary', () => { + cy.get( + ':nth-child(1) > .text-right > .q-btn > .q-btn__content > .q-icon' + ).click(); + }); + + it('should go to the worker summary', () => { + cy.get('#searchbar > .q-field > .q-field__inner > .q-field__control').type( 'jessica jones{enter}' ); }); diff --git a/test/cypress/integration/worker/workerLocker.spec.js b/test/cypress/integration/worker/workerLocker.spec.js index ef2f88300..75539fcd1 100644 --- a/test/cypress/integration/worker/workerLocker.spec.js +++ b/test/cypress/integration/worker/workerLocker.spec.js @@ -2,7 +2,6 @@ describe('WorkerLocker', () => { const workerId = 1109; const lockerCode = '2F'; const input = '.q-card input'; - const firstOpt = '[role="listbox"] .q-item:nth-child(1)'; beforeEach(() => { cy.viewport(1280, 720); cy.login('productionBoss'); @@ -11,9 +10,7 @@ describe('WorkerLocker', () => { it('should allocates a locker', () => { cy.get(input).click(); - cy.get(input).type(lockerCode); - cy.get(firstOpt).click(); - cy.saveCard(); - cy.get(input).invoke('val').should('eq', lockerCode); + cy.get(input).type(`${lockerCode}{enter}`); + cy.get(input).should('have.value', lockerCode); }); }); From 1ac0a8596916c920f842516015a7baba5742f6d8 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Tue, 23 Jul 2024 15:09:42 +0200 Subject: [PATCH 06/20] updates --- src/components/ui/VnFilterPanel.vue | 4 ++-- src/pages/Order/Card/OrderCatalog.vue | 22 ++++++++++----------- src/pages/Order/Card/OrderCatalogFilter.vue | 12 +++++++++-- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index f79852a9d..2dce3228c 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -95,8 +95,8 @@ watch( ); watch( - () => arrayData.store.userParams, - (val) => setUserParams(val) + () => [store.userParams, store.userFilter], + ([userParams, userFilter]) => setUserParams({ ...userParams, filter: userFilter }) ); watch( diff --git a/src/pages/Order/Card/OrderCatalog.vue b/src/pages/Order/Card/OrderCatalog.vue index d1479e3c3..cb3e9a8eb 100644 --- a/src/pages/Order/Card/OrderCatalog.vue +++ b/src/pages/Order/Card/OrderCatalog.vue @@ -54,17 +54,17 @@ function extractValueTags(items) { <template> <!-- TODO Sobreescribir la barra de búsqueda --> - <Teleport to="#searchbar"> - <VnSearchbar - data-key="OrderCatalogList" - :user-params="catalogParams" - :static-params="['orderFk', 'orderBy']" - :redirect="false" - url="Orders/CatalogFilter" - :label="t('Search items')" - :info="t('You can search orders by reference')" - /> - </Teleport> + <!-- <Teleport to="#searchbar"> --> + <VnSearchbar + data-key="OrderCatalogList" + :user-params="catalogParams" + :static-params="['orderFk', 'orderBy']" + :redirect="false" + url="Orders/CatalogFilter" + :label="t('Search items')" + :info="t('You can search orders by reference')" + /> + <!-- </Teleport> --> <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above> <QScrollArea class="fit text-grey-8"> <OrderCatalogFilter diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index 8d96fe93a..d9447e530 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -29,7 +29,7 @@ const props = defineProps({ }); const categoryList = ref(null); const selectedCategoryFk = ref(null); -const typeList = ref(null); +const typeList = ref([]); const selectedTypeFk = ref(null); const validationsStore = useValidator(); const selectedOrder = ref(null); @@ -165,7 +165,8 @@ const onOrderFieldChange = (value, params) => { break; } }; - +const getCategory = (fk) => + (categoryList.value || []).find((category) => category?.id === fk); const _moreFields = ['ASC', 'DESC']; const _moreFieldsTypes = ['Relevancy', 'ColorAndPrice', 'Name', 'Price']; const setCategoryList = (data) => { @@ -177,6 +178,13 @@ const setCategoryList = (data) => { })); moreFields.value = useLang(_moreFields); moreFieldsOrder.value = useLang(_moreFieldsTypes); + const { categoryFk } = JSON.parse(JSON.parse(route.query.params).filter).where; + + if (!selectedCategoryFk.value) { + selectedCategoryFk.value = categoryFk; + selectedCategory.value = getCategory(categoryFk); + loadTypes(categoryFk); + } }; const getCategoryClass = (category, params) => { From e013e5571dfad469af9bbd657d229a9ee9579989 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Tue, 23 Jul 2024 20:18:53 +0200 Subject: [PATCH 07/20] perf: use ref at component start --- src/pages/Order/Card/OrderCatalogFilter.vue | 41 +++++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index d9447e530..62095bf1a 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -28,7 +28,34 @@ const props = defineProps({ }, }); const categoryList = ref(null); -const selectedCategoryFk = ref(null); +const params = JSON.parse(route?.query?.params ?? '{}'); +const filter = JSON.parse(params?.filter ?? '{}'); +const selectedCategoryFk = ref(filter?.where?.categoryFk ?? null); +// CHATGPT +/** + // Función para parsear JSON de manera segura +const parseJSON = (str, fallback) => { + try { + return JSON.parse(str); + } catch (e) { + console.error("Error parsing JSON:", e); + return fallback; + } +}; + +// Obtener los parámetros de la ruta +const params = parseJSON(route?.query?.params, {}); + +// Extraer y parsear el filtro de los parámetros +const { filter: filterStr = '{}' } = params; +const filter = parseJSON(filterStr, {}); + +// Obtener el categoryFk del filtro, si existe +const selectedCategoryFk = ref(filter?.where?.categoryFk ?? null); + +console.log(selectedCategoryFk.value); + + */ const typeList = ref([]); const selectedTypeFk = ref(null); const validationsStore = useValidator(); @@ -178,13 +205,13 @@ const setCategoryList = (data) => { })); moreFields.value = useLang(_moreFields); moreFieldsOrder.value = useLang(_moreFieldsTypes); - const { categoryFk } = JSON.parse(JSON.parse(route.query.params).filter).where; + // const { categoryFk } = JSON.parse(JSON.parse(route.query.params).filter).where; - if (!selectedCategoryFk.value) { - selectedCategoryFk.value = categoryFk; - selectedCategory.value = getCategory(categoryFk); - loadTypes(categoryFk); - } + // if (!selectedCategoryFk.value) { + // selectedCategoryFk.value = categoryFk; + // selectedCategory.value = getCategory(categoryFk); + // loadTypes(categoryFk); + // } }; const getCategoryClass = (category, params) => { From cc518d5a80d4734a2a7c750f07032796e74b5f33 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Wed, 24 Jul 2024 10:33:22 +0200 Subject: [PATCH 08/20] perf: refs #7717 right menu filter --- src/filters/getParamWhere.js | 21 +++++++++++ src/filters/index.js | 2 + src/pages/Order/Card/OrderCatalog.vue | 3 -- src/pages/Order/Card/OrderCatalogFilter.vue | 41 ++------------------- 4 files changed, 27 insertions(+), 40 deletions(-) create mode 100644 src/filters/getParamWhere.js diff --git a/src/filters/getParamWhere.js b/src/filters/getParamWhere.js new file mode 100644 index 000000000..48cd9c479 --- /dev/null +++ b/src/filters/getParamWhere.js @@ -0,0 +1,21 @@ +// parsing JSON safely +function parseJSON(str, fallback) { + try { + return JSON.parse(str ?? '{}'); + } catch (e) { + console.error('Error parsing JSON:', e); + return fallback; + } +} +export default function (route, param) { + // catch route query params + const params = parseJSON(route?.query?.params, {}); + + // extract and parse filter from params + const { filter: filterStr = '{}' } = params; + const where = parseJSON(filterStr, {})?.where; + if (where && where[param] !== undefined) { + return where[param]; + } + return null; +} diff --git a/src/filters/index.js b/src/filters/index.js index 940788ed1..5f08f19c7 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,6 +11,7 @@ import dashIfEmpty from './dashIfEmpty'; import dateRange from './dateRange'; import toHour from './toHour'; import dashOrCurrency from './dashOrCurrency'; +import getParamWhere from './getParamWhere'; export { toLowerCase, @@ -26,4 +27,5 @@ export { toPercentage, dashIfEmpty, dateRange, + getParamWhere, }; diff --git a/src/pages/Order/Card/OrderCatalog.vue b/src/pages/Order/Card/OrderCatalog.vue index cb3e9a8eb..dc7115422 100644 --- a/src/pages/Order/Card/OrderCatalog.vue +++ b/src/pages/Order/Card/OrderCatalog.vue @@ -53,8 +53,6 @@ function extractValueTags(items) { </script> <template> - <!-- TODO Sobreescribir la barra de búsqueda --> - <!-- <Teleport to="#searchbar"> --> <VnSearchbar data-key="OrderCatalogList" :user-params="catalogParams" @@ -64,7 +62,6 @@ function extractValueTags(items) { :label="t('Search items')" :info="t('You can search orders by reference')" /> - <!-- </Teleport> --> <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above> <QScrollArea class="fit text-grey-8"> <OrderCatalogFilter diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index 62095bf1a..85476b438 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -9,6 +9,7 @@ import VnSelect from 'components/common/VnSelect.vue'; import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue'; import { useValidator } from 'src/composables/useValidator'; import VnInput from 'src/components/common/VnInput.vue'; +import getParamWhere from 'src/filters/getParamWhere'; const { t } = useI18n(); @@ -28,34 +29,7 @@ const props = defineProps({ }, }); const categoryList = ref(null); -const params = JSON.parse(route?.query?.params ?? '{}'); -const filter = JSON.parse(params?.filter ?? '{}'); -const selectedCategoryFk = ref(filter?.where?.categoryFk ?? null); -// CHATGPT -/** - // Función para parsear JSON de manera segura -const parseJSON = (str, fallback) => { - try { - return JSON.parse(str); - } catch (e) { - console.error("Error parsing JSON:", e); - return fallback; - } -}; - -// Obtener los parámetros de la ruta -const params = parseJSON(route?.query?.params, {}); - -// Extraer y parsear el filtro de los parámetros -const { filter: filterStr = '{}' } = params; -const filter = parseJSON(filterStr, {}); - -// Obtener el categoryFk del filtro, si existe -const selectedCategoryFk = ref(filter?.where?.categoryFk ?? null); - -console.log(selectedCategoryFk.value); - - */ +const selectedCategoryFk = ref(getParamWhere(route, 'categoryFk')); const typeList = ref([]); const selectedTypeFk = ref(null); const validationsStore = useValidator(); @@ -98,7 +72,7 @@ const selectCategory = (params, category, search) => { search(); }; -const loadTypes = async (categoryFk) => { +const loadTypes = async (categoryFk = selectedCategoryFk.value) => { const { data } = await axios.get(`Orders/${route.params.id}/getItemTypeAvailable`, { params: { itemCategoryId: categoryFk }, }); @@ -192,8 +166,6 @@ const onOrderFieldChange = (value, params) => { break; } }; -const getCategory = (fk) => - (categoryList.value || []).find((category) => category?.id === fk); const _moreFields = ['ASC', 'DESC']; const _moreFieldsTypes = ['Relevancy', 'ColorAndPrice', 'Name', 'Price']; const setCategoryList = (data) => { @@ -205,13 +177,8 @@ const setCategoryList = (data) => { })); moreFields.value = useLang(_moreFields); moreFieldsOrder.value = useLang(_moreFieldsTypes); - // const { categoryFk } = JSON.parse(JSON.parse(route.query.params).filter).where; - // if (!selectedCategoryFk.value) { - // selectedCategoryFk.value = categoryFk; - // selectedCategory.value = getCategory(categoryFk); - // loadTypes(categoryFk); - // } + selectedCategoryFk.value && loadTypes(); }; const getCategoryClass = (category, params) => { From d588db05ac9b5e6adb97ddc01a5d98f91086f434 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Fri, 26 Jul 2024 14:09:09 +0200 Subject: [PATCH 09/20] fix: refs #7717 fix OrderList table filters' and summary table style --- src/pages/Order/Card/OrderSummary.vue | 37 ++++++++++---------------- src/pages/Order/OrderList.vue | 38 ++++++++++++++++++--------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/pages/Order/Card/OrderSummary.vue b/src/pages/Order/Card/OrderSummary.vue index cb708fb1d..09c47d4a7 100644 --- a/src/pages/Order/Card/OrderSummary.vue +++ b/src/pages/Order/Card/OrderSummary.vue @@ -180,15 +180,17 @@ const detailsColumns = ref([ <ItemDescriptorProxy :id="props.row.item?.id" /> </span> </QTd> - <QTd key="description" :props="props" class="description"> - <div class="name"> - <span>{{ props.row.item.name }}</span> - <span - v-if="props.row.item.subName" - class="subName" - > - {{ props.row.item.subName }} - </span> + <QTd key="description" :props="props"> + <div class="description"> + <div class="name"> + {{ props.row.item.name }} + <span + v-if="props.row.item.subName" + class="subName" + > + {{ props.row.item.subName }} + </span> + </div> </div> <FetchedTags :item="props.row.item" :max-length="5" /> </QTd> @@ -228,24 +230,13 @@ const detailsColumns = ref([ } .description { - display: flex; - flex-direction: column; - justify-content: center; text-align: left; - height: auto; - padding-top: 12px; - padding-bottom: 12px; + padding-top: 15px; + padding-bottom: 15px; .name { - display: flex; - align-items: center; - padding-bottom: 8px; - - & > * { - flex: 1; - } - .subName { + margin-left: 5%; text-transform: uppercase; color: var(--vn-label-color); } diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue index fa82540e6..e0261fc19 100644 --- a/src/pages/Order/OrderList.vue +++ b/src/pages/Order/OrderList.vue @@ -29,7 +29,7 @@ const columns = computed(() => [ }, { align: 'left', - name: 'clientName', + name: 'clientFk', label: t('module.customer'), isTitle: true, cardVisible: true, @@ -41,20 +41,26 @@ const columns = computed(() => [ columnField: { component: null, }, + format: (row) => row?.clientName, }, { align: 'left', - name: 'name', + name: 'salesPersonFk', label: t('module.salesPerson'), - component: 'select', - attrs: { - url: 'Workers/activeWithInheritedRole', - fields: ['id', 'name'], - where: { role: 'salesPerson' }, - }, - columnField: { - component: null, + columnFilter: { + component: 'select', + inWhere: true, + attrs: { + url: 'Workers/activeWithInheritedRole', + fields: ['id', 'name'], + where: { role: 'salesPerson' }, + useLike: false, + optionValue: 'id', + optionLabel: 'name', + optionFilter: 'firstName', + }, }, + format: (row) => row?.name, }, { align: 'left', @@ -92,22 +98,30 @@ const columns = computed(() => [ }, { align: 'left', - name: 'agencyName', + name: 'agencyModeFk', label: t('module.agency'), component: 'select', cardVisible: true, attrs: { - url: 'Agencies', + url: 'agencyModes', fields: ['id', 'name'], + find: { + value: 'agencyModeFk', + label: 'agencyName', + }, }, columnField: { component: null, }, + format: (row) => row?.agencyName, }, { align: 'left', name: 'total', label: t('module.total'), + columnFilter: { + inWhere: true, + }, format: ({ total }) => toCurrency(total), cardVisible: true, }, From 4d7fe0fd864f816e733aea6ea7c9aaa779d0225c Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Fri, 26 Jul 2024 14:56:26 +0200 Subject: [PATCH 10/20] fix: refs #7717 fix volume and lines redirect --- src/pages/Order/Card/OrderLines.vue | 13 ++++++++++- src/pages/Order/Card/OrderVolume.vue | 32 +++++++++++++++++++++------- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/pages/Order/Card/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue index f361d9898..391a4e374 100644 --- a/src/pages/Order/Card/OrderLines.vue +++ b/src/pages/Order/Card/OrderLines.vue @@ -1,8 +1,9 @@ <script setup> import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import { ref, computed } from 'vue'; +import { ref, computed, watch } from 'vue'; import { useQuasar } from 'quasar'; +import { useRouter } from 'vue-router'; import VnConfirm from 'components/ui/VnConfirm.vue'; import { toCurrency, toDate } from 'src/filters'; @@ -14,6 +15,7 @@ import VnLv from 'src/components/ui/VnLv.vue'; import FetchedTags from 'src/components/ui/FetchedTags.vue'; import { useStateStore } from 'stores/useStateStore'; +const router = useRouter(); const stateStore = useStateStore(); const route = useRoute(); const { t } = useI18n(); @@ -194,6 +196,15 @@ async function confirmOrder() { type: 'positive', }); } + +watch( + () => router.currentRoute.value.params.id, + () => { + lineFilter.value.where.orderFk = router.currentRoute.value.params.id; + + tableLinesRef.value.reload(); + } +); </script> <template> diff --git a/src/pages/Order/Card/OrderVolume.vue b/src/pages/Order/Card/OrderVolume.vue index 35d68de16..62aa08bc3 100644 --- a/src/pages/Order/Card/OrderVolume.vue +++ b/src/pages/Order/Card/OrderVolume.vue @@ -1,7 +1,9 @@ <script setup> +import axios from 'axios'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import { ref } from 'vue'; +import { ref, watch } from 'vue'; +import { useRouter } from 'vue-router'; import VnPaginate from 'components/ui/VnPaginate.vue'; import FetchData from 'components/FetchData.vue'; @@ -10,11 +12,20 @@ import CardList from 'components/ui/CardList.vue'; import FetchedTags from 'components/ui/FetchedTags.vue'; import { dashIfEmpty } from 'src/filters'; -import axios from 'axios'; +const router = useRouter(); const route = useRoute(); const { t } = useI18n(); const volumeSummary = ref(null); +const volumeRef = ref(); +const volumeFilter = ref({ + include: [ + { + relation: 'item', + }, + ], + where: { orderFk: route.params.id }, +}); const loadVolumes = async (rows) => { const { data } = await axios.get(`Orders/${route.params.id}/getVolumes`); @@ -26,6 +37,15 @@ const loadVolumes = async (rows) => { }); }); }; + +watch( + () => router.currentRoute.value.params.id, + () => { + volumeFilter.value.where.orderFk = router.currentRoute.value.params.id; + + volumeRef.value.fetch(); + } +); </script> <template> @@ -54,15 +74,11 @@ const loadVolumes = async (rows) => { </QCard> <VnPaginate data-key="OrderCatalogVolume" + ref="volumeRef" url="OrderRows" :limit="20" auto-load - :filter="{ - include: { - relation: 'item', - }, - where: { orderFk: route.params.id }, - }" + :user-filter="volumeFilter" order="itemFk" @on-fetch="(data) => loadVolumes(data)" > From 7e3bfce7320beb2bdba80d8cefbd37c71aa5c4d5 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Tue, 30 Jul 2024 13:31:12 +0200 Subject: [PATCH 11/20] fix: refs #7717 fix basic data form & minor errors --- src/pages/Order/Card/OrderForm.vue | 9 ++------- src/pages/Order/Card/OrderLines.vue | 5 ++++- src/pages/Order/Card/OrderVolume.vue | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/pages/Order/Card/OrderForm.vue b/src/pages/Order/Card/OrderForm.vue index f447950d2..91640101c 100644 --- a/src/pages/Order/Card/OrderForm.vue +++ b/src/pages/Order/Card/OrderForm.vue @@ -1,5 +1,5 @@ <script setup> -import { useRoute, useRouter } from 'vue-router'; +import { useRoute } from 'vue-router'; import { ref } from 'vue'; import { useI18n } from 'vue-i18n'; import axios from 'axios'; @@ -15,7 +15,6 @@ const route = useRoute(); const state = useState(); const ORDER_MODEL = 'order'; -const router = useRouter(); const isNew = Boolean(!route.params.id); const clientList = ref([]); const agencyList = ref([]); @@ -106,10 +105,6 @@ const onClientChange = async (clientId) => { console.error('Error al cambiar el cliente:', error); } }; - -async function onDataSaved({ id }) { - await router.push({ path: `/order/${id}/catalog` }); -} </script> <template> @@ -117,7 +112,7 @@ async function onDataSaved({ id }) { <div class="q-pa-md"> <FormModel :url="`Orders/${route.params.id}`" - @on-data-saved="onDataSaved" + :url-update="`Orders/${route.params.id}/updateBasicData`" :model="ORDER_MODEL" :mapper="orderMapper" :filter="orderFilter" diff --git a/src/pages/Order/Card/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue index 391a4e374..9165cfd67 100644 --- a/src/pages/Order/Card/OrderLines.vue +++ b/src/pages/Order/Card/OrderLines.vue @@ -106,6 +106,7 @@ const columns = computed(() => [ component: null, }, format: (row) => row?.item?.name, + columnClass: 'expand', }, { align: 'left', @@ -149,7 +150,6 @@ const columns = computed(() => [ align: 'left', name: 'amount', label: t('lines.amount'), - format: (row) => toCurrency(row.amount), }, { align: 'right', @@ -278,6 +278,9 @@ watch( </div> <FetchedTags :item="row?.item" :max-length="6" /> </template> + <template #column-amount="{ row }"> + {{ toCurrency(row.quantity * row.price) }} + </template> </VnTable> </div> <QPageSticky :offset="[20, 20]" v-if="!order?.isConfirmed" style="z-index: 2"> diff --git a/src/pages/Order/Card/OrderVolume.vue b/src/pages/Order/Card/OrderVolume.vue index 62aa08bc3..69f0a9c6b 100644 --- a/src/pages/Order/Card/OrderVolume.vue +++ b/src/pages/Order/Card/OrderVolume.vue @@ -166,7 +166,7 @@ es: total: Total boxes: Cajas item: Artículo - subName: Subname + subName: Subnombre quantity: Cantidad volume: m³ por cantidad </i18n> From 68ce5880dd7f1a82aa206ca44bbf1938fe5563e0 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Wed, 31 Jul 2024 07:35:59 +0200 Subject: [PATCH 12/20] refactor: refs #7717 deleted useless code --- src/components/common/VnCard.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue index 4b7a6ba63..8470fdff0 100644 --- a/src/components/common/VnCard.vue +++ b/src/components/common/VnCard.vue @@ -33,7 +33,7 @@ const url = computed(() => { }); const searchRightDataKey = computed(() => { if (!props.searchDataKey) return route.name; - else return props.searchDataKey; + return props.searchDataKey; }); const arrayData = useArrayData(props.dataKey, { url: url.value, From 3f76b5496a2c30c278bd1b7c06e1f16b472bd090 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Fri, 9 Aug 2024 07:46:32 +0200 Subject: [PATCH 13/20] fix: refs #7717 fix order sections --- src/composables/useArrayData.js | 2 +- src/pages/Order/Card/OrderCatalog.vue | 25 +++++++++++++++---- src/pages/Order/Card/OrderCatalogFilter.vue | 3 ++- .../Order/Card/OrderCatalogItemDialog.vue | 23 ++++++++++------- src/pages/Order/Card/OrderDescriptor.vue | 19 +++++++++----- src/pages/Order/Card/OrderForm.vue | 21 +++++++++++++--- src/pages/Order/Card/OrderLines.vue | 19 +++++++++++++- src/pages/Order/Card/OrderVolume.vue | 8 +++--- 8 files changed, 90 insertions(+), 30 deletions(-) diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index 50d620a34..651bcefb0 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -28,7 +28,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { delete params.filter; store.userParams = { ...params, ...store.userParams }; store.userFilter = { ...filter, ...store.userFilter }; - if (filter.order) store.order = filter.order; + if (filter?.order) store.order = filter.order; } }); diff --git a/src/pages/Order/Card/OrderCatalog.vue b/src/pages/Order/Card/OrderCatalog.vue index dc7115422..68bf9511f 100644 --- a/src/pages/Order/Card/OrderCatalog.vue +++ b/src/pages/Order/Card/OrderCatalog.vue @@ -1,7 +1,8 @@ <script setup> import { useStateStore } from 'stores/useStateStore'; -import { useRoute } from 'vue-router'; +import { useRoute, useRouter } from 'vue-router'; import { onMounted, onUnmounted, ref } from 'vue'; +import axios from 'axios'; import { useI18n } from 'vue-i18n'; import VnPaginate from 'components/ui/VnPaginate.vue'; import CatalogItem from 'components/ui/CatalogItem.vue'; @@ -9,10 +10,15 @@ import OrderCatalogFilter from 'pages/Order/Card/OrderCatalogFilter.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; const route = useRoute(); +const router = useRouter(); const stateStore = useStateStore(); const { t } = useI18n(); +const tags = ref([]); -onMounted(() => (stateStore.rightDrawer = true)); +onMounted(() => { + stateStore.rightDrawer = true; + checkOrderConfirmation(); +}); onUnmounted(() => (stateStore.rightDrawer = false)); const catalogParams = { @@ -20,7 +26,12 @@ const catalogParams = { orderBy: JSON.stringify({ field: 'relevancy DESC, name', way: 'ASC', isTag: false }), }; -const tags = ref([]); +async function checkOrderConfirmation() { + const response = await axios.get(`Orders/${route.params.id}`); + if (response.data.isConfirmed === 1) { + router.push(`/order/${route.params.id}/line`); + } +} function extractTags(items) { const resultTags = []; @@ -60,7 +71,7 @@ function extractValueTags(items) { :redirect="false" url="Orders/CatalogFilter" :label="t('Search items')" - :info="t('You can search orders by reference')" + :info="t('You can search items by name or id')" /> <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above> <QScrollArea class="fit text-grey-8"> @@ -78,7 +89,6 @@ function extractValueTags(items) { url="Orders/CatalogFilter" :limit="50" :user-params="catalogParams" - auto-load @on-fetch="extractTags" :update-router="false" > @@ -116,3 +126,8 @@ function extractValueTags(items) { text-align: center; } </style> + +<i18n> +es: + You can search items by name or id: Puedes buscar items por nombre o id +</i18n> diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index 85476b438..887cb6740 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -102,7 +102,8 @@ function exprBuilder(param, value) { case 'typeFk': return { [param]: value }; case 'search': - return { 'i.name': { like: `%${value}%` } }; + if (/^\d+$/.test(value)) return { 'i.id': value }; + else return { 'i.name': { like: `%${value}%` } }; } } diff --git a/src/pages/Order/Card/OrderCatalogItemDialog.vue b/src/pages/Order/Card/OrderCatalogItemDialog.vue index 047816127..3f97443ca 100644 --- a/src/pages/Order/Card/OrderCatalogItemDialog.vue +++ b/src/pages/Order/Card/OrderCatalogItemDialog.vue @@ -5,10 +5,12 @@ import { useI18n } from 'vue-i18n'; import axios from 'axios'; import { useRoute } from 'vue-router'; import useNotify from 'composables/useNotify'; +import { useArrayData } from 'composables/useArrayData'; const { t } = useI18n(); -const route = useRoute(); const { notify } = useNotify(); +const emit = defineEmits(['added']); +const route = useRoute(); const props = defineProps({ prices: { type: Array, @@ -16,9 +18,8 @@ const props = defineProps({ }, }); -const emit = defineEmits(['added']); - const fields = ref((props.prices || []).map((item) => ({ ...item, quantity: 0 }))); +const descriptorData = useArrayData('orderData'); const addToOrder = async () => { const items = (fields.value || []).filter((item) => Number(item.quantity) > 0); @@ -28,19 +29,20 @@ const addToOrder = async () => { }); notify(t('globals.dataSaved'), 'positive'); emit('added'); + descriptorData.fetch({}); }; </script> <template> - <div class="container order-catalog-item q-pb-md"> + <div class="container order-catalog-item q-pa-md"> <QForm @submit="addToOrder"> <QMarkupTable class="shadow-0"> <tbody> <tr v-for="item in fields" :key="item.warehouse"> - <td class="text-bold q-py-lg"> + <td class="text-bold q-pr-md td" style="width: 35%"> {{ item.warehouse }} </td> - <td class="text-right"> + <td class="text-right" style="width: 35%"> <span class="link" @click=" @@ -75,8 +77,11 @@ const addToOrder = async () => { </template> <style lang="scss" scoped> -.container { - max-width: 448px; - width: 100%; +// .container { +// max-width: 768px; +// width: 100%; +// } +.td { + width: 200px; } </style> diff --git a/src/pages/Order/Card/OrderDescriptor.vue b/src/pages/Order/Card/OrderDescriptor.vue index 4d84a32fc..8d2b5309e 100644 --- a/src/pages/Order/Card/OrderDescriptor.vue +++ b/src/pages/Order/Card/OrderDescriptor.vue @@ -4,13 +4,13 @@ import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; import { toCurrency, toDate } from 'src/filters'; import { useState } from 'src/composables/useState'; - import useCardDescription from 'src/composables/useCardDescription'; -import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; + import CardDescriptor from 'components/ui/CardDescriptor.vue'; import VnLv from 'src/components/ui/VnLv.vue'; -import OrderDescriptorMenu from 'pages/Order/Card/OrderDescriptorMenu.vue'; import FetchData from 'components/FetchData.vue'; +import OrderDescriptorMenu from 'pages/Order/Card/OrderDescriptorMenu.vue'; +import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; const DEFAULT_ITEMS = 0; @@ -25,6 +25,8 @@ const $props = defineProps({ const route = useRoute(); const state = useState(); const { t } = useI18n(); +const data = ref(useCardDescription()); +const getTotalRef = ref(); const entityId = computed(() => { return $props.id || route.params.id; @@ -57,11 +59,11 @@ const filter = { ], }; -const data = ref(useCardDescription()); const setData = (entity) => { if (!entity) return; + getTotalRef.value && getTotalRef.value.fetch(); data.value = useCardDescription(entity?.client?.name, entity?.id); - state.set('OrderDescriptor', entity); + state.set('orderData', entity); }; const getConfirmationValue = (isConfirmed) => { @@ -69,10 +71,15 @@ const getConfirmationValue = (isConfirmed) => { }; const total = ref(null); + +function ticketFilter(order) { + return JSON.stringify({ id: order.id }); +} </script> <template> <FetchData + ref="getTotalRef" :url="`Orders/${entityId}/getTotal`" @on-fetch="(response) => (total = response)" auto-load @@ -120,7 +127,7 @@ const total = ref(null); color="primary" :to="{ name: 'TicketList', - query: { params: JSON.stringify({ orderFk: entity.id }) }, + query: { table: ticketFilter(entity) }, }" > <QTooltip>{{ t('order.summary.orderTicketList') }}</QTooltip> diff --git a/src/pages/Order/Card/OrderForm.vue b/src/pages/Order/Card/OrderForm.vue index 91640101c..74d0a8b75 100644 --- a/src/pages/Order/Card/OrderForm.vue +++ b/src/pages/Order/Card/OrderForm.vue @@ -64,11 +64,14 @@ const fetchOrderDetails = (order) => { }; const orderMapper = (order) => { - return { + const mappedOrder = { addressId: order.addressFk, - agencyModeId: order.agencyModeFk, landed: new Date(order.landed).toISOString(), }; + if (order.agencyModeFk !== null && order.agencyModeFk !== undefined) { + mappedOrder.agencyModeId = order.agencyModeFk; + } + return mappedOrder; }; const orderFilter = { include: [ @@ -184,7 +187,19 @@ const onClientChange = async (clientId) => { option-value="agencyModeFk" option-label="agencyMode" hide-selected - :disable="!agencyList?.length" + :disable="!agencyList?.length && data.isConfirmed === 1" + clearable + emit-value + map-options + :model-value=" + !data.isConfirmed && + agencyList?.length && + agencyList.some( + (agency) => agency.agencyModeFk === data.agency_id + ) + ? data.agencyModeFk + : null + " > </VnSelect> </VnRow> diff --git a/src/pages/Order/Card/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue index 21ea3b300..d4a5c4b1d 100644 --- a/src/pages/Order/Card/OrderLines.vue +++ b/src/pages/Order/Card/OrderLines.vue @@ -61,6 +61,13 @@ const lineFilter = ref({ fields: ['id', 'name'], }, }, + { + relation: 'order', + scope: { + fields: ['id', 'isConfirmed'], + where: { id: route.params.id }, + }, + }, ], where: { orderFk: route.params.id }, }); @@ -157,8 +164,9 @@ const columns = computed(() => [ name: 'tableActions', actions: [ { - title: t('delete'), + title: t('Delete'), icon: 'delete', + show: (row) => !row.order.isConfirmed, action: (row) => confirmRemove(row), isPrimary: true, }, @@ -281,6 +289,15 @@ watch( <template #column-amount="{ row }"> {{ toCurrency(row.quantity * row.price) }} </template> + <template #column-tableActions="{ row }"> + <QIcon + v-if="row.order?.isConfirmed === 0" + name="delete" + icon="delete" + @click="confirmRemove(row)" + class="cursor-pointer" + /> + </template> </VnTable> </div> <QPageSticky :offset="[20, 20]" v-if="!order?.isConfirmed" style="z-index: 2"> diff --git a/src/pages/Order/Card/OrderVolume.vue b/src/pages/Order/Card/OrderVolume.vue index 69f0a9c6b..8622a1fa5 100644 --- a/src/pages/Order/Card/OrderVolume.vue +++ b/src/pages/Order/Card/OrderVolume.vue @@ -10,14 +10,16 @@ import FetchData from 'components/FetchData.vue'; import VnLv from 'components/ui/VnLv.vue'; import CardList from 'components/ui/CardList.vue'; import FetchedTags from 'components/ui/FetchedTags.vue'; - +import { useStateStore } from 'stores/useStateStore'; import { dashIfEmpty } from 'src/filters'; +import { onMounted } from 'vue'; const router = useRouter(); const route = useRoute(); const { t } = useI18n(); const volumeSummary = ref(null); const volumeRef = ref(); +const stateStore = useStateStore(); const volumeFilter = ref({ include: [ { @@ -46,6 +48,7 @@ watch( volumeRef.value.fetch(); } ); +onMounted(() => (stateStore.rightDrawer = false)); </script> <template> @@ -63,9 +66,6 @@ watch( {{ t('globals.noResults') }} </div> <QCard v-else class="order-volume-summary q-pa-lg"> - <p class="header text-right block"> - {{ t('summary') }} - </p> <VnLv :label="t('total')" :value="`${volumeSummary?.totalVolume} m³`" /> <VnLv :label="t('boxes')" From ee71ae9d24ccb018b7017f09016bff4985dc16c7 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Fri, 9 Aug 2024 13:07:37 +0200 Subject: [PATCH 14/20] feat(orderList): use orderFilter and fixed this --- src/pages/Order/Card/OrderFilter.vue | 232 ++++++++++----------------- src/pages/Order/OrderList.vue | 14 +- 2 files changed, 94 insertions(+), 152 deletions(-) diff --git a/src/pages/Order/Card/OrderFilter.vue b/src/pages/Order/Card/OrderFilter.vue index 347affb04..be47eed54 100644 --- a/src/pages/Order/Card/OrderFilter.vue +++ b/src/pages/Order/Card/OrderFilter.vue @@ -21,15 +21,13 @@ const salesPersonFilter = { fields: ['id', 'nickname'], }; const salesPersonList = ref(null); -const sourceFilter = { fields: ['value'] }; -const sourceList = ref(null); +const sourceList = ref([]); </script> <template> <FetchData url="AgencyModes/isActive" :filter="agencyFilter" - limit="30" sort-by="name ASC" auto-load @on-fetch="(data) => (agencyList = data)" @@ -37,7 +35,6 @@ const sourceList = ref(null); <FetchData url="Workers/search" :filter="salesPersonFilter" - limit="30" sort-by="nickname ASC" @on-fetch="(data) => (salesPersonList = data)" :params="{ departmentCodes: ['VT'] }" @@ -45,8 +42,7 @@ const sourceList = ref(null); /> <FetchData url="Orders/getSourceValues" - :filter="sourceFilter" - limit="30" + :filter="{ fields: ['value'] }" sort-by="value ASC" @on-fetch="(data) => (sourceList = data)" auto-load @@ -59,148 +55,88 @@ const sourceList = ref(null); </div> </template> <template #body="{ params }"> - <QItem> - <QItemSection> - <VnInput - is-outlined - :label="t('customerId')" - v-model="params.clientFk" - lazy-rules - > - <template #prepend> - <QIcon name="badge" size="sm"></QIcon> - </template> - </VnInput> - </QItemSection> - </QItem> - <QItem> - <QItemSection v-if="agencyList"> - <VnSelect - :label="t('agency')" - v-model="params.agencyModeFk" - :options="agencyList" - option-value="id" - option-label="name" - dense - outlined - rounded - emit-value - map-options - use-input - :input-debounce="0" - /> - </QItemSection> - <QItemSection v-else> - <QSkeleton type="QInput" class="full-width" /> - </QItemSection> - </QItem> - <QItem> - <QItemSection v-if="salesPersonList"> - <VnSelect - :label="t('salesPerson')" - v-model="params.workerFk" - :options="salesPersonList" - option-value="id" - option-label="name" - dense - outlined - rounded - emit-value - map-options - use-input - :input-debounce="0" - > - <template #option="{ itemProps, opt }"> - <QItem v-bind="itemProps"> - <QItemSection> - <QItemLabel>{{ opt.name }}</QItemLabel> - <QItemLabel caption> - {{ opt.nickname }},{{ opt.code }} - </QItemLabel> - </QItemSection> - </QItem> - </template> - </VnSelect> - </QItemSection> - <QItemSection v-else> - <QSkeleton type="QInput" class="full-width" /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <VnInputDate - v-model="params.from" - :label="t('fromLanded')" - dense - outlined - rounded - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <VnInputDate - v-model="params.to" - :label="t('toLanded')" - dense - outlined - rounded - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <VnInput - :label="t('orderId')" - v-model="params.orderFk" - lazy-rules - is-outlined - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection v-if="sourceList"> - <VnSelect - :label="t('application')" - v-model="params.sourceApp" - :options="sourceList" - option-label="value" - emit-value - map-options - use-input - dense - outlined - rounded - :input-debounce="0" - /> - </QItemSection> - <QItemSection v-else> - <QSkeleton type="QInput" class="full-width" /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <QCheckbox - v-model="params.myTeam" - :label="t('myTeam')" - toggle-indeterminate - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <QCheckbox - v-model="params.isConfirmed" - :label="t('isConfirmed')" - toggle-indeterminate - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <QCheckbox v-model="params.showEmpty" :label="t('showEmpty')" /> - </QItemSection> - </QItem> + <div class="q-px-md q-gutter-y-sm"> + <VnInput + :label="t('customerId')" + v-model="params.clientFk" + lazy-rules + dense + outlined + rounded + /> + <VnSelect + :label="t('agency')" + v-model="params.agencyModeFk" + :options="agencyList" + :input-debounce="0" + dense + outlined + rounded + /> + <VnSelect + :label="t('salesPerson')" + v-model="params.workerFk" + url="Workers/search" + :filter="{ departmentCodes: ['VT'] }" + sort-by="nickname ASC" + option-label="nickname" + dense + outlined + rounded + > + <template #option="{ itemProps, opt }"> + <QItem v-bind="itemProps"> + <QItemSection> + <QItemLabel>{{ opt.name }}</QItemLabel> + <QItemLabel caption> + {{ opt.nickname }},{{ opt.code }} + </QItemLabel> + </QItemSection> + </QItem> + </template> + </VnSelect> + <VnInputDate + v-model="params.from" + :label="t('fromLanded')" + dense + outlined + rounded + /> + <VnInputDate + v-model="params.to" + :label="t('toLanded')" + dense + outlined + rounded + /> + <VnInput + :label="t('orderId')" + v-model="params.orderFk" + lazy-rules + is-outlined + /> + <VnSelect + :label="t('application')" + v-model="params.sourceApp" + :options="sourceList" + option-label="value" + dense + outlined + rounded + :input-debounce="0" + /> + <QCheckbox + v-model="params.myTeam" + :label="t('myTeam')" + toggle-indeterminate + /> + <QCheckbox + v-model="params.isConfirmed" + :label="t('isConfirmed')" + toggle-indeterminate + /> + <QCheckbox v-model="params.showEmpty" :label="t('showEmpty')" /> + </div> </template> </VnFilterPanel> </template> diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue index e0261fc19..1622f5ffe 100644 --- a/src/pages/Order/OrderList.vue +++ b/src/pages/Order/OrderList.vue @@ -9,6 +9,8 @@ import VnTable from 'src/components/VnTable/VnTable.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnSelect from 'src/components/common/VnSelect.vue'; import OrderSearchbar from './Card/OrderSearchbar.vue'; +import RightMenu from 'src/components/common/RightMenu.vue'; +import OrderFilter from './Card/OrderFilter.vue'; const { t } = useI18n(); const { viewSummary } = useSummaryDialog(); @@ -119,9 +121,6 @@ const columns = computed(() => [ align: 'left', name: 'total', label: t('module.total'), - columnFilter: { - inWhere: true, - }, format: ({ total }) => toCurrency(total), cardVisible: true, }, @@ -147,10 +146,16 @@ async function fetchClientAddress(id, data) { </script> <template> <OrderSearchbar /> + <RightMenu> + <template #right-panel> + <OrderFilter data-key="OrderList" /> + </template> + </RightMenu> <VnTable ref="tableRef" data-key="OrderList" url="Orders/filter" + :order="['landed DESC', 'clientFk ASC', 'id DESC']" :create="{ urlCreate: 'Orders/new', title: 'Create Order', @@ -162,9 +167,10 @@ async function fetchClientAddress(id, data) { addressId: null, }, }" + :user-params="{ showEmpty: false }" + :right-search="false" :columns="columns" redirect="order" - auto-load > <template #more-create-dialog="{ data }"> <VnSelect From dc7c686508acbaedb756fac6eddf7d2a4f355b63 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Fri, 9 Aug 2024 14:19:08 +0200 Subject: [PATCH 15/20] feat(orderList): correct create order --- src/pages/Order/OrderList.vue | 85 ++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue index 1622f5ffe..9870be9b3 100644 --- a/src/pages/Order/OrderList.vue +++ b/src/pages/Order/OrderList.vue @@ -15,9 +15,9 @@ import OrderFilter from './Card/OrderFilter.vue'; const { t } = useI18n(); const { viewSummary } = useSummaryDialog(); const tableRef = ref(); -const clientList = ref([]); const agencyList = ref([]); -const selectedAddress = ref(); +const addressesList = ref([]); +const clientId = ref(); const columns = computed(() => [ { @@ -102,20 +102,19 @@ const columns = computed(() => [ align: 'left', name: 'agencyModeFk', label: t('module.agency'), - component: 'select', - cardVisible: true, - attrs: { - url: 'agencyModes', - fields: ['id', 'name'], - find: { - value: 'agencyModeFk', - label: 'agencyName', + format: (row) => row?.agencyName, + columnFilter: { + component: 'select', + attrs: { + url: 'agencyModes', + fields: ['id', 'name'], + find: { + value: 'agencyModeFk', + label: 'agencyName', + }, }, }, - columnField: { - component: null, - }, - format: (row) => row?.agencyName, + cardVisible: true, }, { align: 'left', @@ -138,10 +137,22 @@ const columns = computed(() => [ }, ]); -async function fetchClientAddress(id, data) { - const clientData = await axios.get(`Clients/${id}`); - selectedAddress.value = clientData.data.defaultAddressFk; - data.addressId = selectedAddress.value; +async function fetchClientAddress(id, formData) { + const { data } = await axios.get(`Clients/${id}`, { + params: { filter: { include: { relation: 'addresses' } } }, + }); + addressesList.value = data.addresses; + formData.addressId = data.defaultAddressFk; + fetchAgencies(formData); +} + +async function fetchAgencies({ landed, addressId }) { + if (!landed || !addressId) return (agencyList.value = []); + + const { data } = await axios.get('Agencies/landsThatDay', { + params: { addressFk: addressId, landed }, + }); + agencyList.value = data; } </script> <template> @@ -175,29 +186,41 @@ async function fetchClientAddress(id, data) { <template #more-create-dialog="{ data }"> <VnSelect url="Clients" - v-model="data.id" + :include="{ relation: 'addresses' }" + v-model="clientId" :label="t('module.customer')" - :options="clientList" - option-value="id" - option-label="name" @update:model-value="(id) => fetchClientAddress(id, data)" /> <VnSelect - url="Clients" - v-model="selectedAddress" + v-model="data.addressId" + :options="addressesList" :label="t('module.address')" - :options="selectedAddress" - option-value="defaultAddressFk" - option-label="street" + option-value="id" + option-label="nickname" + @update:model-value="() => fetchAgencies(data)" + > + <template #option="scope"> + <QItem v-bind="scope.itemProps"> + <QItemSection> + <QItemLabel> + {{ scope.opt?.nickname }}: {{ scope.opt?.street }}, + {{ scope.opt?.city }}</QItemLabel + > + </QItemSection> + </QItem> + </template> + </VnSelect> + <VnInputDate + v-model="data.landed" + :label="t('module.landed')" + @update:model-value="() => fetchAgencies(data)" /> - <VnInputDate v-model="data.landed" :label="t('module.landed')" /> <VnSelect - url="Agencies" v-model="data.agencyModeId" :label="t('module.agency')" :options="agencyList" - option-value="id" - option-label="name" + option-value="agencyModeFk" + option-label="agencyMode" /> </template> </VnTable> From 37244cdbc7a78f9b98fb9875747678b4a52fe790 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Fri, 9 Aug 2024 14:55:49 +0200 Subject: [PATCH 16/20] feat(orderBasicData): add notes --- src/i18n/locale/en.yml | 1 + src/i18n/locale/es.yml | 1 + .../Card/{OrderForm.vue => OrderBasicData.vue} | 16 +++++++++++----- src/router/modules/order.js | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) rename src/pages/Order/Card/{OrderForm.vue => OrderBasicData.vue} (95%) diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 12680d0cb..e639b9fda 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -93,6 +93,7 @@ globals: since: Since from: From to: To + notes: Notes pageTitles: logIn: Login summary: Summary diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 747a10d51..2d7358d5e 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -93,6 +93,7 @@ globals: since: Desde from: Desde to: Hasta + notes: Notas pageTitles: logIn: Inicio de sesión summary: Resumen diff --git a/src/pages/Order/Card/OrderForm.vue b/src/pages/Order/Card/OrderBasicData.vue similarity index 95% rename from src/pages/Order/Card/OrderForm.vue rename to src/pages/Order/Card/OrderBasicData.vue index 74d0a8b75..dfdb5ae48 100644 --- a/src/pages/Order/Card/OrderForm.vue +++ b/src/pages/Order/Card/OrderBasicData.vue @@ -7,6 +7,7 @@ import { useState } from 'composables/useState'; import FormModel from 'components/FormModel.vue'; import VnRow from 'components/ui/VnRow.vue'; import VnSelect from 'components/common/VnSelect.vue'; +import VnInput from 'components/common/VnInput.vue'; import VnInputDate from 'components/common/VnInputDate.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; @@ -117,7 +118,6 @@ const onClientChange = async (clientId) => { :url="`Orders/${route.params.id}`" :url-update="`Orders/${route.params.id}/updateBasicData`" :model="ORDER_MODEL" - :mapper="orderMapper" :filter="orderFilter" @on-fetch="fetchOrderDetails" auto-load @@ -178,8 +178,6 @@ const onClientChange = async (clientId) => { () => fetchAgencyList(data.landed, data.addressFk) " /> - </VnRow> - <VnRow> <VnSelect :label="t('order.form.agencyModeFk')" v-model="data.agencyModeFk" @@ -200,8 +198,16 @@ const onClientChange = async (clientId) => { ? data.agencyModeFk : null " - > - </VnSelect> + /> + </VnRow> + <VnRow> + <VnInput + :label="t('globals.notes')" + type="textarea" + v-model="data.note" + fill-input + autogrow + /> </VnRow> </template> </FormModel> diff --git a/src/router/modules/order.js b/src/router/modules/order.js index 9cac802c2..9ccdb820b 100644 --- a/src/router/modules/order.js +++ b/src/router/modules/order.js @@ -63,7 +63,7 @@ export default { title: 'basicData', icon: 'vn:settings', }, - component: () => import('src/pages/Order/Card/OrderForm.vue'), + component: () => import('src/pages/Order/Card/OrderBasicData.vue'), }, { name: 'OrderCatalog', From e11e51f432d2d80214876f6ad488880ca7d928d8 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Mon, 12 Aug 2024 09:17:51 +0200 Subject: [PATCH 17/20] fix: order description to vnTable --- src/pages/Order/Card/OrderVolume.vue | 166 +++++++++++---------------- 1 file changed, 67 insertions(+), 99 deletions(-) diff --git a/src/pages/Order/Card/OrderVolume.vue b/src/pages/Order/Card/OrderVolume.vue index 8622a1fa5..b16022c2f 100644 --- a/src/pages/Order/Card/OrderVolume.vue +++ b/src/pages/Order/Card/OrderVolume.vue @@ -2,24 +2,20 @@ import axios from 'axios'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import { ref, watch } from 'vue'; -import { useRouter } from 'vue-router'; - -import VnPaginate from 'components/ui/VnPaginate.vue'; -import FetchData from 'components/FetchData.vue'; -import VnLv from 'components/ui/VnLv.vue'; -import CardList from 'components/ui/CardList.vue'; -import FetchedTags from 'components/ui/FetchedTags.vue'; -import { useStateStore } from 'stores/useStateStore'; +import { ref } from 'vue'; import { dashIfEmpty } from 'src/filters'; -import { onMounted } from 'vue'; -const router = useRouter(); +import FetchData from 'components/FetchData.vue'; +import FetchedTags from 'components/ui/FetchedTags.vue'; +import ItemDescriptorProxy from 'pages/Item/Card/ItemDescriptorProxy.vue'; +import VnLv from 'components/ui/VnLv.vue'; +import VnTable from 'components/VnTable/VnTable.vue'; + const route = useRoute(); const { t } = useI18n(); const volumeSummary = ref(null); const volumeRef = ref(); -const stateStore = useStateStore(); +const volumes = ref([]); const volumeFilter = ref({ include: [ { @@ -29,26 +25,39 @@ const volumeFilter = ref({ where: { orderFk: route.params.id }, }); +const columns = [ + { + name: 'itemFk', + label: t('item'), + align: 'left', + }, + { + name: 'description', + label: t('globals.description'), + align: 'left', + }, + { + name: 'quantity', + label: t('quantity'), + align: 'left', + }, + { + name: 'volume', + label: t('volume'), + align: 'left', + }, +]; + const loadVolumes = async (rows) => { + if (!rows) return; const { data } = await axios.get(`Orders/${route.params.id}/getVolumes`); - (rows || []).forEach((order) => { + rows.forEach((order) => { (data.volumes || []).forEach((volume) => { - if (order.itemFk === volume.itemFk) { - order.volume = volume.volume; - } + if (order.itemFk === volume.itemFk) order.volume = volume.volume; }); }); + volumes.value = rows; }; - -watch( - () => router.currentRoute.value.params.id, - () => { - volumeFilter.value.where.orderFk = router.currentRoute.value.params.id; - - volumeRef.value.fetch(); - } -); -onMounted(() => (stateStore.rightDrawer = false)); </script> <template> @@ -57,61 +66,38 @@ onMounted(() => (stateStore.rightDrawer = false)); @on-fetch="(data) => (volumeSummary = data)" auto-load /> - <QPage class="column items-center q-pa-md"> - <div class="vn-card-list"> - <div - v-if="!volumeSummary?.totalVolume && !volumeSummary?.totalBoxes" - class="no-result" - > - {{ t('globals.noResults') }} - </div> - <QCard v-else class="order-volume-summary q-pa-lg"> - <VnLv :label="t('total')" :value="`${volumeSummary?.totalVolume} m³`" /> - <VnLv - :label="t('boxes')" - :value="`${dashIfEmpty(volumeSummary?.totalBoxes)} U`" - /> - </QCard> - <VnPaginate - data-key="OrderCatalogVolume" - ref="volumeRef" - url="OrderRows" - :limit="20" - auto-load - :user-filter="volumeFilter" - order="itemFk" - @on-fetch="(data) => loadVolumes(data)" - > - <template #body="{ rows }"> - <div class="catalog-list q-mt-xl"> - <CardList - v-for="row in rows" - :key="row.id" - :id="row.id" - :title="row?.item?.name" - class="cursor-inherit" - > - <template #list-items> - <div class="q-mb-sm"> - <FetchedTags :item="row.item" :max-length="5" /> - </div> - <VnLv :label="t('item')" :value="row.item.id" /> - <VnLv :label="t('subName')"> - <template #value> - <span class="text-uppercase"> - {{ row.item.subName }} - </span> - </template> - </VnLv> - <VnLv :label="t('quantity')" :value="row.quantity" /> - <VnLv :label="t('volume')" :value="row.volume" /> - </template> - </CardList> - </div> - </template> - </VnPaginate> - </div> - </QPage> + <QCard v-if="volumeSummary" class="order-volume-summary q-pa-lg"> + <VnLv :label="t('total')" :value="`${volumeSummary?.totalVolume} m³`" /> + <VnLv + :label="t('boxes')" + :value="`${dashIfEmpty(volumeSummary?.totalBoxes)} U`" + /> + </QCard> + <VnTable + ref="volumeRef" + data-key="OrderCatalogVolume" + url="OrderRows" + :columns="columns" + auto-load + :user-filter="volumeFilter" + order="itemFk" + @on-fetch="(data) => loadVolumes(data)" + :right-search="false" + :column-search="false" + > + <template #column-itemFk="{ row }"> + <span class="link"> + {{ row.itemFk }} + <ItemDescriptorProxy :id="row.itemFk" /> + </span> + </template> + <template #column-description="{ row }"> + <FetchedTags :item="row.item" :max-length="5" /> + </template> + <template #column-volume="{ rowIndex }"> + {{ volumes?.[rowIndex]?.volume }} + </template> + </VnTable> </template> <style lang="scss"> @@ -136,29 +122,12 @@ onMounted(() => (stateStore.rightDrawer = false)); } } </style> -<style lang="scss" scoped> -.header { - color: $primary; - font-weight: bold; - margin-bottom: 25px; - font-size: 20px; - display: inline-block; -} - -.no-result { - font-size: 24px; - font-weight: bold; - color: var(--vn-label-color); - text-align: center; -} -</style> <i18n> en: summary: Summary total: Total boxes: Boxes item: Item - subName: Subname quantity: Quantity volume: m³ per quantity es: @@ -166,7 +135,6 @@ es: total: Total boxes: Cajas item: Artículo - subName: Subnombre quantity: Cantidad volume: m³ por cantidad </i18n> From 190579e7fd8661f4883576753d38b1c91daa5af9 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Mon, 12 Aug 2024 10:22:52 +0200 Subject: [PATCH 18/20] fix: orderCatalogFilter order --- src/pages/Order/Card/OrderCatalogFilter.vue | 122 ++++++++------------ 1 file changed, 45 insertions(+), 77 deletions(-) diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index 887cb6740..e9987d363 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -32,14 +32,22 @@ const categoryList = ref(null); const selectedCategoryFk = ref(getParamWhere(route, 'categoryFk')); const typeList = ref([]); const selectedTypeFk = ref(null); -const validationsStore = useValidator(); -const selectedOrder = ref(null); -const selectedOrderField = ref(null); -const moreFields = ref([]); -const moreFieldsOrder = ref([]); const selectedTag = ref(null); const tagValues = ref([{}]); const tagOptions = ref([]); +const vnFilterPanelRef = ref(); +const orderByList = ref([ + { id: 'relevancy DESC, name', name: t('params.relevancy'), priority: 999 }, + { id: 'showOrder, price', name: t('params.colorAndPrice'), priority: 999 }, + { id: 'name', name: t('params.name'), priority: 999 }, + { id: 'price', name: t('params.price'), priority: 999 }, +]); +const orderWayList = ref([ + { id: 'ASC', name: t('params.ASC') }, + { id: 'DESC', name: t('params.DESC') }, +]); +const orderBySelected = ref('relevancy DESC, name'); +const orderWaySelected = ref('ASC'); const createValue = (val, done) => { if (val.length > 2) { @@ -140,35 +148,6 @@ const removeTagChip = (selection, params, search) => { search(); }; -const onOrderChange = (value, params) => { - const tagObj = JSON.parse(params.orderBy); - tagObj.way = value.name; - params.orderBy = JSON.stringify(tagObj); -}; - -const onOrderFieldChange = (value, params) => { - const tagObj = JSON.parse(params.orderBy); - switch (value) { - case 'Relevancy': - tagObj.name = value + ' DESC, name'; - params.orderBy = JSON.stringify(tagObj); - break; - case 'ColorAndPrice': - tagObj.name = 'showOrder, price'; - params.orderBy = JSON.stringify(tagObj); - break; - case 'Name': - tagObj.name = 'name'; - params.orderBy = JSON.stringify(tagObj); - break; - case 'Price': - tagObj.name = 'price'; - params.orderBy = JSON.stringify(tagObj); - break; - } -}; -const _moreFields = ['ASC', 'DESC']; -const _moreFieldsTypes = ['Relevancy', 'ColorAndPrice', 'Name', 'Price']; const setCategoryList = (data) => { categoryList.value = (data || []) .filter((category) => category.display) @@ -176,8 +155,6 @@ const setCategoryList = (data) => { ...category, icon: `vn:${(category.icon || '').split('-')[1]}`, })); - moreFields.value = useLang(_moreFields); - moreFieldsOrder.value = useLang(_moreFieldsTypes); selectedCategoryFk.value && loadTypes(); }; @@ -188,24 +165,19 @@ const getCategoryClass = (category, params) => { } }; -const useLang = (values) => { - const { models } = validationsStore; - const properties = models.Item?.properties || {}; - return values.map((name) => { - let prop = properties[name]; - const label = t(`params.${name}`); - return { - name, - label, - type: prop ? prop.type : null, - }; - }); -}; +function addOrder(value, field, params) { + let { orderBy } = params; + orderBy = JSON.parse(orderBy); + orderBy[field] = value; + params.orderBy = JSON.stringify(orderBy); + vnFilterPanelRef.value.search(); +} </script> <template> <FetchData url="ItemCategories" limit="30" auto-load @on-fetch="setCategoryList" /> <VnFilterPanel + ref="vnFilterPanelRef" :data-key="props.dataKey" :hidden-tags="['orderFk', 'orderBy']" :un-removable-params="['orderFk', 'orderBy']" @@ -298,33 +270,29 @@ const useLang = (values) => { </QItemSection> </QItem> <QSeparator /> - <QItem class="q-my-md"> - <QItemSection> - <VnSelect - :label="t('Order')" - v-model="selectedOrder" - :options="moreFields" - option-label="label" - option-value="way" - dense - outlined - rounded - @update:model-value="(value) => onOrderChange(value, params)" - /> - </QItemSection> - </QItem> <QItem class="q-mb-md"> <QItemSection> <VnSelect :label="t('Order by')" - v-model="selectedOrderField" - :options="moreFieldsOrder" - option-label="label" - option-value="name" + v-model="orderBySelected" + :options="orderByList" dense outlined rounded - @update:model-value="(value) => onOrderFieldChange(value, params)" + @update:model-value="(value) => addOrder(value, 'field', params)" + /> + </QItemSection> + </QItem> + <QItem class="q-my-md"> + <QItemSection> + <VnSelect + :label="t('Order')" + v-model="orderWaySelected" + :options="orderWayList" + dense + outlined + rounded + @update:model-value="(value) => addOrder(value, 'way', params)" /> </QItemSection> </QItem> @@ -490,10 +458,10 @@ en: order: Order ASC: Ascendant DESC: Descendant - Relevancy: Relevancy - ColorAndPrice: Color and price - Name: Name - Price: Price + relevancy: Relevancy + colorAndPrice: Color and price + name: Name + price: Price es: params: type: Tipo @@ -503,10 +471,10 @@ es: order: Orden ASC: Ascendiente DESC: Descendiente - Relevancy: Relevancia - ColorAndPrice: Color y precio - Name: Nombre - Price: Precio + relevancy: Relevancia + colorAndPrice: Color y precio + name: Nombre + price: Precio Order: Orden Order by: Ordenar por Plant: Planta From 3222a7a42cc40effd9291964e0ebf6ddc08f2fdd Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Mon, 12 Aug 2024 11:51:21 +0200 Subject: [PATCH 19/20] fix(orderLines): reload when delete and redirect when confirm --- src/pages/Order/Card/OrderDescriptor.vue | 1 - src/pages/Order/Card/OrderLines.vue | 136 ++++++++++++----------- 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/src/pages/Order/Card/OrderDescriptor.vue b/src/pages/Order/Card/OrderDescriptor.vue index 8d2b5309e..a035971b0 100644 --- a/src/pages/Order/Card/OrderDescriptor.vue +++ b/src/pages/Order/Card/OrderDescriptor.vue @@ -82,7 +82,6 @@ function ticketFilter(order) { ref="getTotalRef" :url="`Orders/${entityId}/getTotal`" @on-fetch="(response) => (total = response)" - auto-load /> <CardDescriptor ref="descriptor" diff --git a/src/pages/Order/Card/OrderLines.vue b/src/pages/Order/Card/OrderLines.vue index d4a5c4b1d..dab4a959c 100644 --- a/src/pages/Order/Card/OrderLines.vue +++ b/src/pages/Order/Card/OrderLines.vue @@ -1,25 +1,26 @@ <script setup> -import { useRoute } from 'vue-router'; +import { useRoute, useRouter } from 'vue-router'; import { useI18n } from 'vue-i18n'; import { ref, computed, watch } from 'vue'; import { useQuasar } from 'quasar'; -import { useRouter } from 'vue-router'; +import axios from 'axios'; +import { useStateStore } from 'stores/useStateStore'; +import { useArrayData } from 'composables/useArrayData'; +import { toCurrency, toDate } from 'src/filters'; import VnConfirm from 'components/ui/VnConfirm.vue'; -import { toCurrency, toDate } from 'src/filters'; -import axios from 'axios'; import VnTable from 'src/components/VnTable/VnTable.vue'; import FetchData from 'src/components/FetchData.vue'; import VnImg from 'src/components/ui/VnImg.vue'; import VnLv from 'src/components/ui/VnLv.vue'; import FetchedTags from 'src/components/ui/FetchedTags.vue'; -import { useStateStore } from 'stores/useStateStore'; const router = useRouter(); const stateStore = useStateStore(); const route = useRoute(); const { t } = useI18n(); const quasar = useQuasar(); +const descriptorData = useArrayData('orderData'); const componentKey = ref(0); const tableLinesRef = ref(); const order = ref(); @@ -27,6 +28,8 @@ const orderSummary = ref({ total: null, vat: null, }); +const getTotalRef = ref(); +const getVATRef = ref(); const lineFilter = ref({ include: [ @@ -195,6 +198,9 @@ async function remove(item) { type: 'positive', }); tableLinesRef.value.reload(); + descriptorData.fetch({}); + getTotalRef.value.fetch(); + getVATRef.value.fetch(); } async function confirmOrder() { @@ -203,6 +209,12 @@ async function confirmOrder() { message: t('globals.confirm'), type: 'positive', }); + router.push({ + name: 'TicketList', + query: { + table: JSON.stringify({ clientFk: descriptorData.store.data.clientFk }), + }, + }); } watch( @@ -223,90 +235,80 @@ watch( auto-load /> <FetchData + ref="getTotalRef" :key="componentKey" :url="`Orders/${route.params.id}/getTotal`" @on-fetch="(data) => (orderSummary.total = data)" auto-load /> <FetchData + ref="getVATRef" :key="componentKey" :url="`Orders/${route.params.id}/getVAT`" @on-fetch="(data) => (orderSummary.vat = data)" auto-load /> <QDrawer side="right" :width="270" v-model="stateStore.rightDrawer"> - <QCard class="order-lines-summary q-pa-lg"> + <QCard + class="order-lines-summary q-pa-lg" + v-if="orderSummary.vat && orderSummary.total" + > <p class="header text-right block"> {{ t('summary') }} </p> <VnLv - v-if="orderSummary.vat && orderSummary.total" :label="t('subtotal') + ': '" :value="toCurrency(orderSummary.total - orderSummary.vat)" /> - <VnLv - v-if="orderSummary.vat" - :label="t('VAT') + ': '" - :value="toCurrency(orderSummary?.vat)" - /> - <VnLv - v-if="orderSummary.total" - :label="t('total') + ': '" - :value="toCurrency(orderSummary?.total)" - /> + <VnLv :label="t('VAT') + ': '" :value="toCurrency(orderSummary?.vat)" /> + <VnLv :label="t('total') + ': '" :value="toCurrency(orderSummary?.total)" /> </QCard> </QDrawer> - <QPage :key="componentKey" class="column items-center"> - <div class="order-list full-width"> - <div v-if="!orderSummary.total" class="no-result"> - {{ t('globals.noResults') }} - </div> - <VnTable - ref="tableLinesRef" - data-key="OrderLines" - url="OrderRows" - :columns="columns" - :right-search="false" - :use-model="true" - auto-load - :user-filter="lineFilter" - > - <template #column-image="{ row }"> - <div class="image-wrapper"> - <VnImg :id="parseInt(row?.item?.image)" class="rounded" /> - </div> - </template> - <template #column-itemFk="{ row }"> - <div class="row column full-width justify-between items-start"> - {{ row?.item?.name }} - <div v-if="row?.item?.subName" class="subName"> - {{ row?.item?.subName.toUpperCase() }} - </div> - </div> - <FetchedTags :item="row?.item" :max-length="6" /> - </template> - <template #column-amount="{ row }"> - {{ toCurrency(row.quantity * row.price) }} - </template> - <template #column-tableActions="{ row }"> - <QIcon - v-if="row.order?.isConfirmed === 0" - name="delete" - icon="delete" - @click="confirmRemove(row)" - class="cursor-pointer" - /> - </template> - </VnTable> - </div> - <QPageSticky :offset="[20, 20]" v-if="!order?.isConfirmed" style="z-index: 2"> - <QBtn fab icon="check" color="primary" @click="confirmOrder()" /> - <QTooltip> - {{ t('confirm') }} - </QTooltip> - </QPageSticky> - </QPage> + <VnTable + ref="tableLinesRef" + data-key="OrderLines" + url="OrderRows" + :columns="columns" + :right-search="false" + :use-model="true" + auto-load + :user-filter="lineFilter" + > + <template #column-image="{ row }"> + <div class="image-wrapper"> + <VnImg :id="parseInt(row?.item?.image)" class="rounded" /> + </div> + </template> + + <template #column-itemFk="{ row }"> + <div class="row column full-width justify-between items-start"> + {{ row?.item?.name }} + <div v-if="row?.item?.subName" class="subName"> + {{ row?.item?.subName.toUpperCase() }} + </div> + </div> + <FetchedTags :item="row?.item" :max-length="6" /> + </template> + <template #column-amount="{ row }"> + {{ toCurrency(row.quantity * row.price) }} + </template> + <template #column-tableActions="{ row }"> + <QIcon + v-if="row.order?.isConfirmed === 0" + name="delete" + icon="delete" + @click="confirmRemove(row)" + class="cursor-pointer" + /> + </template> + </VnTable> + <QPageSticky :offset="[20, 20]" v-if="!order?.isConfirmed" style="z-index: 2"> + <QBtn fab icon="check" color="primary" @click="confirmOrder()" /> + <QTooltip> + {{ t('confirm') }} + </QTooltip> + </QPageSticky> </template> <style lang="scss" scoped> From f3d7590edfc191c4e60b26aecd0d1c8c6c8c9bc6 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Mon, 19 Aug 2024 10:49:04 +0200 Subject: [PATCH 20/20] refactor: refs #7717 delete useless function and import --- src/pages/Order/Card/OrderBasicData.vue | 10 ---------- src/pages/Order/Card/OrderCatalogFilter.vue | 1 - 2 files changed, 11 deletions(-) diff --git a/src/pages/Order/Card/OrderBasicData.vue b/src/pages/Order/Card/OrderBasicData.vue index dfdb5ae48..4bc9e2e43 100644 --- a/src/pages/Order/Card/OrderBasicData.vue +++ b/src/pages/Order/Card/OrderBasicData.vue @@ -64,16 +64,6 @@ const fetchOrderDetails = (order) => { fetchAgencyList(order?.landed, order?.addressFk); }; -const orderMapper = (order) => { - const mappedOrder = { - addressId: order.addressFk, - landed: new Date(order.landed).toISOString(), - }; - if (order.agencyModeFk !== null && order.agencyModeFk !== undefined) { - mappedOrder.agencyModeId = order.agencyModeFk; - } - return mappedOrder; -}; const orderFilter = { include: [ { relation: 'agencyMode', scope: { fields: ['name'] } }, diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue index e9987d363..850abb755 100644 --- a/src/pages/Order/Card/OrderCatalogFilter.vue +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -7,7 +7,6 @@ import FetchData from 'components/FetchData.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnSelect from 'components/common/VnSelect.vue'; import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue'; -import { useValidator } from 'src/composables/useValidator'; import VnInput from 'src/components/common/VnInput.vue'; import getParamWhere from 'src/filters/getParamWhere';