From 8a3b5751574ac2f8748cbaf2ac3ce0db9171e7ed Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Fri, 24 May 2024 00:28:18 +0200 Subject: [PATCH 01/69] fix: refs #6346 fix list and create --- src/pages/Wagon/Type/WagonTypeCreate.vue | 102 ++++++++++------------- src/pages/Wagon/Type/WagonTypeList.vue | 7 ++ 2 files changed, 51 insertions(+), 58 deletions(-) diff --git a/src/pages/Wagon/Type/WagonTypeCreate.vue b/src/pages/Wagon/Type/WagonTypeCreate.vue index bc9c1a40c..640ca75c6 100644 --- a/src/pages/Wagon/Type/WagonTypeCreate.vue +++ b/src/pages/Wagon/Type/WagonTypeCreate.vue @@ -4,6 +4,7 @@ import { useRoute, useRouter } from 'vue-router'; import { useQuasar } from 'quasar'; import VnInput from 'src/components/common/VnInput.vue'; +import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import { useI18n } from 'vue-i18n'; import axios from 'axios'; @@ -12,8 +13,8 @@ onMounted(() => fetch()); onUpdated(() => fetch()); const { t } = useI18n(); +const { notify } = useQuasar(); const route = useRoute(); -const quasar = useQuasar(); const router = useRouter(); const $props = defineProps({ id: { @@ -29,29 +30,19 @@ const divisible = ref(false); const name = ref(''); const colorPickerActive = ref(false); let originalData = { trays: [] }; -let wagonConfig; +let maxTrays, maxWagonHeight, minHeightBetweenTrays; let wagonTypeColors; let currentTrayColorPicked; async function fetch() { try { - await axios.get('WagonConfigs').then(async (res) => { - if (res.data) { - wagonConfig = res.data[0]; - } - }); + ({ + data: [{ maxTrays, maxWagonHeight, minHeightBetweenTrays }], + } = await axios.get('WagonConfigs')); await axios.get(`WagonTypeColors`).then(async (res) => { - if (res.data) { - wagonTypeColors = res.data; - if (!entityId.value) - wagon.value.push({ - id: 0, - position: 0, - color: { ...wagonTypeColors[0] }, - action: 'add', - }); - else { + if ((wagonTypeColors = res.data)) { + if (entityId.value) { await axios .get(`WagonTypeTrays`, { params: { filter: { where: { typeFk: entityId.value } } }, @@ -76,18 +67,23 @@ async function fetch() { }); } }); - } + } else + wagon.value.push({ + id: 0, + position: 0, + color: { ...wagonTypeColors[0] }, + action: 'add', + }); } }); - if (entityId.value) { + if (entityId.value) await axios.get(`WagonTypes/${entityId.value}`).then((res) => { if (res.data) { originalData.name = name.value = res.data.name; originalData.divisible = divisible.value = res.data.divisible; } }); - } } catch (e) { // } @@ -98,27 +94,24 @@ function addTray() { wagon.value.find((tray) => { return tray.position == null; }) - ) { - quasar.notify({ + ) + return notify({ message: t('wagon.warnings.uncompleteTrays'), type: 'warning', }); - return; - } - if (wagon.value.length < wagonConfig.maxTrays) { + if (wagon.value.length < maxTrays) wagon.value.unshift({ id: wagon.value.length, position: null, color: { ...wagonTypeColors[0] }, action: 'delete', }); - } else { - quasar.notify({ + else + notify({ message: t('wagon.warnings.maxTrays'), type: 'warning', }); - } } function deleteTray(trayToDelete) { @@ -127,9 +120,8 @@ function deleteTray(trayToDelete) { } function reorderIds() { - for (let index = wagon.value.length - 1; index >= 0; index--) { + for (let index = wagon.value.length - 1; index >= 0; index--) wagon.value[index].id = index; - } } async function onSubmit() { @@ -153,7 +145,7 @@ async function onSubmit() { } } -function onReset() { +async function onReset() { name.value = entityId.value ? originalData.name : null; divisible.value = entityId.value ? originalData.divisible : false; wagon.value = entityId.value @@ -169,11 +161,8 @@ function onReset() { } function doAction(tray) { - if (tray.action == 'add') { - addTray(); - } else { - deleteTray(tray); - } + if (tray.action == 'add') addTray(); + else deleteTray(tray); } function showColorPicker(tray) { @@ -193,10 +182,8 @@ function updateColor(newColor) { function onPositionBlur(tray) { if (tray.position) { - if (tray.position == '' || tray.position < 0) { - tray.position = null; - return; - } + if (tray.position == '' || tray.position < 0) return (tray.position = null); + tray.position = parseInt(tray.position); wagon.value.sort((a, b) => b.position - a.position); reorderIds(); @@ -204,18 +191,18 @@ function onPositionBlur(tray) { if (exceedMaxHeight(index - 1)) continue; if ( wagon.value[index - 1].position - wagon.value[index].position >= - wagonConfig.minHeightBetweenTrays - ) { + minHeightBetweenTrays + ) continue; - } else { + else { wagon.value[index - 1].position += - wagonConfig.minHeightBetweenTrays - + minHeightBetweenTrays - (wagon.value[index - 1].position - wagon.value[index].position); - quasar.notify({ + notify({ message: t('wagon.warnings.minHeightBetweenTrays') + - wagonConfig.minHeightBetweenTrays + + minHeightBetweenTrays + ' cm', type: 'warning', }); @@ -227,20 +214,19 @@ function onPositionBlur(tray) { } function exceedMaxHeight(pos) { - if (wagon.value[pos].position > wagonConfig.maxWagonHeight) { - wagon.value.splice(pos, 1); - quasar.notify({ - message: - t('wagon.warnings.maxWagonHeight') + wagonConfig.maxWagonHeight + ' cm', - type: 'warning', - }); - return true; - } - return false; + if (wagon.value[pos].position < maxWagonHeight) return false; + + wagon.value.splice(pos, 1); + notify({ + message: t('wagon.warnings.maxWagonHeight') + maxWagonHeight + ' cm', + type: 'warning', + }); + return true; } </script> <template> + <VnSubToolbar /> <QPage class="q-pa-sm q-mx-xl"> <QForm @submit="onSubmit()" @reset="onReset()" class="q-pa-sm"> <QCard class="q-pa-md"> @@ -264,13 +250,13 @@ function exceedMaxHeight(pos) { <QTooltip :delay="2000"> {{ t('wagon.warnings.minHeightBetweenTrays') + - wagonConfig.minHeightBetweenTrays + + minHeightBetweenTrays + ' cm' }} <QSpace /> {{ t('wagon.warnings.maxWagonHeight') + - wagonConfig.maxWagonHeight + + maxWagonHeight + ' cm' }} </QTooltip> diff --git a/src/pages/Wagon/Type/WagonTypeList.vue b/src/pages/Wagon/Type/WagonTypeList.vue index 3ecca1ea3..6744dde04 100644 --- a/src/pages/Wagon/Type/WagonTypeList.vue +++ b/src/pages/Wagon/Type/WagonTypeList.vue @@ -56,6 +56,13 @@ async function remove(row) { :id="row.id" @click="navigate(row.id)" > + <template #list-items> + <QCheckbox + :label="t('Divisble')" + :model-value="row.divisible" + disable + /> + </template> <template #actions> <QBtn :label="t('components.smartCard.openCard')" From 12370b6437ea2b28410762d88fbb871f52f1f0dd Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Tue, 23 Jul 2024 13:22:54 +0200 Subject: [PATCH 02/69] feat: refs #6346 new wagon type section --- src/i18n/locale/en.yml | 1 + src/i18n/locale/es.yml | 1 + .../Customer/Defaulter/CustomerDefaulter.vue | 3 +- src/pages/Wagon/Type/WagonCreateTray.vue | 148 +++++++ src/pages/Wagon/Type/WagonTypeCreate.vue | 419 ------------------ src/pages/Wagon/Type/WagonTypeEdit.vue | 301 +++++++++++++ src/pages/Wagon/Type/WagonTypeList.vue | 88 +++- src/router/modules/wagon.js | 6 +- .../wagonType/wagonTypeCreate.spec.js | 46 +- .../wagonType/wagonTypeEdit.spec.js | 27 ++ .../pages/Wagons/WagonTypeCreate.spec.js | 271 ----------- 11 files changed, 551 insertions(+), 760 deletions(-) create mode 100644 src/pages/Wagon/Type/WagonCreateTray.vue delete mode 100644 src/pages/Wagon/Type/WagonTypeCreate.vue create mode 100644 src/pages/Wagon/Type/WagonTypeEdit.vue create mode 100644 test/cypress/integration/wagonType/wagonTypeEdit.spec.js delete mode 100644 test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 8ccdf640f..d82a5dbd1 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -919,6 +919,7 @@ wagon: typeCreate: Create type typeEdit: Edit type wagonCounter: Trolley counter + wagonTray: Tray List type: name: Name submit: Submit diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 452421343..274edf491 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -907,6 +907,7 @@ wagon: typeCreate: Crear tipo typeEdit: Editar tipo wagonCounter: Contador de carros + wagonTray: Listado bandejas type: name: Nombre submit: Guardar diff --git a/src/pages/Customer/Defaulter/CustomerDefaulter.vue b/src/pages/Customer/Defaulter/CustomerDefaulter.vue index af7ce0a26..854db2801 100644 --- a/src/pages/Customer/Defaulter/CustomerDefaulter.vue +++ b/src/pages/Customer/Defaulter/CustomerDefaulter.vue @@ -189,7 +189,7 @@ const columns = computed(() => [ { align: 'left', field: 'finished', - label: t('Has recover'), + label: t('Has recovery'), name: 'finished', }, ]); @@ -408,4 +408,5 @@ es: Credit I.: Crédito A. Credit insurance: Crédito asegurado From: Desde + Has recovery: Tiene recobro </i18n> diff --git a/src/pages/Wagon/Type/WagonCreateTray.vue b/src/pages/Wagon/Type/WagonCreateTray.vue new file mode 100644 index 000000000..19f66b0b3 --- /dev/null +++ b/src/pages/Wagon/Type/WagonCreateTray.vue @@ -0,0 +1,148 @@ +<script setup> +import { ref, watch } from 'vue'; +import VnSelect from 'src/components/common/VnSelect.vue'; +import FormPopup from 'src/components/FormPopup.vue'; +import VnRow from 'src/components/ui/VnRow.vue'; +import VnInput from 'src/components/common/VnInput.vue'; +import FetchData from 'src/components/FetchData.vue'; +import { useI18n } from 'vue-i18n'; +import { useQuasar } from 'quasar'; +import axios from 'axios'; + +const $props = defineProps({ + entityId: { + type: Number, + required: true, + }, + height: { + type: Number, + default: 0, + }, + color: { + type: Array, + default: () => [], + }, +}); +const entityId = ref($props.entityId); +const selectedTrayColor = ref(); +const trayHeight = ref(); +const wagonColors = ref([]); +const wagonColorTranslated = ref(); +const heights = ref(); +const existingTrayHeight = ref($props.height); +const { t } = useI18n(); +const { notify } = useQuasar(); + +watch(wagonColors, () => { + wagonColorTranslated.value = wagonColors.value.map((color) => { + return { ...color, name: t(`colors.${color.name}`) }; + }); +}); +const emit = defineEmits(['onSubmit']); + +async function getTrays() { + const data = await axios.get('WagonTypeTrays', undefined, { + filter: { wagonTypeFk: entityId.value }, + }); + existingTrayHeight.value = data.data.filter( + (item) => item.wagonTypeFk == entityId.value + ); + heights.value = existingTrayHeight.value.map((item) => item.height); +} + +function onSubmit() { + if (heights.value.includes(parseInt(trayHeight.value))) { + notify({ + message: t( + 'A tray with the same height already exists, try with a different height' + ), + type: 'negative', + }); + return; + } + if (trayHeight.value - heights.value[heights.value.length - 1] < 50) { + notify({ + message: t('The minimum height between trays is 50cm'), + type: 'negative', + }); + return; + } + + if (trayHeight.value > 200) { + notify({ + message: t( + 'The maximum height of the wagon is 200cm, try with a lower height' + ), + type: 'negative', + }); + return; + } + + const newTray = { + wagonTypeFk: entityId.value, + wagonTypeColorFk: selectedTrayColor.value, + height: trayHeight.value, + }; + + emit('onSubmit', newTray); +} +getTrays(); +</script> + +<template> + <FetchData + url="WagonTypeColors" + @on-fetch="(data) => (wagonColors = data)" + auto-load + /> + <FormPopup + ref="createTrayFormDialogRef" + @on-submit="onSubmit()" + :title="t('Add new tray')" + :entity-id="selectedEntityId" + > + <template #form-inputs> + <VnRow class="row q-gutter-md q-mb-md"> + <VnSelect + v-model="selectedTrayColor" + :options="wagonColorTranslated" + option-label="name" + option-value="id" + id="id" + :label="t('Select a tray color')" + > + <template #option="scope"> + <QItem v-bind="scope.itemProps" clickable> + <QItemSection> + <QItemLabel>{{ scope.opt.name }}</QItemLabel> + </QItemSection> + </QItem> + </template> + </VnSelect> + <VnInput v-model="trayHeight" :label="t('Height')" type="number" /> + </VnRow> + </template> + </FormPopup> +</template> + +<i18n> + en: + Select a tray: Select a tray + colors: + white: White + red: Red + green: Green + blue: Blue + es: + Select a tray color: Seleccione un color + Add new tray: Añadir nueva bandeja + Height: Altura + The minimum height between trays is 50cm: La altura mínima entre bandejas es de 50cm + The maximum height of the wagon is 200cm: La altura máxima del vagón es de 200cm + A tray with the same height already exists, try with a different height: Ya existe una bandeja con la misma altura, prueba con una diferente + colors: + white: Blanco + red: Rojo + green: Verde + blue: Azul +</i18n> diff --git a/src/pages/Wagon/Type/WagonTypeCreate.vue b/src/pages/Wagon/Type/WagonTypeCreate.vue deleted file mode 100644 index 640ca75c6..000000000 --- a/src/pages/Wagon/Type/WagonTypeCreate.vue +++ /dev/null @@ -1,419 +0,0 @@ -<script setup> -import { computed, ref, onMounted, onUpdated } from 'vue'; -import { useRoute, useRouter } from 'vue-router'; -import { useQuasar } from 'quasar'; - -import VnInput from 'src/components/common/VnInput.vue'; -import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; - -import { useI18n } from 'vue-i18n'; -import axios from 'axios'; - -onMounted(() => fetch()); -onUpdated(() => fetch()); - -const { t } = useI18n(); -const { notify } = useQuasar(); -const route = useRoute(); -const router = useRouter(); -const $props = defineProps({ - id: { - type: Number, - required: false, - default: null, - }, -}); -const entityId = computed(() => $props.id || route.params.id); - -const wagon = ref([]); -const divisible = ref(false); -const name = ref(''); -const colorPickerActive = ref(false); -let originalData = { trays: [] }; -let maxTrays, maxWagonHeight, minHeightBetweenTrays; -let wagonTypeColors; -let currentTrayColorPicked; - -async function fetch() { - try { - ({ - data: [{ maxTrays, maxWagonHeight, minHeightBetweenTrays }], - } = await axios.get('WagonConfigs')); - - await axios.get(`WagonTypeColors`).then(async (res) => { - if ((wagonTypeColors = res.data)) { - if (entityId.value) { - await axios - .get(`WagonTypeTrays`, { - params: { filter: { where: { typeFk: entityId.value } } }, - }) - .then(async (res) => { - if (res.data) { - for (let i = 0; i < res.data.length; i++) { - const tray = res.data[i]; - wagon.value.push({ - id: res.data.length - i - 1, - position: tray.height, - color: { - ...wagonTypeColors.find((color) => { - return color.id === tray.colorFk; - }), - }, - action: tray.height == 0 ? 'add' : 'delete', - }); - } - wagon.value.forEach((value) => { - originalData.trays.push({ ...value }); - }); - } - }); - } else - wagon.value.push({ - id: 0, - position: 0, - color: { ...wagonTypeColors[0] }, - action: 'add', - }); - } - }); - - if (entityId.value) - await axios.get(`WagonTypes/${entityId.value}`).then((res) => { - if (res.data) { - originalData.name = name.value = res.data.name; - originalData.divisible = divisible.value = res.data.divisible; - } - }); - } catch (e) { - // - } -} - -function addTray() { - if ( - wagon.value.find((tray) => { - return tray.position == null; - }) - ) - return notify({ - message: t('wagon.warnings.uncompleteTrays'), - type: 'warning', - }); - - if (wagon.value.length < maxTrays) - wagon.value.unshift({ - id: wagon.value.length, - position: null, - color: { ...wagonTypeColors[0] }, - action: 'delete', - }); - else - notify({ - message: t('wagon.warnings.maxTrays'), - type: 'warning', - }); -} - -function deleteTray(trayToDelete) { - wagon.value = wagon.value.filter((tray) => tray.id !== trayToDelete.id); - reorderIds(); -} - -function reorderIds() { - for (let index = wagon.value.length - 1; index >= 0; index--) - wagon.value[index].id = index; -} - -async function onSubmit() { - try { - const path = entityId.value - ? 'WagonTypes/editWagonType' - : 'WagonTypes/createWagonType'; - - const params = { - id: entityId.value, - name: name.value, - divisible: divisible.value, - trays: wagon.value, - }; - - await axios.patch(path, params).then((res) => { - if (res.status == 204) router.push({ path: `/wagon/type/list` }); - }); - } catch (error) { - // - } -} - -async function onReset() { - name.value = entityId.value ? originalData.name : null; - divisible.value = entityId.value ? originalData.divisible : false; - wagon.value = entityId.value - ? [...originalData.trays] - : [ - { - id: 0, - position: 0, - color: { ...wagonTypeColors[0] }, - action: 'add', - }, - ]; -} - -function doAction(tray) { - if (tray.action == 'add') addTray(); - else deleteTray(tray); -} - -function showColorPicker(tray) { - colorPickerActive.value = true; - currentTrayColorPicked = wagon.value.findIndex((val) => { - return val.id === tray.id; - }); -} - -function updateColor(newColor) { - wagon.value[currentTrayColorPicked].color = { - ...wagonTypeColors.find((color) => { - return color.rgb === newColor; - }), - }; -} - -function onPositionBlur(tray) { - if (tray.position) { - if (tray.position == '' || tray.position < 0) return (tray.position = null); - - tray.position = parseInt(tray.position); - wagon.value.sort((a, b) => b.position - a.position); - reorderIds(); - for (let index = wagon.value.length - 1; index > 0; index--) { - if (exceedMaxHeight(index - 1)) continue; - if ( - wagon.value[index - 1].position - wagon.value[index].position >= - minHeightBetweenTrays - ) - continue; - else { - wagon.value[index - 1].position += - minHeightBetweenTrays - - (wagon.value[index - 1].position - wagon.value[index].position); - - notify({ - message: - t('wagon.warnings.minHeightBetweenTrays') + - minHeightBetweenTrays + - ' cm', - type: 'warning', - }); - - exceedMaxHeight(index - 1); - } - } - } -} - -function exceedMaxHeight(pos) { - if (wagon.value[pos].position < maxWagonHeight) return false; - - wagon.value.splice(pos, 1); - notify({ - message: t('wagon.warnings.maxWagonHeight') + maxWagonHeight + ' cm', - type: 'warning', - }); - return true; -} -</script> - -<template> - <VnSubToolbar /> - <QPage class="q-pa-sm q-mx-xl"> - <QForm @submit="onSubmit()" @reset="onReset()" class="q-pa-sm"> - <QCard class="q-pa-md"> - <VnInput - filled - v-model="name" - :label="t('wagon.type.name')" - :rules="[(val) => !!val || t('wagon.warnings.nameNotEmpty')]" - /> - <QCheckbox class="q-mb-sm" v-model="divisible" label="Divisible" /> - <div class="wagon-tray q-mx-lg" v-for="tray in wagon" :key="tray.id"> - <div class="position"> - <QInput - autofocus - filled - type="number" - :class="{ isVisible: tray.action == 'add' }" - v-model="tray.position" - @blur="onPositionBlur(tray)" - > - <QTooltip :delay="2000"> - {{ - t('wagon.warnings.minHeightBetweenTrays') + - minHeightBetweenTrays + - ' cm' - }} - <QSpace /> - {{ - t('wagon.warnings.maxWagonHeight') + - maxWagonHeight + - ' cm' - }} - </QTooltip> - </QInput> - </div> - <div class="shelving"> - <div class="shelving-half"> - <div class="shelving-up"></div> - <div - class="shelving-down" - :style="{ backgroundColor: tray.color.rgb }" - @click="showColorPicker(tray)" - ></div> - </div> - <div - class="shelving-divisible" - :class="{ isVisible: !divisible }" - ></div> - <div class="shelving-half"> - <div class="shelving-up"></div> - <div - class="shelving-down" - :style="{ backgroundColor: tray.color.rgb }" - @click="showColorPicker(tray)" - ></div> - </div> - </div> - <div class="action-button"> - <QBtn - flat - round - color="primary" - :icon="tray.action" - @click="doAction(tray)" - /> - </div> - </div> - <div class="q-mb-sm wheels"> - <QIcon color="grey-6" name="trip_origin" size="xl" /> - <QIcon color="grey-6" name="trip_origin" size="xl" /> - </div> - <QDialog - v-model="colorPickerActive" - position="right" - :no-backdrop-dismiss="false" - > - <QCard> - <QCardSection> - <div class="text-h6">{{ t('wagon.type.trayColor') }}</div> - </QCardSection> - <QCardSection class="row items-center no-wrap"> - <QColor - flat - v-model="wagon[currentTrayColorPicked].color.rgb" - no-header - no-footer - default-view="palette" - :palette=" - wagonTypeColors.map((color) => { - return color.rgb; - }) - " - @change="updateColor($event)" - /> - <QBtn flat round icon="close" v-close-popup /> - </QCardSection> - </QCard> - </QDialog> - </QCard> - <div class="q-mt-md"> - <QBtn :label="t('wagon.type.submit')" type="submit" color="primary" /> - <QBtn - :label="t('wagon.type.reset')" - type="reset" - color="primary" - flat - class="q-ml-sm" - /> - </div> - </QForm> - </QPage> -</template> - -<style lang="scss" scoped> -.q-page { - display: flex; - justify-content: center; - align-items: flex-start; -} - -.q-form { - width: 70%; -} - -.q-dialog { - .q-card { - width: 100%; - } -} - -.wheels { - margin-left: 5%; - display: flex; - justify-content: space-around; -} - -.wagon-tray { - display: flex; - height: 6rem; - - .position { - width: 20%; - border-right: 1rem solid gray; - display: flex; - align-items: flex-end; - justify-content: flex-end; - padding-right: 1rem; - } - - .shelving { - display: flex; - width: 75%; - - .shelving-half { - width: 50%; - height: 100%; - - .shelving-up { - height: 80%; - width: 100%; - } - - .shelving-down { - height: 20%; - width: 100%; - } - } - - .shelving-divisible { - width: 1%; - height: 100%; - border-left: 0.5rem dashed grey; - border-right: 0.5rem dashed grey; - } - } - - .action-button { - width: 10%; - border-left: 1rem solid gray; - display: flex; - align-items: flex-end; - justify-content: flex-start; - padding-left: 1rem; - } - - .isVisible { - display: none; - } -} -</style> diff --git a/src/pages/Wagon/Type/WagonTypeEdit.vue b/src/pages/Wagon/Type/WagonTypeEdit.vue new file mode 100644 index 000000000..25ba05714 --- /dev/null +++ b/src/pages/Wagon/Type/WagonTypeEdit.vue @@ -0,0 +1,301 @@ +<script setup> +import { computed, ref, watch } from 'vue'; +import { useRoute } from 'vue-router'; +import { useQuasar } from 'quasar'; +import VnInput from 'src/components/common/VnInput.vue'; +import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; +import FormModel from 'src/components/FormModel.vue'; +import { useI18n } from 'vue-i18n'; +import axios from 'axios'; +import VnPaginate from 'components/ui/VnPaginate.vue'; +import WagonCreateTray from './WagonCreateTray.vue'; + +const { t } = useI18n(); +const { notify } = useQuasar(); +const route = useRoute(); +const entityId = computed(() => route.params.id); +const wagonTrays = ref([]); +const createTrayFormDialogRef = ref(); +const selectedEntityId = ref(); + +async function loadTrays() { + try { + const res = await axios.get('WagonTypeTrays'); + const filteredTrays = res.data.filter( + (tray) => tray.wagonTypeFk === entityId.value + ); + wagonTrays.value = filteredTrays; + return; + } catch (err) { + console.error('Error loading trays:', err); + } +} + +async function addTray(newTray) { + try { + const res = await axios.post(`WagonTypeTrays`, newTray); + wagonTrays.value.push(res.data); + notify({ + message: t(`Tray added successfully`), + type: 'positive', + }); + } catch (err) { + console.log('err: ', err); + } +} + +async function deleteTray(trayToDelete) { + try { + await axios.delete(`WagonTypeTrays/${trayToDelete.id}`); + const index = wagonTrays.value.findIndex((tray) => tray.id === trayToDelete.id); + if (index !== -1) { + wagonTrays.value.splice(index, 1); + } + notify({ + message: t('Tray deleted successfully'), + type: 'positive', + }); + } catch (err) { + console.log('err: ', err); + } +} + +const filter = { + where: { wagonTypeFk: entityId.value }, + include: { + relation: 'color', + scope: { + fields: ['rgb'], + }, + }, +}; + +const formFilter = { where: { wagonTypeFk: entityId.value } }; + +const showCreateTrayForm = (id) => { + selectedEntityId.value = id; + createTrayFormDialogRef.value.show(); +}; + +watch( + () => wagonTrays.value, + async (newVal, oldVal) => { + if (newVal.length !== oldVal.length) { + await loadTrays(); + } + }, + { deep: true } +); +</script> + +<template> + <VnSubToolbar /> + <QPage class="q-pa-sm q-mx-xl"> + <FormModel + :url="`WagonTypes/ ${entityId}`" + :url-update="`WagonTypes/ ${entityId}`" + :filter="formFilter" + model="WagonType" + auto-load + > + <template #form="{ data }"> + <QCard class="q-pa-md"> + <VnInput + filled + v-model="data.name" + :label="t('wagon.type.name')" + :rules="[(val) => !!val || t('wagon.warnings.nameNotEmpty')]" + /> + <QCheckbox + class="q-mb-sm" + v-model="data.divisible" + label="Divisible" + /> + + <VnPaginate + data-key="wagonTypeTray" + url="WagonTypeTrays" + order="id DESC" + :filter="filter" + auto-load + ref="vnPaginateRef" + v-bind="$attrs" + :key="wagonTrays.length" + > + <template #body="{ rows }"> + <div v-for="row in rows" :key="row.id"> + <div class="shelving"></div> + <div class="action-button"> + <div class="wagon-tray q-mx-lg"> + <div class="position"> + <VnInput + borderless + type="number" + disable + class="input-tray q-mb-sm" + :label="t('Height') + ': '" + v-model="row.height" + /> + </div> + <div class="shelving"> + <div class="shelving-half"> + <div class="shelving-up"></div> + <div + class="shelving-down" + :style="{ + backgroundColor: row.color.rgb, + }" + ></div> + </div> + <div + class="shelving-divisible" + :class="{ isVisible: !data.divisible }" + ></div> + <div class="shelving-half"> + <div class="shelving-up"></div> + <div + class="shelving-down" + :style="{ + backgroundColor: row.color.rgb, + }" + ></div> + </div> + </div> + <div class="action-button"> + <QBtn + v-if="row.height === 0" + flat + round + color="primary" + :icon="'add'" + class="btn-tray" + @click="showCreateTrayForm(entityId)" + /> + <QBtn + v-else + flat + round + color="primary" + :icon="'delete'" + class="btn-tray" + @click="deleteTray(row)" + /> + </div> + </div> + </div> + </div> + </template> + </VnPaginate> + <div class="q-mb-sm wheels"> + <QIcon color="grey-6" name="trip_origin" size="xl" /> + <QIcon color="grey-6" name="trip_origin" size="xl" /> + </div> + </QCard> + <QDialog ref="createTrayFormDialogRef"> + <WagonCreateTray :entity-id="entityId" @on-submit="addTray($event)" /> + </QDialog> + </template> + </FormModel> + </QPage> +</template> + +<style lang="scss" scoped> +.q-page { + display: flex; + justify-content: center; + align-items: flex-start; +} + +.q-form { + width: 70%; +} + +.q-dialog { + .q-card { + width: 100%; + } +} + +.wheels { + margin-left: 5%; + display: flex; + justify-content: space-around; +} + +.wagon-tray { + display: flex; + height: 6rem; + + .position { + width: 26%; + border-right: 1rem solid gray; + display: flex; + align-items: flex-start; + justify-content: flex-start; + padding-right: 2rem; + padding-left: 3rem; + } + + .shelving { + display: flex; + width: 54%; + + .shelving-half { + width: 100%; + height: 100%; + + .shelving-up { + height: 80%; + width: 100%; + } + + .shelving-down { + height: 20%; + width: 100%; + } + } + + .shelving-divisible { + width: 1%; + height: 100%; + border-left: 0.5rem dashed grey; + border-right: 0.5rem dashed grey; + } + } + + .action-button { + width: 20%; + border-left: 1rem solid gray; + align-items: baseline; + padding-left: 3rem; + } + + .isVisible { + display: none; + } +} +.btn-tray { + margin-right: 100%; + margin-top: 100%; +} +.input-tray { + margin-top: 100%; + margin-left: 40%; +} +</style> + +<i18n> + en: + tray: Tray + wagonColor: Wagon color + Select a tray: Select a tray + es: + tray: Bandeja + wagonColor: Color de la bandeja + Select a tray: Seleccione una bandeja + Create new Wagon type: Crear nuevo tipo de vagón + Add new tray: Añadir nueva bandeja + Height: Altura + Tray added successfully: Bandeja añadida correctamente + Tray deleted successfully: Bandeja eliminada correctamente +</i18n> diff --git a/src/pages/Wagon/Type/WagonTypeList.vue b/src/pages/Wagon/Type/WagonTypeList.vue index 6744dde04..acd6f14be 100644 --- a/src/pages/Wagon/Type/WagonTypeList.vue +++ b/src/pages/Wagon/Type/WagonTypeList.vue @@ -1,4 +1,5 @@ <script setup> +import { ref, computed } from 'vue'; import axios from 'axios'; import { useQuasar } from 'quasar'; import VnPaginate from 'src/components/ui/VnPaginate.vue'; @@ -6,36 +7,40 @@ import { useArrayData } from 'src/composables/useArrayData'; import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; import CardList from 'components/ui/CardList.vue'; +import FormModelPopup from 'src/components/FormModelPopup.vue'; +import VnInput from 'src/components/common/VnInput.vue'; +import VnRow from 'src/components/ui/VnRow.vue'; const quasar = useQuasar(); const arrayData = useArrayData('WagonTypeList'); const store = arrayData.store; -const router = useRouter(); +const dialog = ref(); +const { push } = useRouter(); const { t } = useI18n(); +const paginate = ref(); -function navigate(id) { - router.push({ path: `/wagon/type/${id}/edit` }); +const initialData = computed(() => { + return { + name: null, + }; +}); + +function reloadData() { + initialData.value.name = null; + paginate.value.fetch(); } -function create() { - router.push({ path: `/wagon/type/create` }); +function navigate(id, name) { + push({ path: `/wagon/type/${id}/edit`, query: { name } }); } async function remove(row) { - try { - const id = row.id; - await axios - .delete(`WagonTypes/deleteWagonType`, { params: { id } }) - .then(async () => { - quasar.notify({ - message: t('wagon.type.removeItem'), - type: 'positive', - }); - store.data.splice(store.data.indexOf(row), 1); - }); - } catch (error) { - // - } + await axios.delete(`WagonTypes/${row.id}`); + quasar.notify({ + message: t('wagon.type.removeItem'), + type: 'positive', + }); + store.data.splice(store.data.indexOf(row), 1); } </script> @@ -43,8 +48,9 @@ async function remove(row) { <QPage class="column items-center q-pa-md"> <div class="vn-card-list"> <VnPaginate + ref="paginate" data-key="WagonTypeList" - url="/WagonTypes" + url="WagonTypes" order="id DESC" auto-load > @@ -54,7 +60,7 @@ async function remove(row) { :key="row.id" :title="(row.name || '').toString()" :id="row.id" - @click="navigate(row.id)" + @click="navigate(row.id, row.name)" > <template #list-items> <QCheckbox @@ -66,7 +72,7 @@ async function remove(row) { <template #actions> <QBtn :label="t('components.smartCard.openCard')" - @click.stop="navigate(row.id)" + @click.stop="navigate(row.id, row.name)" outline /> <QBtn @@ -80,8 +86,42 @@ async function remove(row) { </template> </VnPaginate> </div> - <QPageSticky position="bottom-right" :offset="[18, 18]"> - <QBtn @click="create" fab icon="add" color="primary" /> + <QPageSticky :offset="[18, 18]"> + <QBtn @click.stop="dialog.show()" color="primary" fab icon="add"> + <QDialog ref="dialog"> + <FormModelPopup + :title="t('Create new Wagon type')" + url-create="WagonTypes" + model="WagonType" + :form-initial-data="initialData" + @on-data-saved="reloadData()" + auto-load + > + <template #form-inputs="{ data }"> + <VnRow class="row q-gutter-md q-mb-md"> + <VnInput + filled + v-model="data.name" + :label="t('Name')" + :rules="[(val) => !!val || t('nameNotEmpty')]" + /> + </VnRow> + </template> + </FormModelPopup> + </QDialog> + </QBtn> + <QTooltip> + {{ t('globals.new') }} + </QTooltip> </QPageSticky> </QPage> </template> + +<i18n> +en: + nameNotEmpty: The name cannot be empty +es: + Create new Wagon type: Crear nuevo tipo de vagón + Name: Nombre + nameNotEmpty: El nombre no puede estar vacío +</i18n> diff --git a/src/router/modules/wagon.js b/src/router/modules/wagon.js index 6f9a4c819..ecdf7dff0 100644 --- a/src/router/modules/wagon.js +++ b/src/router/modules/wagon.js @@ -11,7 +11,7 @@ export default { component: RouterView, redirect: { name: 'WagonMain' }, menus: { - main: ['WagonList', 'WagonTypeList', 'WagonCounter'], + main: ['WagonList', 'WagonTypeList', 'WagonCounter', 'WagonTray'], card: [], }, children: [ @@ -81,7 +81,7 @@ export default { title: 'typeCreate', icon: 'create', }, - component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue'), + component: () => import('src/pages/Wagon/Type/WagonTypeList.vue'), }, { path: ':id/edit', @@ -90,7 +90,7 @@ export default { title: 'typeEdit', icon: 'edit', }, - component: () => import('src/pages/Wagon/Type/WagonTypeCreate.vue'), + component: () => import('src/pages/Wagon/Type/WagonTypeEdit.vue'), }, ], }, diff --git a/test/cypress/integration/wagonType/wagonTypeCreate.spec.js b/test/cypress/integration/wagonType/wagonTypeCreate.spec.js index bcf7fe841..05d61c9c5 100644 --- a/test/cypress/integration/wagonType/wagonTypeCreate.spec.js +++ b/test/cypress/integration/wagonType/wagonTypeCreate.spec.js @@ -5,50 +5,12 @@ describe('WagonTypeCreate', () => { cy.visit('/#/wagon/type/create'); }); - function chooseColor(color) { - cy.get('div.shelving-down').eq(1).click(); - cy.get('div.q-color-picker__cube').eq(color).click(); - cy.get('div.q-card__section').find('button').click(); - } - - function addTray(position) { - cy.get('div.action-button').last().find('button').click(); - cy.focused().type(position); - cy.focused().blur(); - } - - it('should create and delete a new wagon type', () => { + it('should create a new wagon type', () => { + cy.get('.q-page-sticky > div > .q-btn').click(); cy.get('input').first().type('Example for testing'); - cy.get('div.q-checkbox__bg').click(); - chooseColor(1); - - // Insert invalid position (not minimal height) - addTray(20); - cy.get('div[role="alert"]').should('exist'); - chooseColor(2); - addTray(150); - chooseColor(3); - addTray(100); - - // Insert invalid position (max height reached) - addTray(210); - cy.get('div[role="alert"]').should('exist'); - - // Save cy.get('button[type="submit"]').click(); - - // Check data has been saved successfully - cy.get(':nth-child(1) > :nth-child(1) > .justify-between > .flex > .title') - .contains('Example for testing') - .click(); - cy.get('input').first().should('have.value', 'Example for testing'); - cy.get('div.wagon-tray').should('have.length', 4); - cy.get('div.position').eq(0).find('input').should('have.value', '150'); - cy.get('div.position').eq(1).find('input').should('have.value', '100'); - cy.get('div.position').eq(2).find('input').should('have.value', '50'); - - // Delete wagon type created - cy.go('back'); + }); + it('delete a wagon type', () => { cy.get( ':nth-child(2) > :nth-child(1) > .card-list-body > .actions > .q-btn--standard' ).click(); diff --git a/test/cypress/integration/wagonType/wagonTypeEdit.spec.js b/test/cypress/integration/wagonType/wagonTypeEdit.spec.js new file mode 100644 index 000000000..6e5816e51 --- /dev/null +++ b/test/cypress/integration/wagonType/wagonTypeEdit.spec.js @@ -0,0 +1,27 @@ +describe('WagonTypeEdit', () => { + const trayColorRow = + '.q-select > .q-field__inner > .q-field__control > .q-field__control-container'; + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('developer'); + cy.visit('/#/wagon/type/2/edit'); + }); + + it('should edit the name and the divisible field of the wagon type', () => { + cy.get('.q-card'); + cy.get('input').first().type(' changed'); + cy.get('div.q-checkbox__bg').first().click(); + cy.get('.q-btn--standard').click(); + }); + + it('should create a tray', () => { + cy.get('.action-button > .q-btn > .q-btn__content > .q-icon').click(); + cy.get('input').last().type('150'); + cy.get(trayColorRow).type('{downArrow}{downArrow}{enter}'); + }); + + it('should delete a tray', () => { + cy.get('.action-button > .q-btn > .q-btn__content > .q-icon').first().click(); + cy.reload(); + }); +}); diff --git a/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js b/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js deleted file mode 100644 index 60c199b73..000000000 --- a/test/vitest/__tests__/pages/Wagons/WagonTypeCreate.spec.js +++ /dev/null @@ -1,271 +0,0 @@ -import { axios, createWrapper } from 'app/test/vitest/helper'; -import WagonTypeCreate from 'pages/Wagon/Type/WagonTypeCreate.vue'; -import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; - -describe('WagonTypeCreate', () => { - let vmCreate, vmEdit; - const entityId = 1; - - beforeAll(() => { - vmEdit = createWrapper(WagonTypeCreate, {propsData: { - id: entityId, - }}).vm; - vmCreate = createWrapper(WagonTypeCreate).vm; - vmEdit.wagonConfig = vmCreate.wagonConfig = {maxTrays: 2 ,minHeightBetweenTrays: 50, maxWagonHeight: 200 }; - vmEdit.wagonTypeColors = vmCreate.wagonTypeColors = [{id: 1, color:'white', rgb:'#000000'}]; - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - describe('addTray()', () => { - it('should throw message if there are uncomplete trays', async () => { - vi.spyOn(vmEdit.quasar, 'notify'); - vmEdit.wagon = [{ - id: 1, - position: null, - color: vmEdit.wagonTypeColors[0] - }]; - - await vmEdit.addTray(); - - expect(vmEdit.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - - it('should create a new tray if the limit has not been reached', async () => { - vmEdit.wagon = [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - }]; - - await vmEdit.addTray(); - expect(vmEdit.wagon.length).toEqual(2); - }); - - it('should throw message if there are uncomplete trays', async () => { - vi.spyOn(vmEdit.quasar, 'notify'); - vmEdit.wagon = [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - },{ - id: 2, - position: 50, - color: vmEdit.wagonTypeColors[0] - }]; - - await vmEdit.addTray(); - - expect(vmEdit.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - }); - - describe('deleteTray() reorderIds()', () => { - it('should delete a tray and reorder the ids', async () => { - const trayToDelete = { - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - }; - const trayMaintained = { - id: 2, - position: 50, - color: vmEdit.wagonTypeColors[0] - }; - vmEdit.wagon = [trayToDelete,trayMaintained]; - - await vmEdit.deleteTray(trayToDelete); - - expect(vmEdit.wagon.length).toEqual(1); - expect(vmEdit.wagon[0].id).toEqual(0); - expect(vmEdit.wagon[0].position).toEqual(50); - - }); - }); - - describe('onSubmit()', () => { - it('should make a patch to editWagonType if have id', async () => { - vi.spyOn(axios, 'patch').mockResolvedValue({ data: true }); - const wagon = { - id: entityId, - name: "Mock name", - divisible: true, - trays: [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - }] - } - vmEdit.name = wagon.name; - vmEdit.divisible = wagon.divisible; - vmEdit.wagon = wagon.trays; - - await vmEdit.onSubmit(); - - expect(axios.patch).toHaveBeenCalledWith( - `WagonTypes/editWagonType`, wagon - ); - }); - - it('should make a patch to createtWagonType if not have id', async () => { - vi.spyOn(axios, 'patch').mockResolvedValue({ data: true }); - const wagon = { - name: "Mock name", - divisible: true, - trays: [{ - id: 1, - position: 0, - color: vmCreate.wagonTypeColors[0] - }] - } - vmCreate.name = wagon.name; - vmCreate.divisible = wagon.divisible; - vmCreate.wagon = wagon.trays; - - await vmCreate.onSubmit(); - - expect(axios.patch).toHaveBeenCalledWith( - `WagonTypes/createWagonType`, wagon - ); - }); - }); - - describe('onReset()', () => { - it('should reset if have id', async () => { - vmEdit.name = 'Changed name'; - vmEdit.divisible = false; - vmEdit.wagon = []; - vmEdit.originalData = { - name: 'Original name', - divisible: true, - trays: [{ - id: 1, - position: 0, - color: vmEdit.wagonTypeColors[0] - },{ - id: 2, - position: 50, - color: vmEdit.wagonTypeColors[0] - }] - }; - - vmEdit.onReset(); - - expect(vmEdit.name).toEqual(vmEdit.originalData.name); - expect(vmEdit.divisible).toEqual(vmEdit.originalData.divisible); - expect(vmEdit.wagon).toEqual(vmEdit.originalData.trays); - }); - - it('should reset if not have id', async () => { - vmCreate.name = 'Changed name'; - vmCreate.divisible = false; - vmCreate.wagon = []; - - vmCreate.onReset(); - - expect(vmCreate.name).toEqual(null); - expect(vmCreate.divisible).toEqual(false); - expect(vmCreate.wagon.length).toEqual(1); - }); - }); - - describe('onPositionBlur()', () => { - it('should set position null if position is negative', async () => { - const negativeTray = { - id: 1, - position: -1, - color: vmCreate.wagonTypeColors[0] - }; - - vmCreate.onPositionBlur(negativeTray); - - expect(negativeTray.position).toEqual(null); - }); - - it('should set position and reorder array', async () => { - const trays = [{ - id: 0, - position: 100, - color: vmCreate.wagonTypeColors[0] - },{ - id: 1, - position: 0, - color: vmCreate.wagonTypeColors[0] - }]; - const newTray = { - id: 2, - position: 50, - color: vmCreate.wagonTypeColors[0] - }; - trays.push(newTray); - vmCreate.wagon = trays; - - vmCreate.onPositionBlur(newTray); - - expect(vmCreate.wagon[0].position).toEqual(100); - expect(vmCreate.wagon[1].position).toEqual(50); - expect(vmCreate.wagon[2].position).toEqual(0); - }); - - it('should throw message if not have min height between trays and should set new adequate positions', async () => { - vi.spyOn(vmCreate.quasar, 'notify'); - const trays = [{ - id: 0, - position: 0, - color: vmCreate.wagonTypeColors[0] - }]; - const newTray = { - id: 1, - position: 20, - color: vmCreate.wagonTypeColors[0] - }; - trays.push(newTray); - vmCreate.wagon = trays; - - vmCreate.onPositionBlur(newTray); - - expect(vmCreate.wagon[0].position).toEqual(50); - expect(vmCreate.wagon[1].position).toEqual(0); - expect(vmCreate.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - - it('should throw message if max height has been exceed', async () => { - vi.spyOn(vmCreate.quasar, 'notify'); - const trays = [{ - id: 0, - position: 0, - color: vmCreate.wagonTypeColors[0] - }]; - const newTray = { - id: 1, - position: 210, - color: vmCreate.wagonTypeColors[0] - }; - trays.push(newTray); - vmCreate.wagon = trays; - - vmCreate.onPositionBlur(newTray); - - expect(vmCreate.wagon.length).toEqual(1); - expect(vmCreate.quasar.notify).toHaveBeenCalledWith( - expect.objectContaining({ - type: 'warning', - }) - ); - }); - }); -}); From 3a0204d27bde863207db6d8a621611cd7085dc18 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Wed, 24 Jul 2024 14:58:51 +0200 Subject: [PATCH 03/69] feat: vnLocation changes --- src/components/common/VnLocation.vue | 149 +++++++++++------- .../Customer/Card/CustomerFiscalData.vue | 6 +- .../Supplier/Card/SupplierFiscalData.vue | 10 +- .../vnComponent/vnLocation.spec.js | 2 +- 4 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue index 9ed48ca15..fc19e509f 100644 --- a/src/components/common/VnLocation.vue +++ b/src/components/common/VnLocation.vue @@ -1,18 +1,23 @@ <script setup> -import { ref, toRefs, computed, watch, onMounted } from 'vue'; +import { ref, toRefs, onMounted, nextTick } from 'vue'; import CreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue'; import VnSelectDialog from 'components/common/VnSelectDialog.vue'; -import FetchData from 'components/FetchData.vue'; -const emit = defineEmits(['update:modelValue', 'update:options']); +const emit = defineEmits(['update:selected', 'update:options']); import { useI18n } from 'vue-i18n'; +import { useArrayData } from 'src/composables/useArrayData'; const { t } = useI18n(); const postcodesOptions = ref([]); -const postcodesRef = ref(null); +const postcodesOptionsOriginal = ref([]); +// const postcodesRef = ref(null); const $props = defineProps({ - modelValue: { - type: [String, Number, Object], + postalCodeKey: { + type: String, + default: 'postalCode', + }, + location: { + type: Object, default: null, }, options: { @@ -41,89 +46,115 @@ const $props = defineProps({ }, }); -const { options } = toRefs($props); -const myOptions = ref([]); -const myOptionsOriginal = ref([]); - -const value = computed({ - get() { - return $props.modelValue; - }, - set(value) { - emit( - 'update:modelValue', - postcodesOptions.value.find((p) => p.code === value) - ); - }, +const selectedId = ref(null); +const mySelect = ref(); +const modelValue = ref($props.location[$props.postalCodeKey]); +const arrayData = useArrayData('postcodes', { + url: 'Postcodes/filter', + limit: 1, }); -onMounted(() => { - locationFilter($props.modelValue); -}); +function sanitizePostcode(data) { + return data.map((postcode) => ({ + ...postcode, + original: postcode, + id: sanitizeId(postcode), + label: sanitizeLabel(postcode), + })); +} +function sanitizeId(postcode) { + return `${postcode.code ?? postcode[$props.postalCodeKey]}_${postcode.provinceFk}_${ + postcode.countryFk + }`; +} +onMounted(async () => { + await retriveOptions(); + nextTick(() => mySelect.value.showPopup()); +}); +async function retriveOptions() { + let options = []; + if (modelValue.value) { + await locationFilter(modelValue.value, () => {}); + options = arrayData.store.data; + } else { + const { data } = await arrayData.fetch({ updateRouter: false, append: true }); + options = data; + } + setOptions(options); +} +function findOptionById(postcode) { + return postcodesOptions.value.find((p) => p.id === postcode); +} function setOptions(data) { - myOptions.value = JSON.parse(JSON.stringify(data)); - myOptionsOriginal.value = JSON.parse(JSON.stringify(data)); -} -setOptions(options.value); - -watch(options, (newValue) => { - setOptions(newValue); -}); - -function showLabel(data) { - return `${data.code} - ${data.town}(${data.province}), ${data.country}`; + postcodesOptions.value = sanitizePostcode(data); + if (modelValue.value) { + const { [$props.postalCodeKey]: code } = $props.location; + selectedId.value = + findOptionById(sanitizeId({ ...$props.location, code })) ?? + sanitizePostcode([$props.location])[0]; + } + postcodesOptionsOriginal.value = JSON.parse(JSON.stringify(postcodesOptions.value)); } -function locationFilter(search = '') { - if ( - search && - (search.includes('undefined') || search.startsWith(`${$props.modelValue} - `)) - ) +async function handleInput(value) { + if (value) emit('update:selected', findOptionById(value)); + if (modelValue.value) { + modelValue.value = value; + arrayData.store.userFilter = {}; + await retriveOptions(); + mySelect.value.showPopup(); + } else postcodesOptions.value = postcodesOptionsOriginal.value; +} +function sanitizeLabel(postcode) { + return `${postcode.code ?? postcode[$props.postalCodeKey]} - ${postcode.town}(${ + postcode.province + }), ${postcode.country}`; +} + +async function locationFilter(search, update) { + if (search.length === 0) { return; + } let where = { search }; - postcodesRef.value.fetch({ filter: { where }, limit: 30 }); + arrayData.store.userFilter = { filter: { where } }; + await arrayData.fetch({ append: false, updateRouter: false }); + + update(() => { + postcodesOptions.value = sanitizePostcode(arrayData.store.data); + }); } -function handleFetch(data) { - postcodesOptions.value = data; -} function onDataSaved(newPostcode) { postcodesOptions.value.push(newPostcode); - value.value = newPostcode.code; + selectedId.value = newPostcode.code ?? newPostcode[$props.postalCodeKey]; } </script> <template> - <FetchData - ref="postcodesRef" - url="Postcodes/filter" - @on-fetch="(data) => handleFetch(data)" - /> <VnSelectDialog - v-if="postcodesRef" - :option-label="(opt) => showLabel(opt) ?? 'code'" - :option-value="(opt) => opt.code" - v-model="value" + ref="mySelect" + option-label="label" + option-value="id" + v-model="selectedId" :options="postcodesOptions" :label="t('Location')" + @update:model-value="handleInput" :placeholder="t('search_by_postalcode')" - @input-value="locationFilter" - :default-filter="false" + @filter="locationFilter" :input-debounce="300" :class="{ required: $attrs.required }" v-bind="$attrs" clearable + emit-value > <template #form> - <CreateNewPostcode - @on-data-saved="onDataSaved" - /> + <CreateNewPostcode @on-data-saved="onDataSaved" /> </template> <template #option="{ itemProps, opt }"> <QItem v-bind="itemProps"> <QItemSection v-if="opt.code"> <QItemLabel>{{ opt.code }}</QItemLabel> - <QItemLabel caption>{{ showLabel(opt) }}</QItemLabel> + <QItemLabel caption>{{ opt.label }}</QItemLabel> </QItemSection> </QItem> </template> diff --git a/src/pages/Customer/Card/CustomerFiscalData.vue b/src/pages/Customer/Card/CustomerFiscalData.vue index a7cdfafc5..d05e4fa01 100644 --- a/src/pages/Customer/Card/CustomerFiscalData.vue +++ b/src/pages/Customer/Card/CustomerFiscalData.vue @@ -95,9 +95,9 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - :options="postcodesOptions" - v-model="data.postcode" - @update:model-value="(location) => handleLocation(data, location)" + :location="data" + postal-code-key="postcode" + @update:selected="(location) => handleLocation(data, location)" > </VnLocation> </VnRow> diff --git a/src/pages/Supplier/Card/SupplierFiscalData.vue b/src/pages/Supplier/Card/SupplierFiscalData.vue index 179c6f5e6..61077d48e 100644 --- a/src/pages/Supplier/Card/SupplierFiscalData.vue +++ b/src/pages/Supplier/Card/SupplierFiscalData.vue @@ -17,11 +17,10 @@ const sageTaxTypesOptions = ref([]); const sageWithholdingsOptions = ref([]); const sageTransactionTypesOptions = ref([]); const supplierActivitiesOptions = ref([]); -const postcodesOptions = ref([]); function handleLocation(data, location) { - const { town, code, provinceFk, countryFk } = location ?? {}; - data.postCode = code; + const { town, label, provinceFk, countryFk } = location ?? {}; + data.postCode = label; data.city = town; data.provinceFk = provinceFk; data.countryFk = countryFk; @@ -131,9 +130,8 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - :options="postcodesOptions" - v-model="data.postCode" - @update:model-value="(location) => handleLocation(data, location)" + :location="data" + @update:selected="(location) => handleLocation(data, location)" > </VnLocation> </VnRow> diff --git a/test/cypress/integration/vnComponent/vnLocation.spec.js b/test/cypress/integration/vnComponent/vnLocation.spec.js index 6719d8391..c465b152c 100644 --- a/test/cypress/integration/vnComponent/vnLocation.spec.js +++ b/test/cypress/integration/vnComponent/vnLocation.spec.js @@ -17,7 +17,7 @@ describe('VnLocation', () => { cy.get(inputLocation).click(); cy.get(inputLocation).clear(); cy.get(inputLocation).type('al'); - cy.get(locationOptions).should('have.length.at.least', 3); + cy.get(locationOptions).should('have.length.at.least', 4); }); it('input filter location as "ecuador"', function () { cy.get(inputLocation).click(); From 4188569908e57aee9b938e976b670779dd7fd733 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Thu, 25 Jul 2024 10:03:20 +0200 Subject: [PATCH 04/69] feat: refs #7500 added VnImg to show files --- src/components/common/VnDmsList.vue | 33 +++++++++++++++++++++-------- src/components/ui/VnImg.vue | 11 +++++++++- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue index c42de6690..08c4e4aa4 100644 --- a/src/components/common/VnDmsList.vue +++ b/src/components/common/VnDmsList.vue @@ -5,12 +5,14 @@ import { useRoute } from 'vue-router'; import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar'; import axios from 'axios'; +import VnUserLink from '../ui/VnUserLink.vue'; +import { downloadFile } from 'src/composables/downloadFile'; +import VnImg from 'components/ui/VnImg.vue'; import VnPaginate from 'components/ui/VnPaginate.vue'; import VnDms from 'src/components/common/VnDms.vue'; import VnConfirm from 'components/ui/VnConfirm.vue'; import VnInputDate from 'components/common/VnInputDate.vue'; -import VnUserLink from '../ui/VnUserLink.vue'; -import { downloadFile } from 'src/composables/downloadFile'; +import { useSession } from 'src/composables/useSession'; const route = useRoute(); const quasar = useQuasar(); @@ -18,6 +20,7 @@ const { t } = useI18n(); const rows = ref(); const dmsRef = ref(); const formDialog = ref({}); +const token = useSession().getTokenMultimedia(); const $props = defineProps({ model: { @@ -89,6 +92,25 @@ const dmsFilter = { }; const columns = computed(() => [ + { + align: 'left', + field: 'file', + label: t('globals.file'), + name: 'file', + component: VnImg, + props: (prop) => ({ + storage: 'dms', + collection: null, + size: null, + token: prop.token, + url: + 'api/dms/' + + prop.row.file.split('.')[0] + + '/downloadFile?access_token=' + + token, + class: 'rounded', + }), + }, { align: 'left', field: 'id', @@ -141,13 +163,6 @@ const columns = computed(() => [ 'model-value': Boolean(prop.value), }), }, - { - align: 'left', - field: 'file', - label: t('globals.file'), - name: 'file', - component: 'span', - }, { align: 'left', field: 'worker', diff --git a/src/components/ui/VnImg.vue b/src/components/ui/VnImg.vue index 985c9cc53..fc54bddf5 100644 --- a/src/components/ui/VnImg.vue +++ b/src/components/ui/VnImg.vue @@ -24,6 +24,11 @@ const $props = defineProps({ type: Number, required: true, }, + url: { + type: String, + required: false, + default: null, + }, }); const show = ref(false); const token = useSession().getTokenMultimedia(); @@ -31,9 +36,13 @@ const timeStamp = ref(`timestamp=${Date.now()}`); import noImage from '/no-user.png'; import { useRole } from 'src/composables/useRole'; const url = computed(() => { + if ($props.url) return $props.url; const isEmployee = useRole().isEmployee(); + const _url = [$props.storage, $props.collection, $props.size, $props.id] + .filter((prop) => prop) + .join('/'); return isEmployee - ? `/api/${$props.storage}/${$props.collection}/${$props.size}/${$props.id}/download?access_token=${token}&${timeStamp.value}` + ? `/api/${_url}/download?access_token=${token}&${timeStamp.value}` : noImage; }); const reload = () => { From 2a4180a1c364cdd88fadbb7ef0a9a597fe8c7cc4 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Fri, 2 Aug 2024 13:20:46 +0200 Subject: [PATCH 05/69] refactor: refs #6346 deleted front error checking --- src/pages/Wagon/Type/WagonCreateTray.vue | 30 +----------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/src/pages/Wagon/Type/WagonCreateTray.vue b/src/pages/Wagon/Type/WagonCreateTray.vue index 19f66b0b3..c3f8b3847 100644 --- a/src/pages/Wagon/Type/WagonCreateTray.vue +++ b/src/pages/Wagon/Type/WagonCreateTray.vue @@ -6,7 +6,6 @@ import VnRow from 'src/components/ui/VnRow.vue'; import VnInput from 'src/components/common/VnInput.vue'; import FetchData from 'src/components/FetchData.vue'; import { useI18n } from 'vue-i18n'; -import { useQuasar } from 'quasar'; import axios from 'axios'; const $props = defineProps({ @@ -31,7 +30,6 @@ const wagonColorTranslated = ref(); const heights = ref(); const existingTrayHeight = ref($props.height); const { t } = useI18n(); -const { notify } = useQuasar(); watch(wagonColors, () => { wagonColorTranslated.value = wagonColors.value.map((color) => { @@ -51,33 +49,6 @@ async function getTrays() { } function onSubmit() { - if (heights.value.includes(parseInt(trayHeight.value))) { - notify({ - message: t( - 'A tray with the same height already exists, try with a different height' - ), - type: 'negative', - }); - return; - } - if (trayHeight.value - heights.value[heights.value.length - 1] < 50) { - notify({ - message: t('The minimum height between trays is 50cm'), - type: 'negative', - }); - return; - } - - if (trayHeight.value > 200) { - notify({ - message: t( - 'The maximum height of the wagon is 200cm, try with a lower height' - ), - type: 'negative', - }); - return; - } - const newTray = { wagonTypeFk: entityId.value, wagonTypeColorFk: selectedTrayColor.value, @@ -110,6 +81,7 @@ getTrays(); option-value="id" id="id" :label="t('Select a tray color')" + :required="true" > <template #option="scope"> <QItem v-bind="scope.itemProps" clickable> From f2be2b430010d647f2547a8a6d8a2b7604b894dd Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Mon, 5 Aug 2024 15:42:57 +0200 Subject: [PATCH 06/69] fea: stockBought add form and formDetail --- src/components/VnTable/VnTable.vue | 14 +- src/components/common/VnInputDate.vue | 2 +- src/components/common/VnInputTime.vue | 2 +- src/i18n/locale/en.yml | 1 + src/pages/Entry/EntryStockBought.vue | 142 ++++++++++++++++++ src/pages/Entry/EntryStockBoughtDetail.vue | 102 +++++++++++++ src/pages/Route/RouteList.vue | 3 +- src/router/modules/entry.js | 11 +- .../integration/entry/stockBought.spec.js | 36 +++++ 9 files changed, 302 insertions(+), 11 deletions(-) create mode 100644 src/pages/Entry/EntryStockBought.vue create mode 100644 src/pages/Entry/EntryStockBoughtDetail.vue create mode 100644 test/cypress/integration/entry/stockBought.spec.js diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 4e40c0ba6..8a20023f2 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -107,7 +107,7 @@ const orders = ref(parseOrder(routeQuery.filter?.order)); const CrudModelRef = ref({}); const showForm = ref(false); const splittedColumns = ref({ columns: [] }); -const columnsVisibilitySkiped = ref(); +const columnsVisibilitySkipped = ref(); const tableModes = [ { icon: 'view_column', @@ -133,7 +133,7 @@ onMounted(() => { ? CARD_MODE : $props.defaultMode; stateStore.rightDrawer = true; - columnsVisibilitySkiped.value = [ + columnsVisibilitySkipped.value = [ ...splittedColumns.value.columns .filter((c) => c.visible == false) .map((c) => c.name), @@ -325,11 +325,11 @@ defineExpose({ <div class="q-px-md"> <CrudModel v-bind="$attrs" - :limit="20" + :limit="$attrs.limit ?? 20" ref="CrudModelRef" @on-fetch="(...args) => emit('onFetch', ...args)" :search-url="searchUrl" - :disable-infinite-scroll="isTableMode" + :disable-infinite-scroll="$attrs['disable-infinite-scroll'] ?? isTableMode" @save-changes="reload" :has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable" :auto-load="hasParams || $attrs['auto-load']" @@ -351,9 +351,8 @@ defineExpose({ :grid="!isTableMode" table-header-class="bg-header" card-container-class="grid-three" - flat :style="isTableMode && `max-height: ${tableHeight}`" - virtual-scroll + :virtual-scroll="!isTableMode" @virtual-scroll=" (event) => event.index > rows.length - 2 && @@ -361,6 +360,7 @@ defineExpose({ " @row-click="(_, row) => rowClickFunction && rowClickFunction(row)" @update:selected="emit('update:selected', $event)" + flat > <template #top-left v-if="!$props.withoutHeader"> <slot name="top-left"></slot> @@ -370,7 +370,7 @@ defineExpose({ v-if="isTableMode" v-model="splittedColumns.columns" :table-code="tableCode ?? route.name" - :skip="columnsVisibilitySkiped" + :skip="columnsVisibilitySkipped" /> <QBtnToggle v-model="mode" diff --git a/src/components/common/VnInputDate.vue b/src/components/common/VnInputDate.vue index 6e57a8a53..76eee86fc 100644 --- a/src/components/common/VnInputDate.vue +++ b/src/components/common/VnInputDate.vue @@ -45,7 +45,7 @@ const formattedDate = computed({ if (value) { // parse input if (value.includes('/')) { - if (value.length == 6) value = value + new Date().getFullYear(); + if (value.length == 6) value = value + Date.vnNew().getFullYear(); if (value.length >= 10) { if (value.at(2) == '/') value = value.split('/').reverse().join('/'); value = date.formatDate( diff --git a/src/components/common/VnInputTime.vue b/src/components/common/VnInputTime.vue index a59f0e9e8..2c387bf0b 100644 --- a/src/components/common/VnInputTime.vue +++ b/src/components/common/VnInputTime.vue @@ -62,7 +62,7 @@ const formattedTime = computed({ function dateToTime(newDate) { return date.formatDate(new Date(newDate), dateFormat); } -const timeField = ref(); + watch( () => model.value, (val) => (formattedTime.value = val), diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 78c1fa18d..867f338e4 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -142,6 +142,7 @@ globals: dms: File management entryCreate: New entry latestBuys: Latest buys + reserves: Reserves tickets: Tickets ticketCreate: New Tickets boxing: Boxing diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue new file mode 100644 index 000000000..5277cc5e1 --- /dev/null +++ b/src/pages/Entry/EntryStockBought.vue @@ -0,0 +1,142 @@ +<script setup> +import { ref } from 'vue'; +import { useI18n } from 'vue-i18n'; +import { useState } from 'src/composables/useState'; +import { useQuasar } from 'quasar'; + +import VnTable from 'components/VnTable/VnTable.vue'; +import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; +import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; +import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue'; + +const { t } = useI18n(); +const quasar = useQuasar(); +const tableRef = ref(); +const state = useState(); +const user = state.getUser(); +const columns = [ + { + align: 'left', + label: 'Id', + name: 'id', + isTitle: true, + isId: true, + columnFilter: false, + visible: false, + }, + { + align: 'left', + name: 'workerFk', + label: t('Buyer'), + columnFilter: false, + }, + { + align: 'left', + label: t('Reserve'), + name: 'reserve', + columnFilter: false, + create: true, + component: 'number', + }, + { + align: 'left', + name: 'workerFk', + label: t('Buyer'), + component: 'select', + create: true, + visible: false, + columnFilter: false, + attrs: { + url: 'Workers/activeWithInheritedRole', + fields: ['id', 'name'], + where: { role: 'buyer' }, + optionFilter: 'firstName', + optionLabel: 'name', + optionValue: 'id', + useLike: false, + }, + }, + { + align: 'left', + label: t('Bought'), + name: 'bought', + columnFilter: false, + }, + { + align: 'left', + label: t('Date'), + name: 'dated', + component: 'date', + visible: false, + create: true, + }, + { + align: 'left', + name: 'tableActions', + actions: [ + { + title: t('More'), + icon: 'search', + isPrimary: true, + action: (row) => { + console.log('workerFk: ', row.workerFk); + quasar.dialog({ + component: EntryStockBoughtDetail, + componentProps: { + workerFk: row.workerFk, + dated: row.dated, + }, + maximized: true, + }); + }, + }, + ], + }, +]; +</script> +<template> + <VnSubToolbar /> + <VnTable + ref="tableRef" + data-key="StockBoughts" + url="StockBoughts/getStockBought" + save-url="StockBoughts/crud" + order="reserve DESC" + :is-editable="true" + :disable-option="{ card: true }" + :create="{ + urlCreate: 'StockBoughts', + title: t('Reserve some space'), + onDataSaved: () => tableRef.reload(), + formInitialData: { + workerFk: user.id, + dated: Date.now(), + }, + }" + :columns="columns" + > + <template #column-workerFk="{ row }"> + <span class="link" @click.stop> + {{ row?.worker?.user?.name }} + <WorkerDescriptorProxy :id="row?.workerFk" /> + </span> + </template> + </VnTable> +</template> +<i18n> + en: + Buyer: Buyer + Reserve: Reserve + Bought: Bought + More: More + Date: Date + This buyer has already made a reservation for this date: This buyer has already made a reservation for this date + es: + Buyer: Comprador + Reserve: Reservado + Bought: Comprado + More: Más + Date: Fecha + Reserve some space: Reservar espacio + This buyer has already made a reservation for this date: Este comprador ya ha hecho una reserva para esta fecha +</i18n> diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue new file mode 100644 index 000000000..908f5dd20 --- /dev/null +++ b/src/pages/Entry/EntryStockBoughtDetail.vue @@ -0,0 +1,102 @@ +<script setup> +import { ref } from 'vue'; +import { useI18n } from 'vue-i18n'; + +import VnTable from 'components/VnTable/VnTable.vue'; +import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue'; +import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; + +const { t } = useI18n(); +const tableRef = ref(); +const $props = defineProps({ + workerFk: { + type: Number, + required: true, + }, + dated: { + type: String, + required: true, + }, +}); +console.log('$props: ', $props.workerFk, $props.dated); +const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}`; +const columns = [ + { + align: 'left', + label: 'Entry', + name: 'entryFk', + isTitle: true, + isId: true, + columnFilter: false, + }, + { + align: 'left', + name: 'itemFk', + label: t('Item'), + columnFilter: false, + }, + { + align: 'left', + label: t('Name'), + name: 'itemName', + columnFilter: false, + create: true, + columnClass: 'expand', + }, + { + align: 'left', + name: 'volume', + label: t('Volume'), + columnFilter: false, + }, + { + align: 'left', + label: t('Packaging'), + name: 'packagingFk', + columnFilter: false, + }, + { + align: 'left', + label: 'Packing', + name: 'packing', + columnFilter: false, + }, +]; +</script> +<template> + <QDialog> + <VnTable + ref="tableRef" + data-key="StockBoughtsDetail" + :url="customUrl" + order="itemName DESC" + :columns="columns" + :right-search="false" + :disable-infinite-scroll="true" + :disable-option="{ card: true }" + :limit="0" + auto-load + > + <template #column-entryFk="{ row }"> + <span class="link" @click.stop> + {{ row?.entryFk }} + <EntryDescriptorProxy :id="row.entryFk" /> + </span> + </template> + <template #column-itemName="{ row }"> + <span class="link" @click.stop> + {{ row?.itemName }} + <ItemDescriptorProxy :id="row.itemFk" /> + </span> + </template> + </VnTable> + </QDialog> +</template> +<i18n> + es: + Buyer: Comprador + Reserve: Reservado + Bought: Comprado + More: Más + Date: Fecha +</i18n> diff --git a/src/pages/Route/RouteList.vue b/src/pages/Route/RouteList.vue index b13e8cacd..7d5dd5c68 100644 --- a/src/pages/Route/RouteList.vue +++ b/src/pages/Route/RouteList.vue @@ -139,7 +139,7 @@ const columns = computed(() => [ { align: 'center', name: 'm3', - label: 'volume', + label: t('Volume'), cardVisible: true, }, { @@ -379,4 +379,5 @@ es: Route is not served: La ruta no está servida hourStarted: Hora de inicio hourFinished: Hora de fin + Volume: Volumen </i18n> diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js index 0d38ed626..fd5490fbd 100644 --- a/src/router/modules/entry.js +++ b/src/router/modules/entry.js @@ -11,7 +11,7 @@ export default { component: RouterView, redirect: { name: 'EntryMain' }, menus: { - main: ['EntryList', 'MyEntries', 'EntryLatestBuys'], + main: ['EntryList', 'MyEntries', 'EntryLatestBuys', 'EntryStockBought'], card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'], }, children: [ @@ -57,6 +57,15 @@ export default { }, component: () => import('src/pages/Entry/EntryLatestBuys.vue'), }, + { + path: 'stock-Bought', + name: 'EntryStockBought', + meta: { + title: 'reserves', + icon: 'deployed_code_history', + }, + component: () => import('src/pages/Entry/EntryStockBought.vue'), + }, ], }, { diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js new file mode 100644 index 000000000..8e4fe225c --- /dev/null +++ b/test/cypress/integration/entry/stockBought.spec.js @@ -0,0 +1,36 @@ +describe('EntryStockBought', () => { + const reserveField = 'input[name="reserve"]'; + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit( + `/#/entry/stock-Bought?table={"filter":"{}","dated":"2000-12-31T23:00:00.000Z"}` + ); + }); + it('Should edit the reserved space', () => { + cy.get('tBody > tr').its('length').should('eq', 1); + cy.get(reserveField).type('10{enter}'); + cy.get('button[title="Save"]').click(); + cy.get('.q-notification__message').should('have.text', 'Data saved'); + }); + it('Should add a new reserved space for buyerBoss', () => { + cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click(); + cy.get('input[aria-label="Reserve"]').type('1'); + cy.get('input[aria-label="Date"]').eq(1).clear(); + cy.get('input[aria-label="Date"]').eq(1).type('01-01'); + cy.get('input[aria-label="Buyer"]').type('buyerboss{downarrow}{enter}'); + cy.get('.q-notification__message').should('have.text', 'Data created'); + cy.get('tBody > tr').its('length').should('eq', 2); + }); + it('Should check detail for the buyer', () => { + cy.get(':nth-child(1) > .sticky > .q-btn > .q-btn__content > .q-icon').click(); + cy.get('tBody > tr').eq(1).its('length').should('eq', 1); + }); + it('Should check detail for the buyerBoss and had no content', () => { + cy.get(':nth-child(2) > .sticky > .q-btn > .q-btn__content > .q-icon').click(); + cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata').should( + 'have.text', + 'warningNo data available' + ); + }); +}); From de94b3629e6470ba0f8ba9f6b3fad807c6ec01ab Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Mon, 5 Aug 2024 15:44:37 +0200 Subject: [PATCH 07/69] fix: remove console.log --- src/pages/Entry/EntryStockBought.vue | 1 - src/pages/Entry/EntryStockBoughtDetail.vue | 1 - 2 files changed, 2 deletions(-) diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index 5277cc5e1..e0063bb62 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -79,7 +79,6 @@ const columns = [ icon: 'search', isPrimary: true, action: (row) => { - console.log('workerFk: ', row.workerFk); quasar.dialog({ component: EntryStockBoughtDetail, componentProps: { diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue index 908f5dd20..f7e89c691 100644 --- a/src/pages/Entry/EntryStockBoughtDetail.vue +++ b/src/pages/Entry/EntryStockBoughtDetail.vue @@ -18,7 +18,6 @@ const $props = defineProps({ required: true, }, }); -console.log('$props: ', $props.workerFk, $props.dated); const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}`; const columns = [ { From ffd7d98e9cc25cf218b2c577d0c7ef98df7cf59b Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Tue, 13 Aug 2024 17:56:07 +0200 Subject: [PATCH 08/69] feat: travel m3 --- src/components/VnTable/VnTable.vue | 20 +++++++++++ src/pages/Entry/EntryStockBought.vue | 39 +++++++++++++++++++++- src/pages/Entry/EntryStockBoughtDetail.vue | 2 +- src/pages/Travel/Card/TravelBasicData.vue | 3 ++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 8a20023f2..dbe5d1622 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -15,6 +15,7 @@ import VnTableChip from 'components/VnTable/VnChip.vue'; import VnVisibleColumn from 'src/components/VnTable/VnVisibleColumn.vue'; import VnLv from 'components/ui/VnLv.vue'; import VnTableOrder from 'src/components/VnTable/VnOrder.vue'; +import item from 'src/router/modules/item'; const $props = defineProps({ columns: { @@ -609,6 +610,25 @@ defineExpose({ </QCard> </component> </template> + <template #bottom-row="{ cols }"> + <QTr> + <QTh + v-for="col of cols.filter((cols) => cols.visible ?? true)" + :key="col.id" + class="text-center" + > + <span v-if="col.summation"> + {{ + rows.reduce( + (sum, currentRow) => + sum + currentRow[col.name], + 0 + ) + }} + </span> + </QTh> + </QTr> + </template> </QTable> </template> </CrudModel> diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index e0063bb62..12fc96214 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -5,6 +5,10 @@ import { useState } from 'src/composables/useState'; import { useQuasar } from 'quasar'; import VnTable from 'components/VnTable/VnTable.vue'; +import VnRow from 'src/components/ui/VnRow.vue'; +import VnInput from 'src/components/common/VnInput.vue'; +import VnLv from 'src/components/ui/VnLv.vue'; +import FetchData from 'src/components/FetchData.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue'; @@ -37,6 +41,7 @@ const columns = [ columnFilter: false, create: true, component: 'number', + summation: true, }, { align: 'left', @@ -61,6 +66,7 @@ const columns = [ label: t('Bought'), name: 'bought', columnFilter: false, + summation: true, }, { align: 'left', @@ -92,6 +98,21 @@ const columns = [ ], }, ]; +function getFilter(dated = Date.vnNow()) { + console.log('dated: ', new Date(dated * 1000)); + return { + fields: ['id', 'm3'], + where: { dated }, + include: [ + { + relation: 'warehouseIn', + where: { code: 'vnh' }, + }, + ], + }; +} +const travel = ref(); +const fetchDataRef = ref(); </script> <template> <VnSubToolbar /> @@ -109,11 +130,27 @@ const columns = [ onDataSaved: () => tableRef.reload(), formInitialData: { workerFk: user.id, - dated: Date.now(), + dated: Date.vnNow(), }, }" :columns="columns" + auto-load + @on-fetch="() => fetchDataRef.fetch()" > + <template #moreFilterPanel="{ params }"> + <FetchData + ref="fetchDataRef" + url="Travels" + limit="1" + auto-load + :filter="getFilter(params?.date)" + @on-fetch="(data) => (travel = data)" + /> + <VnRow class="q-pa-md" style="align-items: center" v-if="travel?.length"> + <span>{{ t('Booked trucks: ') + travel[0]?.m3 }}</span> + <QBtn style="max-width: 20%" flat icon="edit" /> + </VnRow> + </template> <template #column-workerFk="{ row }"> <span class="link" @click.stop> {{ row?.worker?.user?.name }} diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue index f7e89c691..9212f1115 100644 --- a/src/pages/Entry/EntryStockBoughtDetail.vue +++ b/src/pages/Entry/EntryStockBoughtDetail.vue @@ -38,9 +38,9 @@ const columns = [ align: 'left', label: t('Name'), name: 'itemName', - columnFilter: false, create: true, columnClass: 'expand', + columnFilter: false, }, { align: 'left', diff --git a/src/pages/Travel/Card/TravelBasicData.vue b/src/pages/Travel/Card/TravelBasicData.vue index 8a369a0dd..a3620a6ba 100644 --- a/src/pages/Travel/Card/TravelBasicData.vue +++ b/src/pages/Travel/Card/TravelBasicData.vue @@ -70,6 +70,9 @@ const agenciesOptions = ref([]); hide-selected /> </VnRow> + <VnRow> + <VnInput v-model="data.m3" label="m3" /> + </VnRow> <VnRow> <QCheckbox :label="t('travel.basicData.delivered')" From 92130b4c9c770c6cc49e1253885f7837bcba29cf Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Wed, 14 Aug 2024 08:09:27 +0200 Subject: [PATCH 09/69] WIP: 59262019 Merge pull request '#7283 finish item card sections' (!588) from 7283-itemSectionsMigration into dev --- src/components/common/VnLocation.vue | 103 +++------------------------ 1 file changed, 9 insertions(+), 94 deletions(-) diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue index 4d429a995..8256ec5b0 100644 --- a/src/components/common/VnLocation.vue +++ b/src/components/common/VnLocation.vue @@ -1,124 +1,39 @@ <script setup> -import { ref, toRefs, computed, watch, onMounted } from 'vue'; import CreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue'; import VnSelectDialog from 'components/common/VnSelectDialog.vue'; -import FetchData from 'components/FetchData.vue'; -const emit = defineEmits(['update:modelValue', 'update:options']); import { useI18n } from 'vue-i18n'; -import { useArrayData } from 'src/composables/useArrayData'; const { t } = useI18n(); -const postcodesOptions = ref([]); -const postcodesRef = ref(null); - -const $props = defineProps({ - modelValue: { - type: [String, Number, Object], - default: null, - }, - options: { - type: Array, - default: () => [], - }, - optionLabel: { - type: String, - default: '', - }, - optionValue: { - type: String, - default: '', - }, - filterOptions: { - type: Array, - default: () => [], - }, - isClearable: { - type: Boolean, - default: true, - }, - defaultFilter: { - type: Boolean, - default: true, - }, -}); - -const { options } = toRefs($props); -const myOptions = ref([]); -const myOptionsOriginal = ref([]); - -const value = computed({ - get() { - return $props.modelValue; - }, - set(value) { - emit( - 'update:modelValue', - postcodesOptions.value.find((p) => p.code === value) - ); - }, -}); - -onMounted(() => { - locationFilter($props.modelValue); -}); - -function setOptions(data) { - myOptions.value = JSON.parse(JSON.stringify(data)); - myOptionsOriginal.value = JSON.parse(JSON.stringify(data)); -} -setOptions(options.value); - -watch(options, (newValue) => { - setOptions(newValue); -}); +const value = defineModel({ type: [String, Number, Object] }); function showLabel(data) { return `${data.code} - ${data.town}(${data.province}), ${data.country}`; } - -function locationFilter(search = '') { - if ( - search && - (search.includes('undefined') || search.startsWith(`${$props.modelValue} - `)) - ) - return; - let where = { search }; - postcodesRef.value.fetch({ filter: { where }, limit: 30 }); -} - -function handleFetch(data) { - postcodesOptions.value = data; -} -function onDataSaved(newPostcode) { - postcodesOptions.value.push(newPostcode); - value.value = newPostcode.code; -} </script> <template> <VnSelectDialog - v-if="postcodesRef" - :option-label="(opt) => showLabel(opt) ?? 'code'" - :option-value="(opt) => opt.code" v-model="value" - :options="postcodesOptions" + option-value="code" + option-filter-value="search" + :option-label="(opt) => showLabel(opt)" + url="Postcodes/filter" + :use-like="false" :label="t('Location')" - @update:model-value="handleInput" :placeholder="t('search_by_postalcode')" - @input-value="locationFilter" - :default-filter="false" :input-debounce="300" :class="{ required: $attrs.required }" v-bind="$attrs" clearable + :emit-value="false" > <template #form> - <CreateNewPostcode @on-data-saved="onDataSaved" /> + <CreateNewPostcode @on-data-saved="(newValue) => (value = newValue)" /> </template> <template #option="{ itemProps, opt }"> <QItem v-bind="itemProps"> <QItemSection v-if="opt.code"> <QItemLabel>{{ opt.code }}</QItemLabel> - <QItemLabel caption>{{ opt.label }}</QItemLabel> + <QItemLabel caption>{{ showLabel(opt) }}</QItemLabel> </QItemSection> </QItem> </template> From 55b9cd9ff44f29fb95da4958c29d18ea1ae4207d Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Wed, 14 Aug 2024 09:18:24 +0200 Subject: [PATCH 10/69] feat: handle same multiple CP --- src/components/common/VnLocation.vue | 24 ++++++++++++----- src/i18n/locale/en.yml | 1 + src/i18n/locale/es.yml | 1 + src/pages/Customer/Card/CustomerAddress.vue | 26 ++++++------------- .../Customer/Card/CustomerFiscalData.vue | 2 +- src/pages/Customer/CustomerCreate.vue | 1 - src/pages/Customer/CustomerList.vue | 1 - .../components/CustomerAddressCreate.vue | 1 - .../components/CustomerAddressEdit.vue | 7 ++++- src/pages/Supplier/Card/SupplierAddresses.vue | 8 +++++- .../Supplier/Card/SupplierAddressesCreate.vue | 12 ++++++++- .../Supplier/Card/SupplierFiscalData.vue | 24 ++++++++++++++++- src/pages/Worker/WorkerCreate.vue | 1 - src/pages/Worker/WorkerList.vue | 1 - src/router/modules/customer.js | 2 +- 15 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue index 8256ec5b0..778932be3 100644 --- a/src/components/common/VnLocation.vue +++ b/src/components/common/VnLocation.vue @@ -2,20 +2,32 @@ import CreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue'; import VnSelectDialog from 'components/common/VnSelectDialog.vue'; import { useI18n } from 'vue-i18n'; - +import { ref } from 'vue'; const { t } = useI18n(); -const value = defineModel({ type: [String, Number, Object] }); +const props = defineProps({ + location: { + type: Object, + default: null, + }, +}); +const modelValue = ref( + props.location + ? `${props.location?.postcode} - ${props.location?.city}(${props.location?.province?.name}), ${props.location?.country?.name}` + : null +); function showLabel(data) { return `${data.code} - ${data.town}(${data.province}), ${data.country}`; } </script> <template> + {{ modelValue }} <VnSelectDialog - v-model="value" - option-value="code" + v-model="modelValue" option-filter-value="search" - :option-label="(opt) => showLabel(opt)" + :option-label=" + (opt) => (typeof modelValue === 'string' ? modelValue : showLabel(opt)) + " url="Postcodes/filter" :use-like="false" :label="t('Location')" @@ -27,7 +39,7 @@ function showLabel(data) { :emit-value="false" > <template #form> - <CreateNewPostcode @on-data-saved="(newValue) => (value = newValue)" /> + <CreateNewPostcode @on-data-saved="(newValue) => (modelValue = newValue)" /> </template> <template #option="{ itemProps, opt }"> <QItem v-bind="itemProps"> diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index ee53da80c..f61dda8a4 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -95,6 +95,7 @@ globals: to: To pageTitles: logIn: Login + addressEdit: Update address summary: Summary basicData: Basic data log: Logs diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 86963f3dc..4e71a69fb 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -95,6 +95,7 @@ globals: to: Hasta pageTitles: logIn: Inicio de sesión + addressEdit: Modificar consignatario summary: Resumen basicData: Datos básicos log: Historial diff --git a/src/pages/Customer/Card/CustomerAddress.vue b/src/pages/Customer/Card/CustomerAddress.vue index 6c8279d84..a97b45a50 100644 --- a/src/pages/Customer/Card/CustomerAddress.vue +++ b/src/pages/Customer/Card/CustomerAddress.vue @@ -5,15 +5,12 @@ import { useRoute, useRouter } from 'vue-router'; import axios from 'axios'; -import FetchData from 'components/FetchData.vue'; - const { t } = useI18n(); const route = useRoute(); const router = useRouter(); const addresses = ref([]); const client = ref(null); -const provincesLocation = ref([]); const addressFilter = { fields: [ @@ -41,7 +38,13 @@ const addressFilter = { { relation: 'province', scope: { - fields: ['id', 'name'], + fields: ['id', 'name', 'countryFk'], + include: [ + { + relation: 'country', + scope: { fields: ['id', 'name'] }, + }, + ], }, }, ], @@ -83,13 +86,6 @@ const getClientData = async (id) => { } }; -const setProvince = (provinceFk) => { - const result = provincesLocation.value.filter( - (province) => province.id === provinceFk - ); - return result[0]?.name || ''; -}; - const isDefaultAddress = (address) => { return client?.value?.defaultAddressFk === address.id ? 1 : 0; }; @@ -128,12 +124,6 @@ const toCustomerAddressEdit = (addressId) => { </script> <template> - <FetchData - @on-fetch="(data) => (provincesLocation = data)" - auto-load - url="Provinces/location" - /> - <div class="full-width flex justify-center"> <QCard class="card-width q-pa-lg" v-if="addresses.length"> <QCardSection> @@ -177,7 +167,7 @@ const toCustomerAddressEdit = (addressId) => { <div>{{ item.street }}</div> <div> {{ item.postalCode }} - {{ item.city }}, - {{ setProvince(item.provinceFk) }} + {{ item.province.name }} </div> <div class="flex"> <QCheckbox diff --git a/src/pages/Customer/Card/CustomerFiscalData.vue b/src/pages/Customer/Card/CustomerFiscalData.vue index 5cc656bb3..54b8adb70 100644 --- a/src/pages/Customer/Card/CustomerFiscalData.vue +++ b/src/pages/Customer/Card/CustomerFiscalData.vue @@ -94,7 +94,7 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.postcode" + :location="data" @update:model-value="(location) => handleLocation(data, location)" /> </VnRow> diff --git a/src/pages/Customer/CustomerCreate.vue b/src/pages/Customer/CustomerCreate.vue index 041c92d17..193ed59c9 100644 --- a/src/pages/Customer/CustomerCreate.vue +++ b/src/pages/Customer/CustomerCreate.vue @@ -87,7 +87,6 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.location" @update:model-value="(location) => handleLocation(data, location)" > </VnLocation> diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue index 82ad559ad..1dc0dab43 100644 --- a/src/pages/Customer/CustomerList.vue +++ b/src/pages/Customer/CustomerList.vue @@ -413,7 +413,6 @@ function handleLocation(data, location) { <template #more-create-dialog="{ data }"> <VnLocation :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.location" @update:model-value="(location) => handleLocation(data, location)" /> <QInput v-model="data.userName" :label="t('Web user')" /> diff --git a/src/pages/Customer/components/CustomerAddressCreate.vue b/src/pages/Customer/components/CustomerAddressCreate.vue index 30e4b21d0..e37306a94 100644 --- a/src/pages/Customer/components/CustomerAddressCreate.vue +++ b/src/pages/Customer/components/CustomerAddressCreate.vue @@ -93,7 +93,6 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.location" @update:model-value="(location) => handleLocation(data, location)" /> diff --git a/src/pages/Customer/components/CustomerAddressEdit.vue b/src/pages/Customer/components/CustomerAddressEdit.vue index 7a4c44014..133d2fabc 100644 --- a/src/pages/Customer/components/CustomerAddressEdit.vue +++ b/src/pages/Customer/components/CustomerAddressEdit.vue @@ -177,7 +177,12 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.postalCode" + :location="{ + postcode: data.postalCode, + city: data.city, + province: data.province, + country: data.province.country, + }" @update:model-value="(location) => handleLocation(data, location)" ></VnLocation> </div> diff --git a/src/pages/Supplier/Card/SupplierAddresses.vue b/src/pages/Supplier/Card/SupplierAddresses.vue index 735b50625..4b2174d0b 100644 --- a/src/pages/Supplier/Card/SupplierAddresses.vue +++ b/src/pages/Supplier/Card/SupplierAddresses.vue @@ -26,7 +26,13 @@ const addressesFilter = { { relation: 'province', scope: { - fields: ['id', 'name'], + fields: ['id', 'name', 'countryFk'], + include: [ + { + relation: 'country', + scope: { fields: ['id', 'name'] }, + }, + ], }, }, ], diff --git a/src/pages/Supplier/Card/SupplierAddressesCreate.vue b/src/pages/Supplier/Card/SupplierAddressesCreate.vue index da6549a24..df98b6091 100644 --- a/src/pages/Supplier/Card/SupplierAddressesCreate.vue +++ b/src/pages/Supplier/Card/SupplierAddressesCreate.vue @@ -21,6 +21,7 @@ const newAddressForm = reactive({ provinceFk: null, phone: null, mobile: null, + province: null, }); const onDataSaved = () => { @@ -84,7 +85,16 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.location" + :location=" + data.postalCode + ? { + postcode: data.postalCode, + city: data.city, + province: data.province, + country: data.province.country, + } + : null + " @update:model-value="(location) => handleLocation(data, location)" > </VnLocation> diff --git a/src/pages/Supplier/Card/SupplierFiscalData.vue b/src/pages/Supplier/Card/SupplierFiscalData.vue index c638abbdc..c2cb42c6a 100644 --- a/src/pages/Supplier/Card/SupplierFiscalData.vue +++ b/src/pages/Supplier/Card/SupplierFiscalData.vue @@ -51,6 +51,23 @@ function handleLocation(data, location) { :url="`Suppliers/${route.params.id}`" :url-update="`Suppliers/${route.params.id}/updateFiscalData`" model="supplier" + :filter="{ + fields: ['id', 'name', 'city', 'postCode', 'countryFk', 'provinceFk'], + include: [ + { + relation: 'province', + scope: { + fields: ['id', 'name'], + }, + }, + { + relation: 'country', + scope: { + fields: ['id', 'name'], + }, + }, + ], + }" auto-load :clear-store-on-unmount="false" > @@ -130,7 +147,12 @@ function handleLocation(data, location) { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.postCode" + :location="{ + postcode: data.postCode, + city: data.city, + province: data.province, + country: data.country, + }" @update:model-value="(location) => handleLocation(data, location)" > </VnLocation> diff --git a/src/pages/Worker/WorkerCreate.vue b/src/pages/Worker/WorkerCreate.vue index a1ded2bfd..5f96c136d 100644 --- a/src/pages/Worker/WorkerCreate.vue +++ b/src/pages/Worker/WorkerCreate.vue @@ -172,7 +172,6 @@ onBeforeMount(async () => { <VnLocation :rules="validate('Worker.postcode')" :roles-allowed-to-create="['deliveryAssistant']" - v-model="data.location" @update:model-value="(location) => handleLocation(data, location)" :disable="formData.isFreelance" > diff --git a/src/pages/Worker/WorkerList.vue b/src/pages/Worker/WorkerList.vue index 0c2656597..9d4c3acbf 100644 --- a/src/pages/Worker/WorkerList.vue +++ b/src/pages/Worker/WorkerList.vue @@ -223,7 +223,6 @@ function uppercaseStreetModel(data) { <VnLocation :roles-allowed-to-create="['deliveryAssistant']" :options="postcodesOptions" - v-model="data.location" @update:model-value="(location) => handleLocation(data, location)" :disable="data.isFreelance" > diff --git a/src/router/modules/customer.js b/src/router/modules/customer.js index 684b83b0f..f364bd862 100644 --- a/src/router/modules/customer.js +++ b/src/router/modules/customer.js @@ -174,7 +174,7 @@ export default { path: 'edit', name: 'CustomerAddressEdit', meta: { - title: 'address-edit', + title: 'addressEdit', }, component: () => import( From 8acd008f42e02a80f0c491394f41335705dc3b85 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Wed, 14 Aug 2024 09:47:27 +0200 Subject: [PATCH 11/69] feat: handle newValue --- src/components/common/VnLocation.vue | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue index 778932be3..2fbe357ba 100644 --- a/src/components/common/VnLocation.vue +++ b/src/components/common/VnLocation.vue @@ -4,6 +4,7 @@ import VnSelectDialog from 'components/common/VnSelectDialog.vue'; import { useI18n } from 'vue-i18n'; import { ref } from 'vue'; const { t } = useI18n(); +const emit = defineEmits(['update:model-value', 'update:options']); const props = defineProps({ location: { @@ -39,7 +40,14 @@ function showLabel(data) { :emit-value="false" > <template #form> - <CreateNewPostcode @on-data-saved="(newValue) => (modelValue = newValue)" /> + <CreateNewPostcode + @on-data-saved=" + (newValue) => { + modelValue = newValue; + emit('update:model-value', newValue); + } + " + /> </template> <template #option="{ itemProps, opt }"> <QItem v-bind="itemProps"> From 9eff6b56ea4f78fbc8938dbbf5d22f89a4cd843a Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Wed, 14 Aug 2024 09:48:59 +0200 Subject: [PATCH 12/69] fix: remove print variable --- src/components/common/VnLocation.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue index 2fbe357ba..e95d5a043 100644 --- a/src/components/common/VnLocation.vue +++ b/src/components/common/VnLocation.vue @@ -22,7 +22,6 @@ function showLabel(data) { } </script> <template> - {{ modelValue }} <VnSelectDialog v-model="modelValue" option-filter-value="search" From a131cb559dbbc8f012f650bd6cbdd0130042a6d4 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Wed, 21 Aug 2024 13:34:40 +0200 Subject: [PATCH 13/69] feat: add max rule --- src/components/common/VnInput.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue index 75d4b8a28..e79a235d5 100644 --- a/src/components/common/VnInput.vue +++ b/src/components/common/VnInput.vue @@ -67,9 +67,13 @@ const mixinRules = [ requiredFieldRule, ...($attrs.rules ?? []), (val) => { - const { min } = vnInputRef.value.$attrs; + const { min, max } = vnInputRef.value.$attrs; if (!min) return null; if (min >= 0) if (Math.floor(val) < min) return t('inputMin', { value: min }); + if (!max) return null; + if (max > 0) { + if (Math.floor(val) > max) return t('inputMax', { value: max }); + } }, ]; </script> @@ -116,6 +120,8 @@ const mixinRules = [ <i18n> en: inputMin: Must be more than {value} + inputMax: Must be less than {value} es: inputMin: Debe ser mayor a {value} + inputMax: Debe ser menor a {value} </i18n> From 76a7f8a1b3366d5f5c7f61e7283073c8c6069a65 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Mon, 2 Sep 2024 12:09:48 +0200 Subject: [PATCH 14/69] refactor: refs #7500 refactor vnimg when storage is dms --- src/components/common/VnDmsList.vue | 8 ++------ src/components/ui/VnImg.vue | 15 +++++---------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue index 08c4e4aa4..c0e8ac43b 100644 --- a/src/components/common/VnDmsList.vue +++ b/src/components/common/VnDmsList.vue @@ -102,12 +102,8 @@ const columns = computed(() => [ storage: 'dms', collection: null, size: null, - token: prop.token, - url: - 'api/dms/' + - prop.row.file.split('.')[0] + - '/downloadFile?access_token=' + - token, + id: prop.row.file.split('.')[0], + token: token, class: 'rounded', }), }, diff --git a/src/components/ui/VnImg.vue b/src/components/ui/VnImg.vue index 2e690ffe1..19ac8ce7f 100644 --- a/src/components/ui/VnImg.vue +++ b/src/components/ui/VnImg.vue @@ -12,10 +12,12 @@ const $props = defineProps({ collection: { type: String, default: 'catalog', + required: false, }, resolution: { type: String, default: '200x200', + required: false, }, zoomResolution: { type: String, @@ -29,27 +31,20 @@ const $props = defineProps({ type: Number, required: true, }, - url: { - type: String, - required: false, - default: null, - }, }); const show = ref(false); const token = useSession().getTokenMultimedia(); const timeStamp = ref(`timestamp=${Date.now()}`); -if ($props.url) return $props.url; const isEmployee = useRole().isEmployee(); -const _url = [$props.storage, $props.collection, $props.size, $props.id] - .filter((prop) => prop) - .join('/'); const getUrl = (zoom = false) => { const curResolution = zoom ? $props.zoomResolution || $props.resolution : $props.resolution; + if ($props.storage === 'dms') + return `/api/${$props.storage}/${$props.id}/downloadFile?access_token=${token}`; return isEmployee - ? `/api/${_url}/download?access_token=${token}&${timeStamp.value}` + ? `/api/${$props.storage}/${$props.collection}/${curResolution}/${$props.id}/download?access_token=${token}&${timeStamp.value}` : noImage; }; const reload = () => { From 3dc720e2d0db55c61b7b28df6087d997af241b54 Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Wed, 4 Sep 2024 14:40:36 +0200 Subject: [PATCH 15/69] feat: refs #7404 add m3 and fix detail --- src/components/VnTable/VnTable.vue | 36 ++++- src/pages/Entry/EntryList.vue | 3 - src/pages/Entry/EntryStockBought.vue | 136 +++++++++++------- src/pages/Entry/EntryStockBoughtDetail.vue | 2 +- .../integration/entry/stockBought.spec.js | 2 +- 5 files changed, 118 insertions(+), 61 deletions(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 26b5c424a..0fd6d1dd1 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -90,6 +90,10 @@ const $props = defineProps({ type: String, default: '90vh', }, + footer: { + type: Boolean, + default: false, + }, }); const { t } = useI18n(); const stateStore = useStateStore(); @@ -108,7 +112,7 @@ const orders = ref(parseOrder(routeQuery.filter?.order)); const CrudModelRef = ref({}); const showForm = ref(false); const splittedColumns = ref({ columns: [] }); -const columnsVisibilitySkippped = ref(); +const columnsVisibilitySkipped = ref(); const createForm = ref(); const tableModes = [ @@ -347,11 +351,11 @@ defineExpose({ <CrudModel v-bind="$attrs" :class="$attrs['class'] ?? 'q-px-md'" - :limit="20" + :limit="$attrs.limit ?? 20" ref="CrudModelRef" @on-fetch="(...args) => emit('onFetch', ...args)" :search-url="searchUrl" - :disable-infinite-scroll="isTableMode" + :disable-infinite-scroll="$attrs['disable-infinite-scroll'] ?? isTableMode" @save-changes="reload" :has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable" :auto-load="hasParams || $attrs['auto-load']" @@ -371,7 +375,7 @@ defineExpose({ card-container-class="grid-three" flat :style="isTableMode && `max-height: ${tableHeight}`" - virtual-scroll + :virtual-scroll="!isTableMode" @virtual-scroll=" (event) => event.index > rows.length - 2 && @@ -614,6 +618,28 @@ defineExpose({ </QCard> </component> </template> + <template #bottom-row="{ cols }" v-if="footer"> + <QTr v-if="rows.length" class="bg-header" style="height: 30px"> + <QTh + v-for="col of cols.filter((cols) => cols.visible ?? true)" + :key="col?.id" + class="text-center" + > + <div + v-if="col?.summation" + :class="`text-${col?.align ?? 'left'}`" + class="text-bold q-pa-sm" + > + {{ + rows.reduce( + (sum, currentRow) => sum + currentRow[col.name], + 0 + ) + }} + </div> + </QTh> + </QTr> + </template> </QTable> </template> </CrudModel> @@ -672,7 +698,7 @@ es: } .bg-header { - background-color: var(--vn-header-color); + background-color: var(--vn-accent-color); color: var(--vn-text-color); } diff --git a/src/pages/Entry/EntryList.vue b/src/pages/Entry/EntryList.vue index c03c67edb..6f7ff1935 100644 --- a/src/pages/Entry/EntryList.vue +++ b/src/pages/Entry/EntryList.vue @@ -9,9 +9,6 @@ import RightMenu from 'src/components/common/RightMenu.vue'; import { toDate } from 'src/filters'; import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import EntrySummary from './Card/EntrySummary.vue'; -import VnUserLink from 'components/ui/VnUserLink.vue'; -import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; -import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue'; import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue'; import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue'; diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index 12fc96214..75d356bd2 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -6,24 +6,23 @@ import { useQuasar } from 'quasar'; import VnTable from 'components/VnTable/VnTable.vue'; import VnRow from 'src/components/ui/VnRow.vue'; -import VnInput from 'src/components/common/VnInput.vue'; -import VnLv from 'src/components/ui/VnLv.vue'; import FetchData from 'src/components/FetchData.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue'; +import { useRouter } from 'vue-router'; const { t } = useI18n(); const quasar = useQuasar(); const tableRef = ref(); const state = useState(); const user = state.getUser(); +const router = useRouter(); const columns = [ { align: 'left', label: 'Id', name: 'id', - isTitle: true, isId: true, columnFilter: false, visible: false, @@ -32,6 +31,7 @@ const columns = [ align: 'left', name: 'workerFk', label: t('Buyer'), + isTitle: true, columnFilter: false, }, { @@ -42,6 +42,7 @@ const columns = [ create: true, component: 'number', summation: true, + cardVisible: true, }, { align: 'left', @@ -67,6 +68,7 @@ const columns = [ name: 'bought', columnFilter: false, summation: true, + cardVisible: true, }, { align: 'left', @@ -89,7 +91,6 @@ const columns = [ component: EntryStockBoughtDetail, componentProps: { workerFk: row.workerFk, - dated: row.dated, }, maximized: true, }); @@ -98,15 +99,22 @@ const columns = [ ], }, ]; -function getFilter(dated = Date.vnNow()) { - console.log('dated: ', new Date(dated * 1000)); + +function navigate(id) { + router.push({ path: `/travel/${id}/basic-data` }); +} + +function getFilter(dated) { + const shipped = dated ? new Date(dated) : Date.vnNew(); + shipped.setHours(0, 0, 0, 0); return { - fields: ['id', 'm3'], - where: { dated }, + where: { + shipped, + m3: { neq: null }, + }, include: [ { relation: 'warehouseIn', - where: { code: 'vnh' }, }, ], }; @@ -116,49 +124,74 @@ const fetchDataRef = ref(); </script> <template> <VnSubToolbar /> - <VnTable - ref="tableRef" - data-key="StockBoughts" - url="StockBoughts/getStockBought" - save-url="StockBoughts/crud" - order="reserve DESC" - :is-editable="true" - :disable-option="{ card: true }" - :create="{ - urlCreate: 'StockBoughts', - title: t('Reserve some space'), - onDataSaved: () => tableRef.reload(), - formInitialData: { - workerFk: user.id, - dated: Date.vnNow(), - }, - }" - :columns="columns" - auto-load - @on-fetch="() => fetchDataRef.fetch()" - > - <template #moreFilterPanel="{ params }"> - <FetchData - ref="fetchDataRef" - url="Travels" - limit="1" - auto-load - :filter="getFilter(params?.date)" - @on-fetch="(data) => (travel = data)" - /> - <VnRow class="q-pa-md" style="align-items: center" v-if="travel?.length"> - <span>{{ t('Booked trucks: ') + travel[0]?.m3 }}</span> - <QBtn style="max-width: 20%" flat icon="edit" /> - </VnRow> - </template> - <template #column-workerFk="{ row }"> - <span class="link" @click.stop> - {{ row?.worker?.user?.name }} - <WorkerDescriptorProxy :id="row?.workerFk" /> - </span> - </template> - </VnTable> + <QPage class="column items-center q-pa-md"> + <VnTable + ref="tableRef" + data-key="StockBoughts" + url="StockBoughts/getStockBought" + save-url="StockBoughts/crud" + order="reserve DESC" + :is-editable="true" + :create="{ + urlCreate: 'StockBoughts', + title: t('Reserve some space'), + onDataSaved: () => tableRef.reload(), + formInitialData: { + workerFk: user.id, + dated: Date.vnNow(), + }, + }" + :columns="columns" + auto-load + @on-fetch="() => console.log('fetching...', fetchDataRef.fetch())" + style="max-width: 40%" + :footer="true" + > + <template #moreFilterPanel="{ params }"> + <FetchData + ref="fetchDataRef" + url="Travels" + limit="1" + auto-load + :filter="getFilter(params?.dated)" + @on-fetch="(data) => (travel = data)" + /> + <div class="trucks"> + <div> + <span style="color: var(--vn-label-color)"> + {{ t('Booked trucks') + ': ' }} + </span> + </div> + <div v-if="travel"> + <span> + {{ travel[0]?.m3 }} + </span> + <QBtn + style="max-width: 20%" + flat + icon="edit" + @click="navigate(travel[0]?.id)" + /> + </div> + </div> + </template> + <template #column-workerFk="{ row }"> + <span class="link" @click.stop> + {{ row?.worker?.user?.name }} + <WorkerDescriptorProxy :id="row?.workerFk" /> + </span> + </template> + </VnTable> + </QPage> </template> +<style lang="scss"> +.trucks { + text-align: center; + margin: 3%; + border: 3px solid var(--vn-header-color); + padding: 1%; +} +</style> <i18n> en: Buyer: Buyer @@ -168,6 +201,7 @@ const fetchDataRef = ref(); Date: Date This buyer has already made a reservation for this date: This buyer has already made a reservation for this date es: + Booked trucks: Camiones reservados Buyer: Comprador Reserve: Reservado Bought: Comprado diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue index 9212f1115..b9420af71 100644 --- a/src/pages/Entry/EntryStockBoughtDetail.vue +++ b/src/pages/Entry/EntryStockBoughtDetail.vue @@ -18,7 +18,7 @@ const $props = defineProps({ required: true, }, }); -const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}`; +const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&date=${$props.dated}`; const columns = [ { align: 'left', diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js index 8e4fe225c..10af3ef42 100644 --- a/test/cypress/integration/entry/stockBought.spec.js +++ b/test/cypress/integration/entry/stockBought.spec.js @@ -8,7 +8,7 @@ describe('EntryStockBought', () => { ); }); it('Should edit the reserved space', () => { - cy.get('tBody > tr').its('length').should('eq', 1); + cy.get('tBody > tr').its('length').should('eq', 2); cy.get(reserveField).type('10{enter}'); cy.get('button[title="Save"]').click(); cy.get('.q-notification__message').should('have.text', 'Data saved'); From cd12343302c9fea5bc5419ac04731d43b75baf2d Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Fri, 6 Sep 2024 07:26:04 +0200 Subject: [PATCH 16/69] feat: refs #7404 add some style to the form and reorganize fields --- src/components/VnTable/VnColumn.vue | 3 + src/components/VnTable/VnTable.vue | 8 +- src/components/common/VnComponent.vue | 6 +- src/pages/Entry/EntryStockBought.vue | 119 ++++++++++----------- src/pages/Entry/EntryStockBoughtFilter.vue | 57 ++++++++++ src/pages/Route/Card/RouteSearchbar.vue | 1 - src/pages/Route/RouteList.vue | 1 - 7 files changed, 120 insertions(+), 75 deletions(-) create mode 100644 src/pages/Entry/EntryStockBoughtFilter.vue diff --git a/src/components/VnTable/VnColumn.vue b/src/components/VnTable/VnColumn.vue index ed34e9eee..ad120f02e 100644 --- a/src/components/VnTable/VnColumn.vue +++ b/src/components/VnTable/VnColumn.vue @@ -171,6 +171,8 @@ const components = computed(() => $props.components ?? defaultComponents); :value="{ row, model }" v-model="model" /> + + {{ console.log('model: ', col) }} <VnComponent v-if="col.component" :prop="col" @@ -178,6 +180,7 @@ const components = computed(() => $props.components ?? defaultComponents); :value="{ row, model }" v-model="model" /> + <span :title="value" v-else>{{ value }}</span> <VnComponent v-if="col.after" diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 0fd6d1dd1..b5d6e8d10 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -15,7 +15,6 @@ import VnTableChip from 'components/VnTable/VnChip.vue'; import VnVisibleColumn from 'src/components/VnTable/VnVisibleColumn.vue'; import VnLv from 'components/ui/VnLv.vue'; import VnTableOrder from 'src/components/VnTable/VnOrder.vue'; -import item from 'src/router/modules/item'; const $props = defineProps({ columns: { @@ -410,7 +409,7 @@ defineExpose({ /> </template> <template #header-cell="{ col }"> - <QTh v-if="col.visible ?? true"> + <QTh table-header-style="max-width:50%" v-if="col.visible ?? true"> <div class="column self-start q-ml-xs ellipsis" :class="`text-${col?.align ?? 'left'}`" @@ -665,6 +664,7 @@ defineExpose({ :column-name="column.name" :label="column.label" > + {{ console.log('data: ', data) }} <VnTableColumn :column="column" :row="{}" @@ -708,9 +708,7 @@ es: .q-table--dark .q-table__bottom, .q-table--dark thead, -.q-table--dark tr, -.q-table--dark th, -.q-table--dark td { +.q-table--dark tr { border-color: var(--vn-section-color); } diff --git a/src/components/common/VnComponent.vue b/src/components/common/VnComponent.vue index fa99f9892..1ba1506d5 100644 --- a/src/components/common/VnComponent.vue +++ b/src/components/common/VnComponent.vue @@ -17,17 +17,16 @@ const $props = defineProps({ }, }); -let mixed; const componentArray = computed(() => { if (typeof $props.prop === 'object') return [$props.prop]; return $props.prop; }); function mix(toComponent) { - if (mixed) return mixed; const { component, attrs, event } = toComponent; + console.log('attrs: ', attrs); const customComponent = $props.components[component]; - mixed = { + return { component: customComponent?.component ?? component, attrs: { ...toValueAttrs(attrs), @@ -37,7 +36,6 @@ function mix(toComponent) { }, event: { ...customComponent?.event, ...event }, }; - return mixed; } function toValueAttrs(attrs) { diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index 75d356bd2..8f197be92 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -4,20 +4,18 @@ import { useI18n } from 'vue-i18n'; import { useState } from 'src/composables/useState'; import { useQuasar } from 'quasar'; -import VnTable from 'components/VnTable/VnTable.vue'; -import VnRow from 'src/components/ui/VnRow.vue'; -import FetchData from 'src/components/FetchData.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; +import RightMenu from 'src/components/common/RightMenu.vue'; +import EntryStockBoughtFilter from './EntryStockBoughtFilter.vue'; +import VnTable from 'components/VnTable/VnTable.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue'; -import { useRouter } from 'vue-router'; const { t } = useI18n(); const quasar = useQuasar(); const tableRef = ref(); const state = useState(); const user = state.getUser(); -const router = useRouter(); const columns = [ { align: 'left', @@ -31,8 +29,17 @@ const columns = [ align: 'left', name: 'workerFk', label: t('Buyer'), - isTitle: true, - columnFilter: false, + component: 'select', + create: true, + attrs: { + url: 'Workers/activeWithInheritedRole', + fields: ['id', 'name'], + where: { role: 'buyer' }, + optionFilter: 'firstName', + optionLabel: 'name', + optionValue: 'id', + useLike: false, + }, }, { align: 'left', @@ -44,31 +51,13 @@ const columns = [ summation: true, cardVisible: true, }, - { - align: 'left', - name: 'workerFk', - label: t('Buyer'), - component: 'select', - create: true, - visible: false, - columnFilter: false, - attrs: { - url: 'Workers/activeWithInheritedRole', - fields: ['id', 'name'], - where: { role: 'buyer' }, - optionFilter: 'firstName', - optionLabel: 'name', - optionValue: 'id', - useLike: false, - }, - }, { align: 'left', label: t('Bought'), name: 'bought', - columnFilter: false, summation: true, cardVisible: true, + columnFilter: false, }, { align: 'left', @@ -92,7 +81,6 @@ const columns = [ componentProps: { workerFk: row.workerFk, }, - maximized: true, }); }, }, @@ -100,10 +88,6 @@ const columns = [ }, ]; -function navigate(id) { - router.push({ path: `/travel/${id}/basic-data` }); -} - function getFilter(dated) { const shipped = dated ? new Date(dated) : Date.vnNew(); shipped.setHours(0, 0, 0, 0); @@ -119,11 +103,46 @@ function getFilter(dated) { ], }; } -const travel = ref(); -const fetchDataRef = ref(); +const userParams = ref({ + dated: Date.vnNew(), +}); </script> <template> - <VnSubToolbar /> + <VnSubToolbar> + <template #st-data="{ params }"> + <FetchData + ref="fetchDataRef" + url="Travels" + limit="1" + auto-load + :filter="getFilter(params?.dated)" + @on-fetch="(data) => (travel = data)" + /> + <div> + <div> + <span style="color: var(--vn-label-color)"> + {{ t('Booked trucks') + ': ' }} + </span> + </div> + <div v-if="travel"> + <span> + {{ travel[0]?.m3 }} + </span> + <QBtn + style="max-width: 20%" + flat + icon="edit" + @click="navigate(travel[0]?.id)" + /> + </div> + </div> + </template> + </VnSubToolbar> + <RightMenu> + <template #right-panel> + <EntryStockBoughtFilter data-key="StockBoughts" /> + </template> + </RightMenu> <QPage class="column items-center q-pa-md"> <VnTable ref="tableRef" @@ -131,6 +150,7 @@ const fetchDataRef = ref(); url="StockBoughts/getStockBought" save-url="StockBoughts/crud" order="reserve DESC" + :right-search="false" :is-editable="true" :create="{ urlCreate: 'StockBoughts', @@ -142,39 +162,10 @@ const fetchDataRef = ref(); }, }" :columns="columns" + :user-params="userParams" auto-load - @on-fetch="() => console.log('fetching...', fetchDataRef.fetch())" - style="max-width: 40%" :footer="true" > - <template #moreFilterPanel="{ params }"> - <FetchData - ref="fetchDataRef" - url="Travels" - limit="1" - auto-load - :filter="getFilter(params?.dated)" - @on-fetch="(data) => (travel = data)" - /> - <div class="trucks"> - <div> - <span style="color: var(--vn-label-color)"> - {{ t('Booked trucks') + ': ' }} - </span> - </div> - <div v-if="travel"> - <span> - {{ travel[0]?.m3 }} - </span> - <QBtn - style="max-width: 20%" - flat - icon="edit" - @click="navigate(travel[0]?.id)" - /> - </div> - </div> - </template> <template #column-workerFk="{ row }"> <span class="link" @click.stop> {{ row?.worker?.user?.name }} diff --git a/src/pages/Entry/EntryStockBoughtFilter.vue b/src/pages/Entry/EntryStockBoughtFilter.vue new file mode 100644 index 000000000..3393113f2 --- /dev/null +++ b/src/pages/Entry/EntryStockBoughtFilter.vue @@ -0,0 +1,57 @@ +<script setup> +import { ref } from 'vue'; +import { useI18n } from 'vue-i18n'; +import { onMounted } from 'vue'; +import { useStateStore } from 'stores/useStateStore'; + +import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; +import FetchData from 'components/FetchData.vue'; +import VnInputDate from 'src/components/common/VnInputDate.vue'; + +const { t } = useI18n(); +const props = defineProps({ + dataKey: { + type: String, + required: true, + }, +}); + +const companiesOptions = ref([]); +const stateStore = useStateStore(); +onMounted(async () => { + stateStore.rightDrawer = true; +}); +</script> + +<template> + <FetchData + ref="buyer" + url="Workers/activeWithInheritedRole" + :filter="{ + fields: ['id', 'name'], + where: { role: 'buyer' }, + }" + order="name" + @on-fetch="(data) => (companiesOptions = data)" + auto-load + /> + <VnFilterPanel :data-key="props.dataKey" :search-button="true"> + <template #tags="{ tag, formatFn }"> + <div class="q-gutter-x-xs"> + <strong>{{ t(`params.${tag.label}`) }}: </strong> + <span>{{ formatFn(tag.value) }}</span> + </div> + </template> + <template #body="{ params }"> + <QItem class="q-my-sm"> + <QItemSection> + <VnInputDate v-model="params.dated" :label="t('Date')" is-outlined /> + </QItemSection> + </QItem> + </template> + </VnFilterPanel> +</template> +<i18n> + es: + Date: Fecha +</i18n> diff --git a/src/pages/Route/Card/RouteSearchbar.vue b/src/pages/Route/Card/RouteSearchbar.vue index 48ad09151..a8e11cef6 100644 --- a/src/pages/Route/Card/RouteSearchbar.vue +++ b/src/pages/Route/Card/RouteSearchbar.vue @@ -3,7 +3,6 @@ import VnSearchbar from 'components/ui/VnSearchbar.vue'; import { useI18n } from 'vue-i18n'; const { t } = useI18n(); </script> - <template> <VnSearchbar data-key="RouteList" diff --git a/src/pages/Route/RouteList.vue b/src/pages/Route/RouteList.vue index ef544a68d..7e2358236 100644 --- a/src/pages/Route/RouteList.vue +++ b/src/pages/Route/RouteList.vue @@ -409,5 +409,4 @@ es: Route is not served: La ruta no está servida hourStarted: Hora de inicio hourFinished: Hora de fin - Volume: Volumen </i18n> From e1adb1a8dd7c30f7cc764b5f00e2ca0846565ac3 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Tue, 10 Sep 2024 08:01:28 +0200 Subject: [PATCH 17/69] refactor: refs #6346 requested changes --- src/pages/Wagon/Type/WagonCreateTray.vue | 8 +++----- src/pages/Wagon/Type/WagonTypeEdit.vue | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/Wagon/Type/WagonCreateTray.vue b/src/pages/Wagon/Type/WagonCreateTray.vue index c3f8b3847..bb52e747b 100644 --- a/src/pages/Wagon/Type/WagonCreateTray.vue +++ b/src/pages/Wagon/Type/WagonCreateTray.vue @@ -39,7 +39,7 @@ watch(wagonColors, () => { const emit = defineEmits(['onSubmit']); async function getTrays() { - const data = await axios.get('WagonTypeTrays', undefined, { + const { data } = await axios.get('WagonTypeTrays', undefined, { filter: { wagonTypeFk: entityId.value }, }); existingTrayHeight.value = data.data.filter( @@ -49,13 +49,11 @@ async function getTrays() { } function onSubmit() { - const newTray = { + emit('onSubmit', { wagonTypeFk: entityId.value, wagonTypeColorFk: selectedTrayColor.value, height: trayHeight.value, - }; - - emit('onSubmit', newTray); + }); } getTrays(); </script> diff --git a/src/pages/Wagon/Type/WagonTypeEdit.vue b/src/pages/Wagon/Type/WagonTypeEdit.vue index 25ba05714..dc261990f 100644 --- a/src/pages/Wagon/Type/WagonTypeEdit.vue +++ b/src/pages/Wagon/Type/WagonTypeEdit.vue @@ -56,6 +56,10 @@ async function deleteTray(trayToDelete) { type: 'positive', }); } catch (err) { + notify({ + message: t('Error deleting tray'), + type: 'negative', + }); console.log('err: ', err); } } From 30ffb2428ea7e549681a3d2d360dfdb7aee1b92e Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Tue, 10 Sep 2024 08:28:48 +0200 Subject: [PATCH 18/69] perf: refs #6346 previous changes --- src/pages/Wagon/Type/WagonCreateTray.vue | 4 +-- src/pages/Wagon/Type/WagonTypeEdit.vue | 40 +++++++++--------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/src/pages/Wagon/Type/WagonCreateTray.vue b/src/pages/Wagon/Type/WagonCreateTray.vue index bb52e747b..304fa83ac 100644 --- a/src/pages/Wagon/Type/WagonCreateTray.vue +++ b/src/pages/Wagon/Type/WagonCreateTray.vue @@ -42,9 +42,7 @@ async function getTrays() { const { data } = await axios.get('WagonTypeTrays', undefined, { filter: { wagonTypeFk: entityId.value }, }); - existingTrayHeight.value = data.data.filter( - (item) => item.wagonTypeFk == entityId.value - ); + existingTrayHeight.value = data.filter((item) => item.wagonTypeFk == entityId.value); heights.value = existingTrayHeight.value.map((item) => item.height); } diff --git a/src/pages/Wagon/Type/WagonTypeEdit.vue b/src/pages/Wagon/Type/WagonTypeEdit.vue index dc261990f..eb8205d72 100644 --- a/src/pages/Wagon/Type/WagonTypeEdit.vue +++ b/src/pages/Wagon/Type/WagonTypeEdit.vue @@ -32,36 +32,24 @@ async function loadTrays() { } async function addTray(newTray) { - try { - const res = await axios.post(`WagonTypeTrays`, newTray); - wagonTrays.value.push(res.data); - notify({ - message: t(`Tray added successfully`), - type: 'positive', - }); - } catch (err) { - console.log('err: ', err); - } + const res = await axios.post(`WagonTypeTrays`, newTray); + wagonTrays.value.push(res.data); + notify({ + message: t(`Tray added successfully`), + type: 'positive', + }); } async function deleteTray(trayToDelete) { - try { - await axios.delete(`WagonTypeTrays/${trayToDelete.id}`); - const index = wagonTrays.value.findIndex((tray) => tray.id === trayToDelete.id); - if (index !== -1) { - wagonTrays.value.splice(index, 1); - } - notify({ - message: t('Tray deleted successfully'), - type: 'positive', - }); - } catch (err) { - notify({ - message: t('Error deleting tray'), - type: 'negative', - }); - console.log('err: ', err); + await axios.delete(`WagonTypeTrays/${trayToDelete.id}`); + const index = wagonTrays.value.findIndex((tray) => tray.id === trayToDelete.id); + if (index !== -1) { + wagonTrays.value.splice(index, 1); } + notify({ + message: t('Tray deleted successfully'), + type: 'positive', + }); } const filter = { From c7e717c61108c59e29d35a2f65796aa5492f05bf Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Wed, 11 Sep 2024 07:55:12 +0200 Subject: [PATCH 19/69] feat: refs #7404 add travel m3 to reserves form --- src/components/VnTable/VnColumn.vue | 3 - src/components/common/VnComponent.vue | 1 - src/components/ui/VnFilterPanel.vue | 1 + src/pages/Entry/EntryStockBought.vue | 84 ++++++++++++++----- src/pages/Entry/EntryStockBoughtFilter.vue | 11 ++- .../integration/entry/stockBought.spec.js | 2 +- 6 files changed, 76 insertions(+), 26 deletions(-) diff --git a/src/components/VnTable/VnColumn.vue b/src/components/VnTable/VnColumn.vue index ad120f02e..ed34e9eee 100644 --- a/src/components/VnTable/VnColumn.vue +++ b/src/components/VnTable/VnColumn.vue @@ -171,8 +171,6 @@ const components = computed(() => $props.components ?? defaultComponents); :value="{ row, model }" v-model="model" /> - - {{ console.log('model: ', col) }} <VnComponent v-if="col.component" :prop="col" @@ -180,7 +178,6 @@ const components = computed(() => $props.components ?? defaultComponents); :value="{ row, model }" v-model="model" /> - <span :title="value" v-else>{{ value }}</span> <VnComponent v-if="col.after" diff --git a/src/components/common/VnComponent.vue b/src/components/common/VnComponent.vue index 1ba1506d5..bd25c787c 100644 --- a/src/components/common/VnComponent.vue +++ b/src/components/common/VnComponent.vue @@ -24,7 +24,6 @@ const componentArray = computed(() => { function mix(toComponent) { const { component, attrs, event } = toComponent; - console.log('attrs: ', attrs); const customComponent = $props.components[component]; return { component: customComponent?.component ?? component, diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index cebdc4bbf..b3bdec0a5 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -58,6 +58,7 @@ const $props = defineProps({ }); defineExpose({ search, sanitizer }); + const emit = defineEmits([ 'update:modelValue', 'refresh', diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index 8f197be92..ad338acb1 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -1,10 +1,13 @@ <script setup> -import { ref } from 'vue'; +import { onMounted, ref, watch } from 'vue'; import { useI18n } from 'vue-i18n'; import { useState } from 'src/composables/useState'; import { useQuasar } from 'quasar'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; +import axios from 'axios'; +import FetchData from 'components/FetchData.vue'; +import VnRow from 'components/ui/VnRow.vue'; import RightMenu from 'src/components/common/RightMenu.vue'; import EntryStockBoughtFilter from './EntryStockBoughtFilter.vue'; import VnTable from 'components/VnTable/VnTable.vue'; @@ -13,7 +16,6 @@ import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue'; const { t } = useI18n(); const quasar = useQuasar(); -const tableRef = ref(); const state = useState(); const user = state.getUser(); const columns = [ @@ -88,7 +90,32 @@ const columns = [ }, ]; +const fetchDataRef = ref(); +const tableRef = ref(); +const travel = ref(null); +const userParams = ref({ + dated: Date.vnNew(), +}); +const filter = ref({ + where: { + shipped: (userParams.value.dated + ? new Date(userParams.value.dated) + : Date.vnNew() + ).setHours(0, 0, 0, 0), + m3: { neq: null }, + }, + include: [ + { + relation: 'warehouseIn', + scope: { + where: { code: 'vnh' }, + }, + }, + ], +}); + function getFilter(dated) { + console.log('dated: ', dated); const shipped = dated ? new Date(dated) : Date.vnNew(); shipped.setHours(0, 0, 0, 0); return { @@ -99,48 +126,62 @@ function getFilter(dated) { include: [ { relation: 'warehouseIn', + scope: { + where: { code: 'vnh' }, + }, }, ], }; } -const userParams = ref({ - dated: Date.vnNew(), -}); + +const setUserParams = async ({ dated }) => { + const shipped = (dated ? new Date(dated) : Date.vnNew()).setHours(0, 0, 0, 0); + + filter.value.where.shipped = shipped; + fetchDataRef.value?.fetch(); +}; </script> <template> <VnSubToolbar> - <template #st-data="{ params }"> + <template #st-data> <FetchData ref="fetchDataRef" url="Travels" limit="1" auto-load - :filter="getFilter(params?.dated)" + :filter="filter" @on-fetch="(data) => (travel = data)" /> - <div> - <div> - <span style="color: var(--vn-label-color)"> - {{ t('Booked trucks') + ': ' }} - </span> - </div> - <div v-if="travel"> + + <VnRow> + <div v-if="travel" class="q-pa-md"> + <QIcon + name="local_airport" + class="fill-icon q-mr-sm" + size="md" + :title="t('Travel')" + color="primary" + /> <span> - {{ travel[0]?.m3 }} + {{ t('Booked trucks') + ': ' + travel[0]?.m3 }} </span> <QBtn style="max-width: 20%" flat icon="edit" @click="navigate(travel[0]?.id)" + :title="t('Edit travel')" /> </div> - </div> + </VnRow> </template> </VnSubToolbar> <RightMenu> <template #right-panel> - <EntryStockBoughtFilter data-key="StockBoughts" /> + <EntryStockBoughtFilter + data-key="StockBoughts" + @set-user-params="setUserParams" + /> </template> </RightMenu> <QPage class="column items-center q-pa-md"> @@ -155,7 +196,10 @@ const userParams = ref({ :create="{ urlCreate: 'StockBoughts', title: t('Reserve some space'), - onDataSaved: () => tableRef.reload(), + onDataSaved: () => { + tableRef.reload(); + fetchDataRef.reload(); + }, formInitialData: { workerFk: user.id, dated: Date.vnNow(), @@ -163,8 +207,8 @@ const userParams = ref({ }" :columns="columns" :user-params="userParams" - auto-load :footer="true" + auto-load > <template #column-workerFk="{ row }"> <span class="link" @click.stop> @@ -192,6 +236,8 @@ const userParams = ref({ Date: Date This buyer has already made a reservation for this date: This buyer has already made a reservation for this date es: + Edit travel: Editar envío + Travel: Envíos Booked trucks: Camiones reservados Buyer: Comprador Reserve: Reservado diff --git a/src/pages/Entry/EntryStockBoughtFilter.vue b/src/pages/Entry/EntryStockBoughtFilter.vue index 3393113f2..aaf9e7a5b 100644 --- a/src/pages/Entry/EntryStockBoughtFilter.vue +++ b/src/pages/Entry/EntryStockBoughtFilter.vue @@ -15,9 +15,12 @@ const props = defineProps({ required: true, }, }); - const companiesOptions = ref([]); const stateStore = useStateStore(); +const emit = defineEmits(['set-user-params']); +const setUserParams = (params) => { + emit('set-user-params', params); +}; onMounted(async () => { stateStore.rightDrawer = true; }); @@ -35,7 +38,11 @@ onMounted(async () => { @on-fetch="(data) => (companiesOptions = data)" auto-load /> - <VnFilterPanel :data-key="props.dataKey" :search-button="true"> + <VnFilterPanel + :data-key="props.dataKey" + :search-button="true" + @set-user-params="setUserParams" + > <template #tags="{ tag, formatFn }"> <div class="q-gutter-x-xs"> <strong>{{ t(`params.${tag.label}`) }}: </strong> diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js index 10af3ef42..a18e2bd2e 100644 --- a/test/cypress/integration/entry/stockBought.spec.js +++ b/test/cypress/integration/entry/stockBought.spec.js @@ -20,7 +20,7 @@ describe('EntryStockBought', () => { cy.get('input[aria-label="Date"]').eq(1).type('01-01'); cy.get('input[aria-label="Buyer"]').type('buyerboss{downarrow}{enter}'); cy.get('.q-notification__message').should('have.text', 'Data created'); - cy.get('tBody > tr').its('length').should('eq', 2); + cy.get('tBody > tr').its('length').should('eq', 3); }); it('Should check detail for the buyer', () => { cy.get(':nth-child(1) > .sticky > .q-btn > .q-btn__content > .q-icon').click(); From 2b012d2de4ce72f253b9d8d7e2a99f4ceb03f34f Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Wed, 11 Sep 2024 10:04:40 +0200 Subject: [PATCH 20/69] fix: refs #7353 use same datakey --- src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue b/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue index 4950ab381..f1c347588 100644 --- a/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue +++ b/src/pages/Monitor/Ticket/MonitorTicketSearchbar.vue @@ -3,7 +3,7 @@ import VnSearchbar from 'components/ui/VnSearchbar.vue'; </script> <template> <VnSearchbar - data-key="SalesMonitorTickets" + data-key="saleMonitorTickets" url="SalesMonitors/salesFilter" :redirect="false" :label="$t('searchBar.label')" From b559f2f18c4a0fd370ac85e3f2e7254de8c9f8b4 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Wed, 11 Sep 2024 10:18:11 +0200 Subject: [PATCH 21/69] refactor: refs #7353 use global locales --- src/i18n/locale/en.yml | 9 +++++++ src/i18n/locale/es.yml | 9 +++++++ .../Monitor/Ticket/MonitorTicketFilter.vue | 24 ++++--------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 362c1ec9f..02f04c994 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -278,6 +278,15 @@ globals: createInvoiceIn: Create invoice in myAccount: My account noOne: No one + params: + search: General search + clientFk: Client id + salesPersonFk: Sales person + warehouseFk: Warehouse + provinceFk: Province + from: From + To: To + stateFk: State 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 34383686c..caa6b6788 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -282,6 +282,15 @@ globals: createInvoiceIn: Crear factura recibida myAccount: Mi cuenta noOne: Nadie + params: + search: Búsqueda general + clientFk: Id cliente + salesPersonFk: Comercial + warehouseFk: Almacén + provinceFk: Provincia + from: Desde + To: Hasta + stateFk: Estado errors: statusUnauthorized: Acceso denegado statusInternalServerError: Ha ocurrido un error interno del servidor diff --git a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue index 167a10465..17e26618d 100644 --- a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue +++ b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue @@ -64,7 +64,7 @@ const handleScopeDays = (params, days, callback) => { <QItem> <QItemSection> <VnInput - :label="t('params.clientFk')" + :label="t('globals.params.clientFk')" v-model="params.clientFk" is-outlined /> @@ -105,7 +105,7 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.salesPersonFk')" + :label="t('globals.params.salesPersonFk')" v-model="params.salesPersonFk" url="Workers/search" :params="{ departmentCodes: ['VT'] }" @@ -158,7 +158,7 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.stateFk')" + :label="t('globals.params.stateFk')" v-model="params.stateFk" url="States" is-outlined @@ -184,7 +184,7 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.warehouseFk')" + :label="t('globals.params.warehouseFk')" v-model="params.warehouseFk" :options="warehouses" /> @@ -196,7 +196,7 @@ const handleScopeDays = (params, days, callback) => { outlined dense rounded - :label="t('params.provinceFk')" + :label="t('globals.params.provinceFk')" v-model="params.provinceFk" url="Provinces" /> @@ -235,22 +235,15 @@ const handleScopeDays = (params, days, callback) => { <i18n> en: params: - clientFk: Client id orderFk: Order id scopeDays: Days onward nickname: Nickname - salesPersonFk: Sales person refFk: Invoice agencyModeFk: Agency - stateFk: State groupedStates: Grouped State - warehouseFk: Warehouse - provinceFk: Province myTeam: My team problems: With problems pending: Pending - from: From - to: To alertLevel: Grouped State FREE: Free DELIVERED: Delivered @@ -261,22 +254,15 @@ en: es: params: - clientFk: Id cliente orderFk: Id cesta scopeDays: Días en adelante nickname: Nombre mostrado - salesPersonFk: Comercial refFk: Factura agencyModeFk: Agencia - stateFk: Estado groupedStates: Estado agrupado - warehouseFk: Almacén - provinceFk: Provincia myTeam: Mi equipo problems: Con problemas pending: Pendiente - from: Desde - To: Hasta alertLevel: Estado agrupado FREE: Libre DELIVERED: Servido From 9219fa07f57b4a317de6dd59bc9d037c744c1021 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Wed, 11 Sep 2024 11:23:14 +0200 Subject: [PATCH 22/69] fix: refs #7353 hide search param --- src/i18n/locale/en.yml | 1 - src/i18n/locale/es.yml | 1 - src/pages/Monitor/Ticket/MonitorTicketFilter.vue | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 02f04c994..19372f698 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -279,7 +279,6 @@ globals: myAccount: My account noOne: No one params: - search: General search clientFk: Client id salesPersonFk: Sales person warehouseFk: Warehouse diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index caa6b6788..60e61d51c 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -283,7 +283,6 @@ globals: myAccount: Mi cuenta noOne: Nadie params: - search: Búsqueda general clientFk: Id cliente salesPersonFk: Comercial warehouseFk: Almacén diff --git a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue index 17e26618d..3c95f5cdd 100644 --- a/src/pages/Monitor/Ticket/MonitorTicketFilter.vue +++ b/src/pages/Monitor/Ticket/MonitorTicketFilter.vue @@ -40,7 +40,7 @@ const handleScopeDays = (params, days, callback) => { <VnFilterPanel :data-key="dataKey" :search-button="true" - :hidden-tags="['from', 'to']" + :hidden-tags="['from', 'to', 'search']" :custom-tags="['scopeDays']" :unremovable-params="['from', 'to', 'scopeDays']" > From d822bb6f208bc15812235e43dd0f3cc3e3db2360 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Thu, 12 Sep 2024 09:12:36 +0200 Subject: [PATCH 23/69] fix(ClaimList): attenderFk filter --- src/components/VnTable/VnFilter.vue | 2 +- src/pages/Claim/ClaimList.vue | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/VnTable/VnFilter.vue b/src/components/VnTable/VnFilter.vue index c6d4d8ef2..fd3c29fa3 100644 --- a/src/components/VnTable/VnFilter.vue +++ b/src/components/VnTable/VnFilter.vue @@ -34,7 +34,7 @@ const model = defineModel(undefined, { required: true }); const arrayData = useArrayData($props.dataKey, { searchUrl: $props.searchUrl }); const columnFilter = computed(() => $props.column?.columnFilter); -const updateEvent = { 'update:modelValue': addFilter, remove: () => addFilter(null) }; +const updateEvent = { 'update:modelValue': addFilter }; const enterEvent = { 'keyup.enter': () => addFilter(model.value), remove: () => addFilter(null), diff --git a/src/pages/Claim/ClaimList.vue b/src/pages/Claim/ClaimList.vue index b03dfb226..8f265442a 100644 --- a/src/pages/Claim/ClaimList.vue +++ b/src/pages/Claim/ClaimList.vue @@ -52,6 +52,7 @@ const columns = computed(() => [ name: 'attendedBy', orderBy: 'workerFk', columnFilter: { + name: 'attenderFk', component: 'select', attrs: { url: 'Workers/activeWithInheritedRole', From 6b79d70551f4bdc981c20816d1b014f6d4162fa7 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Thu, 12 Sep 2024 09:14:55 +0200 Subject: [PATCH 24/69] refactor: refs #7828 wip --- src/pages/Worker/Card/WorkerTimeControl.vue | 50 +++++++++------------ 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue index abf60a078..2f66fbcc1 100644 --- a/src/pages/Worker/Card/WorkerTimeControl.vue +++ b/src/pages/Worker/Card/WorkerTimeControl.vue @@ -271,44 +271,38 @@ const fetchWorkerTimeControlMails = async (filter) => { const fetchWeekData = async () => { try { - const filter = { - where: { - workerFk: route.params.id, - year: selectedDate.value ? selectedDate.value?.getFullYear() : null, - week: selectedWeekNumber.value, - }, - }; - - const data = await fetchWorkerTimeControlMails(filter); - if (!data.length) { - state.value = null; - } else { + const data = ( + await axios.get(`WorkerTimeControlMails/${route.params.id}/getWeeklyMail`, { + params: { + workerFk: route.params.id, + year: selectedDate.value.getFullYear(), + week: selectedWeekNumber.value, + }, + }) + ).data; + if (!data.length) state.value = null; + else { const [mail] = data; state.value = mail.state; reason.value = mail.reason; } - await canBeResend(); + canResend.value = !!( + await axios.get('WorkerTimeControlMails/count', { + filter: { + where: { + year: selectedDate.value.getFullYear(), + week: selectedWeekNumber.value, + limit: 1, + }, + }, + }) + ).data.count; } catch (err) { console.error('Error fetching week data'); } }; -const canBeResend = async () => { - canResend.value = false; - - const filter = { - where: { - year: selectedDate.value.getFullYear(), - week: selectedWeekNumber.value, - }, - limit: 1, - }; - - const data = await fetchWorkerTimeControlMails(filter); - if (data.length) canResend.value = true; -}; - const setHours = (data) => { for (const weekDay of weekDays.value) { if (data) { From 22bc8f24142d9faeda7a60b20eeb628dcea553f4 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Thu, 12 Sep 2024 09:33:06 +0200 Subject: [PATCH 25/69] fix: refs #7323 show user name --- src/pages/Worker/Card/WorkerDescriptor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue index 154db1258..d04b5a3d3 100644 --- a/src/pages/Worker/Card/WorkerDescriptor.vue +++ b/src/pages/Worker/Card/WorkerDescriptor.vue @@ -197,7 +197,7 @@ const refetch = async () => await cardDescriptorRef.value.getData(); </div> </template> <template #body="{ entity }"> - <VnLv :label="t('worker.card.name')" :value="entity.user?.nickname" /> + <VnLv :label="t('worker.card.name')" :value="entity.user?.name" /> <VnLv :label="t('worker.card.email')" :value="entity.user?.email" copy /> <VnLv :label="t('worker.list.department')" From d92659289bbcc8e0faddaea3bc84ea38546554e6 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Thu, 12 Sep 2024 09:41:29 +0200 Subject: [PATCH 26/69] fix: refs #7323 add correct label --- src/i18n/locale/en.yml | 2 +- src/i18n/locale/es.yml | 2 +- src/pages/Worker/Card/WorkerDescriptor.vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index ba188a17a..c1f9a18ef 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -834,7 +834,7 @@ worker: newWorker: New worker card: workerId: Worker ID - name: Name + user: User email: Email phone: Phone mobile: Mobile diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index d0f14ec47..08fee22d2 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -837,7 +837,7 @@ worker: newWorker: Nuevo trabajador card: workerId: ID Trabajador - name: Nombre + user: Usuario email: Correo personal phone: Teléfono mobile: Móvil diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue index d04b5a3d3..0785be059 100644 --- a/src/pages/Worker/Card/WorkerDescriptor.vue +++ b/src/pages/Worker/Card/WorkerDescriptor.vue @@ -197,7 +197,7 @@ const refetch = async () => await cardDescriptorRef.value.getData(); </div> </template> <template #body="{ entity }"> - <VnLv :label="t('worker.card.name')" :value="entity.user?.name" /> + <VnLv :label="t('worker.card.user')" :value="entity.user?.name" /> <VnLv :label="t('worker.card.email')" :value="entity.user?.email" copy /> <VnLv :label="t('worker.list.department')" From 59f6913a74ec636523a53ed42d8eb4b9a506cc54 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Thu, 12 Sep 2024 09:43:08 +0200 Subject: [PATCH 27/69] fix: refs #7323 add correct label --- src/i18n/locale/en.yml | 1 + src/i18n/locale/es.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index c1f9a18ef..79eec7d5a 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -835,6 +835,7 @@ worker: card: workerId: Worker ID user: User + name: Name email: Email phone: Phone mobile: Mobile diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 08fee22d2..23ac93e3d 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -838,6 +838,7 @@ worker: card: workerId: ID Trabajador user: Usuario + name: Nombre email: Correo personal phone: Teléfono mobile: Móvil From 994197568320ff2f98592eae2543dafdd8f9bce0 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 08:07:53 +0000 Subject: [PATCH 28/69] fix: infiniteScroll --- src/components/ui/VnPaginate.vue | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index 441a8ff48..eb9828bc7 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -224,20 +224,27 @@ defineExpose({ fetch, addFilter, paginate }); v-bind="$attrs" > <slot name="body" :rows="store.data"></slot> - <div v-if="isLoading" class="info-row q-pa-md text-center"> + <div v-if="isLoading" class="spinner info-row q-pa-md text-center"> <QSpinner color="primary" size="md" /> </div> </QInfiniteScroll> </template> <style lang="scss" scoped> -.info-row { - width: 100%; - - h5 { - margin: 0; + .spinner { + z-index: 1; + align-content: end; + position: absolute; + bottom: 0; + left: 0; + } + .info-row { + width: 100%; + + h5 { + margin: 0; + } } -} </style> <i18n> From 3892df250cc87c166eb6b4dd71d0b05b2bcb1527 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 08:53:46 +0000 Subject: [PATCH 29/69] fix: #5938 grouped filter --- src/pages/Ticket/TicketFutureFilter.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Ticket/TicketFutureFilter.vue b/src/pages/Ticket/TicketFutureFilter.vue index bb597a525..6345f62b3 100644 --- a/src/pages/Ticket/TicketFutureFilter.vue +++ b/src/pages/Ticket/TicketFutureFilter.vue @@ -153,7 +153,7 @@ onMounted(async () => { :label="t('params.state')" v-model="params.state" :options="stateOptions" - option-value="code" + option-value="id" option-label="name" @update:model-value="searchFn()" dense @@ -169,7 +169,7 @@ onMounted(async () => { :label="t('params.futureState')" v-model="params.futureState" :options="stateOptions" - option-value="code" + option-value="id" option-label="name" @update:model-value="searchFn()" dense From c7adb919121d785ba8f5b1a25b82eedad4421db7 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 09:56:37 +0000 Subject: [PATCH 30/69] feat: use disableInifiniteScroll property --- src/pages/Customer/components/CustomerSummaryTable.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/Customer/components/CustomerSummaryTable.vue b/src/pages/Customer/components/CustomerSummaryTable.vue index 87e4cffa7..374769a57 100644 --- a/src/pages/Customer/components/CustomerSummaryTable.vue +++ b/src/pages/Customer/components/CustomerSummaryTable.vue @@ -151,6 +151,7 @@ const setShippedColor = (date) => { :disable-option="{ card: true, table: true }" limit="5" class="full-width" + :disable-infinite-scroll="true" > <template #column-nickname="{ row }"> <span class="link"> From c22f8f1069882a17c9ccc1ab85a213549d102396 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 09:57:31 +0000 Subject: [PATCH 31/69] fix: stop call back event hasMoreData --- src/components/VnTable/VnTable.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 0ed3de261..689be76ee 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -369,7 +369,7 @@ function handleOnDataSaved(_) { @on-fetch="(...args) => emit('onFetch', ...args)" :search-url="searchUrl" :disable-infinite-scroll=" - $attrs['disableInfiniteScroll'] ? isTableMode : disableInfiniteScroll + $attrs['disableInfiniteScroll'] ? isTableMode : !disableInfiniteScroll " @save-changes="reload" :has-sub-toolbar="$props.hasSubToolbar ?? isEditable" From a3afe790b942e0154cf6b1fc720156d223a62716 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 12:00:07 +0200 Subject: [PATCH 32/69] fix: CustomerGreuges --- src/pages/Customer/Card/CustomerGreuges.vue | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/pages/Customer/Card/CustomerGreuges.vue b/src/pages/Customer/Card/CustomerGreuges.vue index 1c78392e7..1d8b8585f 100644 --- a/src/pages/Customer/Card/CustomerGreuges.vue +++ b/src/pages/Customer/Card/CustomerGreuges.vue @@ -5,10 +5,10 @@ import { useRoute } from 'vue-router'; import { toCurrency } from 'src/filters'; import { toDateTimeFormat } from 'src/filters/date'; import VnTable from 'components/VnTable/VnTable.vue'; - +import FetchData from 'components/FetchData.vue'; +const entityId = computed(() => route.params.id); const { t } = useI18n(); const route = useRoute(); -const rows = ref([]); const totalAmount = ref(); const tableRef = ref(); const filter = computed(() => { @@ -28,7 +28,7 @@ const filter = computed(() => { }, ], where: { - clientFk: route.params.id, + clientFk: entityId, }, }; }); @@ -84,14 +84,14 @@ const columns = computed(() => [ create: true, }, ]); - -const setRows = (data) => { - rows.value = data; - totalAmount.value = data.reduce((acc, { amount = 0 }) => acc + amount, 0); -}; </script> <template> + <FetchData + :url="`Greuges/${entityId}/sumAmount`" + auto-load + @on-fetch="({ sumAmount }) => (totalAmount = sumAmount)" + ></FetchData> <VnTable ref="tableRef" data-key="Greuges" @@ -104,7 +104,6 @@ const setRows = (data) => { :is-editable="false" :use-model="true" :column-search="false" - @on-fetch="(data) => setRows(data)" :disable-option="{ card: true }" :create="{ urlCreate: `Greuges`, From e5056c45c0c15e056e89b773a85cfddd24bce221 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Thu, 12 Sep 2024 12:31:00 +0200 Subject: [PATCH 33/69] fix: refs #7500 fixed showing images wrongly --- src/components/common/VnDmsList.vue | 28 +++++++++++++++------------- src/components/ui/VnImg.vue | 3 +-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue index c0e8ac43b..ea19bf25d 100644 --- a/src/components/common/VnDmsList.vue +++ b/src/components/common/VnDmsList.vue @@ -93,19 +93,21 @@ const dmsFilter = { const columns = computed(() => [ { - align: 'left', - field: 'file', - label: t('globals.file'), + label: '', name: 'file', + align: 'left', component: VnImg, - props: (prop) => ({ - storage: 'dms', - collection: null, - size: null, - id: prop.row.file.split('.')[0], - token: token, - class: 'rounded', - }), + props: (prop) => { + return { + storage: 'dms', + collection: null, + resolution: null, + id: prop.row.file.split('.')[0], + token: token, + class: 'rounded', + ratio: 1, + }; + }, }, { align: 'left', @@ -397,10 +399,10 @@ defineExpose({ </QPageSticky> </template> <style scoped> -.q-gutter-y-ms { +/* .q-gutter-y-ms { display: grid; row-gap: 20px; -} +} */ .labelColor { color: var(--vn-label-color); } diff --git a/src/components/ui/VnImg.vue b/src/components/ui/VnImg.vue index 19ac8ce7f..834f9afdc 100644 --- a/src/components/ui/VnImg.vue +++ b/src/components/ui/VnImg.vue @@ -12,12 +12,10 @@ const $props = defineProps({ collection: { type: String, default: 'catalog', - required: false, }, resolution: { type: String, default: '200x200', - required: false, }, zoomResolution: { type: String, @@ -68,6 +66,7 @@ defineExpose({ v-bind="$attrs" spinner-color="primary" class="img_zoom" + :ratio="0" /> </QDialog> </template> From d00a88a3f44e908ed16c708fd7560ce77cc70474 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Thu, 12 Sep 2024 12:34:54 +0200 Subject: [PATCH 34/69] refactor: refs #7500 deleted useless code --- src/components/common/VnDmsList.vue | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue index ea19bf25d..b7ae449f9 100644 --- a/src/components/common/VnDmsList.vue +++ b/src/components/common/VnDmsList.vue @@ -399,10 +399,6 @@ defineExpose({ </QPageSticky> </template> <style scoped> -/* .q-gutter-y-ms { - display: grid; - row-gap: 20px; -} */ .labelColor { color: var(--vn-label-color); } From 44fd356d63ee78589a3902ba1891ec41dd5d39ad Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Thu, 12 Sep 2024 13:19:31 +0200 Subject: [PATCH 35/69] feat: refs #7828 useAcl & cherry pick mail data worker --- src/pages/Worker/Card/WorkerTimeControl.vue | 63 +++++++-------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue index 2f66fbcc1..3893305a5 100644 --- a/src/pages/Worker/Card/WorkerTimeControl.vue +++ b/src/pages/Worker/Card/WorkerTimeControl.vue @@ -12,7 +12,6 @@ import WorkerTimeControlCalendar from 'pages/Worker/Card/WorkerTimeControlCalend import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; -import { useRole } from 'src/composables/useRole'; import { useAcl } from 'src/composables/useAcl'; import { useWeekdayStore } from 'src/stores/useWeekdayStore'; import { useStateStore } from 'stores/useStateStore'; @@ -63,13 +62,16 @@ const selectedCalendarDates = ref([]); const selectedDateFormatted = ref(toDateString(defaultDate.value)); const arrayData = useArrayData('workerData'); - +const acl = useAcl(); const worker = computed(() => arrayData.store?.data); - -const isHr = computed(() => useRole().hasAny(['hr'])); - -const canSend = computed(() => useAcl().hasAny('WorkerTimeControl', 'sendMail', 'WRITE')); - +const canSend = computed(() => + acl.hasAny([{ model: 'WorkerTimeControl', props: 'sendMail', accessType: 'WRITE' }]) +); +const canUpdate = computed(() => + acl.hasAny([ + { model: 'WorkerTimeControl', props: 'updateMailState', accessType: 'WRITE' }, + ]) +); const isHimself = computed(() => user.value.id === Number(route.params.id)); const columns = computed(() => { @@ -257,46 +259,25 @@ const fetchHours = async () => { } }; -const fetchWorkerTimeControlMails = async (filter) => { - try { - const { data } = await axios.get('WorkerTimeControlMails', { - params: { filter: JSON.stringify(filter) }, - }); - - return data; - } catch (err) { - console.error('Error fetching worker time control mails'); - } -}; - const fetchWeekData = async () => { + const where = { + year: selectedDate.value.getFullYear(), + week: selectedWeekNumber.value, + }; try { - const data = ( - await axios.get(`WorkerTimeControlMails/${route.params.id}/getWeeklyMail`, { - params: { - workerFk: route.params.id, - year: selectedDate.value.getFullYear(), - week: selectedWeekNumber.value, - }, + const mail = ( + await axios.get(`Workers/${route.params.id}/mail`, { + params: { filter: { where } }, }) - ).data; - if (!data.length) state.value = null; + ).data[0]; + if (!mail) state.value = null; else { - const [mail] = data; state.value = mail.state; reason.value = mail.reason; } canResend.value = !!( - await axios.get('WorkerTimeControlMails/count', { - filter: { - where: { - year: selectedDate.value.getFullYear(), - week: selectedWeekNumber.value, - limit: 1, - }, - }, - }) + await axios.get('WorkerTimeControlMails/count', { params: { where } }) ).data.count; } catch (err) { console.error('Error fetching week data'); @@ -443,7 +424,7 @@ onMounted(async () => { <div> <QBtnGroup push class="q-gutter-x-sm" flat> <QBtn - v-if="isHimself && state" + v-if="canUpdate && state" :label="t('Satisfied')" color="primary" type="submit" @@ -451,7 +432,7 @@ onMounted(async () => { @click="isSatisfied()" /> <QBtn - v-if="isHimself && state" + v-if="canUpdate && state" :label="t('Not satisfied')" color="primary" type="submit" @@ -462,7 +443,7 @@ onMounted(async () => { </QBtnGroup> <QBtnGroup push class="q-gutter-x-sm q-ml-none" flat> <QBtn - v-if="reason && state && (isHimself || isHr)" + v-if="reason && state && canUpdate" :label="t('Reason')" color="primary" type="submit" From cfdfc7f53100d2b2698cd3f36c0ab68639389ab1 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 13:19:37 +0200 Subject: [PATCH 36/69] fix: CustomerSamples --- src/components/VnTable/VnTable.vue | 7 +- src/components/ui/VnPaginate.vue | 9 ++- src/composables/usePrintService.js | 5 +- src/pages/Customer/Card/CustomerBalance.vue | 80 +++++++------------ .../components/CustomerSummaryTable.vue | 1 + .../Card/InvoiceOutDescriptorMenu.vue | 3 +- src/pages/Route/RouteList.vue | 19 +++-- src/pages/Ticket/TicketFutureFilter.vue | 4 +- 8 files changed, 54 insertions(+), 74 deletions(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 0ed3de261..d6008de0b 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -369,7 +369,7 @@ function handleOnDataSaved(_) { @on-fetch="(...args) => emit('onFetch', ...args)" :search-url="searchUrl" :disable-infinite-scroll=" - $attrs['disableInfiniteScroll'] ? isTableMode : disableInfiniteScroll + $attrs['disableInfiniteScroll'] ? isTableMode : !disableInfiniteScroll " @save-changes="reload" :has-sub-toolbar="$props.hasSubToolbar ?? isEditable" @@ -507,11 +507,8 @@ function handleOnDataSaved(_) { :key="index" :title="btn.title" :icon="btn.icon" - class="q-px-sm" + class="q-px-sm text-primary-light" flat - :class=" - btn.isPrimary ? 'text-primary-light' : 'color-vn-text ' - " :style="`visibility: ${ (btn.show && btn.show(row)) ?? true ? 'visible' : 'hidden' }`" diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index 441a8ff48..79a79c383 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -224,13 +224,20 @@ defineExpose({ fetch, addFilter, paginate }); v-bind="$attrs" > <slot name="body" :rows="store.data"></slot> - <div v-if="isLoading" class="info-row q-pa-md text-center"> + <div v-if="isLoading" class="spinner info-row q-pa-md text-center"> <QSpinner color="primary" size="md" /> </div> </QInfiniteScroll> </template> <style lang="scss" scoped> +.spinner { + z-index: 1; + align-content: end; + position: absolute; + bottom: 0; + left: 0; +} .info-row { width: 100%; diff --git a/src/composables/usePrintService.js b/src/composables/usePrintService.js index ff43c65a1..68a009d7b 100644 --- a/src/composables/usePrintService.js +++ b/src/composables/usePrintService.js @@ -16,7 +16,7 @@ export function usePrintService() { ); } - function openReport(path, params) { + function openReport(path, params, isNewTab = '_self') { if (typeof params === 'string') params = JSON.parse(params); params = Object.assign( { @@ -26,8 +26,7 @@ export function usePrintService() { ); const query = new URLSearchParams(params).toString(); - - window.open(`api/${path}?${query}`); + window.open(`api/${path}?${query}`, isNewTab); } return { diff --git a/src/pages/Customer/Card/CustomerBalance.vue b/src/pages/Customer/Card/CustomerBalance.vue index 70747bb3f..2a1991bbd 100644 --- a/src/pages/Customer/Card/CustomerBalance.vue +++ b/src/pages/Customer/Card/CustomerBalance.vue @@ -5,12 +5,12 @@ import { useRoute } from 'vue-router'; import { useAcl } from 'src/composables/useAcl'; import axios from 'axios'; import { useQuasar } from 'quasar'; +import FetchData from 'components/FetchData.vue'; import { toCurrency, toDate, toDateHourMin } from 'src/filters'; import { useState } from 'composables/useState'; import { useStateStore } from 'stores/useStateStore'; import { usePrintService } from 'composables/usePrintService'; -import { useSession } from 'composables/useSession'; import { useVnConfirm } from 'composables/useVnConfirm'; import VnTable from 'components/VnTable/VnTable.vue'; @@ -22,12 +22,10 @@ import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue'; const { openConfirmationModal } = useVnConfirm(); -const { sendEmail } = usePrintService(); +const { sendEmail, openReport } = usePrintService(); const { t } = useI18n(); const { hasAny } = useAcl(); - -const session = useSession(); -const tokenMultimedia = session.getTokenMultimedia(); +const currentBalance = ref({}); const quasar = useQuasar(); const route = useRoute(); const state = useState(); @@ -36,7 +34,7 @@ const user = state.getUser(); const clientRisk = ref([]); const tableRef = ref(); -const companyId = ref(); +const companyId = ref(user.value.companyFk); const companyLastId = ref(user.value.companyFk); const balances = ref([]); const vnFilterRef = ref({}); @@ -76,14 +74,14 @@ const companyFilterColumn = { const columns = computed(() => [ { - align: 'left', + align: 'right', name: 'payed', label: t('Date'), format: ({ payed }) => toDate(payed), cardVisible: true, }, { - align: 'left', + align: 'right', name: 'created', label: t('Creation date'), format: ({ created }) => toDateHourMin(created), @@ -91,11 +89,10 @@ const columns = computed(() => [ }, { align: 'left', - name: 'workerFk', label: t('Employee'), columnField: { component: 'userLink', - attrs: ({ row }) => ({ workerId: row.workerFk, tag: row.userName }), + attrs: ({ row }) => ({ workerId: row.workerFk, name: row.userName }), }, cardVisible: true, }, @@ -120,14 +117,14 @@ const columns = computed(() => [ isId: true, }, { - align: 'right', + align: 'left', name: 'credit', label: t('Havings'), format: ({ credit }) => credit && toCurrency(credit), cardVisible: true, }, { - align: 'right', + align: 'left', name: 'balance', label: t('Balance'), format: ({ balance }) => toCurrency(balance), @@ -166,41 +163,15 @@ const columns = computed(() => [ onBeforeMount(() => { stateStore.rightDrawer = true; - companyId.value = user.value.companyFk; }); -async function getClientRisk() { - const { data } = await axios.get(`clientRisks`, { - params: { - filter: JSON.stringify({ - include: { relation: 'company', scope: { fields: ['code'] } }, - where: { clientFk: route.params.id, companyFk: user.value.companyFk }, - }), - }, - }); - clientRisk.value = data; - return clientRisk.value; -} - -async function getCurrentBalance() { - const currentBalance = (await getClientRisk()).find((balance) => { - return balance.companyFk === companyId.value; - }); - return currentBalance && currentBalance.amount; -} - -async function onFetch(data) { - balances.value = []; - for (const [index, balance] of data.entries()) { - if (index === 0) { - balance.balance = await getCurrentBalance(); - continue; - } - const previousBalance = data[index - 1]; - balance.balance = - previousBalance?.balance - (previousBalance?.debit - previousBalance?.credit); +async function getCurrentBalance(data) { + for (const balance of data) { + currentBalance.value[balance.companyFk] = { + code: balance.company.code, + amount: balance.amount, + }; } - balances.value = data; } const showNewPaymentDialog = () => { @@ -215,19 +186,27 @@ const showNewPaymentDialog = () => { }; const showBalancePdf = ({ id }) => { - const url = `api/InvoiceOuts/${id}/download?access_token=${tokenMultimedia}`; - window.open(url, '_blank'); + openReport(`InvoiceOuts/${id}/download`, {}, '_blank'); }; </script> <template> + <FetchData + url="clientRisks" + :filter="{ + include: { relation: 'company', scope: { fields: ['code'] } }, + where: { clientFk: route.params.id, companyFk: companyId }, + }" + auto-load + @on-fetch="getCurrentBalance" + ></FetchData> <VnSubToolbar class="q-mb-md"> <template #st-data> <div class="column justify-center q-px-md q-py-sm"> <span class="text-bold">{{ t('Total by company') }}</span> - <div class="row justify-center" v-if="clientRisk?.length"> - {{ clientRisk[0].company.code }}: - {{ toCurrency(clientRisk[0].amount) }} + <div class="row justify-center"> + {{ currentBalance[companyId]?.code }}: + {{ toCurrency(currentBalance[companyId]?.amount) }} </div> </div> </template> @@ -253,7 +232,6 @@ const showBalancePdf = ({ id }) => { :right-search="false" :is-editable="false" :column-search="false" - @on-fetch="onFetch" :disable-option="{ card: true }" auto-load > @@ -262,7 +240,7 @@ const showBalancePdf = ({ id }) => { </template> <template #column-description="{ row }"> <div class="link" v-if="row.isInvoice"> - {{ row.description }} + {{ t('bill', { ref: row.description }) }} <InvoiceOutDescriptorProxy :id="row.description" /> </div> <span v-else class="q-pa-xs dotted rounded-borders" :title="row.description"> diff --git a/src/pages/Customer/components/CustomerSummaryTable.vue b/src/pages/Customer/components/CustomerSummaryTable.vue index 87e4cffa7..374769a57 100644 --- a/src/pages/Customer/components/CustomerSummaryTable.vue +++ b/src/pages/Customer/components/CustomerSummaryTable.vue @@ -151,6 +151,7 @@ const setShippedColor = (date) => { :disable-option="{ card: true, table: true }" limit="5" class="full-width" + :disable-infinite-scroll="true" > <template #column-nickname="{ row }"> <span class="link"> diff --git a/src/pages/InvoiceOut/Card/InvoiceOutDescriptorMenu.vue b/src/pages/InvoiceOut/Card/InvoiceOutDescriptorMenu.vue index 213e25b4a..08b21fb4a 100644 --- a/src/pages/InvoiceOut/Card/InvoiceOutDescriptorMenu.vue +++ b/src/pages/InvoiceOut/Card/InvoiceOutDescriptorMenu.vue @@ -41,8 +41,7 @@ const invoiceFormType = ref('pdf'); const defaultEmailAddress = ref($props.invoiceOutData.client?.email); const showInvoicePdf = () => { - const url = `api/InvoiceOuts/${$props.invoiceOutData.id}/download?access_token=${token}`; - window.open(url, '_blank'); + openReport(`InvoiceOuts/${$props.invoiceOutData.id}/download`, {}, '_blank'); }; const showInvoiceCsv = () => { diff --git a/src/pages/Route/RouteList.vue b/src/pages/Route/RouteList.vue index 7e2358236..1e20df99c 100644 --- a/src/pages/Route/RouteList.vue +++ b/src/pages/Route/RouteList.vue @@ -17,7 +17,9 @@ import RouteFilter from 'pages/Route/Card/RouteFilter.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnInputDate from 'components/common/VnInputDate.vue'; import VnTable from 'components/VnTable/VnTable.vue'; +import { usePrintService } from 'src/composables/usePrintService'; +const { openReport } = usePrintService(); const { t } = useI18n(); const { viewSummary } = useSummaryDialog(); const quasar = useQuasar(); @@ -235,18 +237,15 @@ const cloneRoutes = () => { const showRouteReport = () => { const ids = selectedRows.value.map((row) => row?.id); const idString = ids.join(','); - let url; - - if (selectedRows.value.length <= 1) { - url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getTokenMultimedia()}`; - } else { - const params = new URLSearchParams({ - access_token: session.getTokenMultimedia(), + let url = `Routes/${idString}/driver-route-pdf`; + let params = {}; + if (selectedRows.value.length >= 1) { + params = { id: idString, - }); - url = `api/Routes/downloadZip?${params.toString()}`; + }; + url = `Routes/downloadZip`; } - window.open(url, '_blank'); + openReport(url, params, '_blank'); }; function markAsServed() { diff --git a/src/pages/Ticket/TicketFutureFilter.vue b/src/pages/Ticket/TicketFutureFilter.vue index bb597a525..6345f62b3 100644 --- a/src/pages/Ticket/TicketFutureFilter.vue +++ b/src/pages/Ticket/TicketFutureFilter.vue @@ -153,7 +153,7 @@ onMounted(async () => { :label="t('params.state')" v-model="params.state" :options="stateOptions" - option-value="code" + option-value="id" option-label="name" @update:model-value="searchFn()" dense @@ -169,7 +169,7 @@ onMounted(async () => { :label="t('params.futureState')" v-model="params.futureState" :options="stateOptions" - option-value="code" + option-value="id" option-label="name" @update:model-value="searchFn()" dense From dcb8c5daad7821cc786aa69d5eb0bfdd77db3546 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Thu, 12 Sep 2024 13:27:28 +0200 Subject: [PATCH 37/69] fix: workerDms filter workerFk --- src/pages/Worker/Card/WorkerDms.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Worker/Card/WorkerDms.vue b/src/pages/Worker/Card/WorkerDms.vue index a4f7ef5a9..e2b62bc4f 100644 --- a/src/pages/Worker/Card/WorkerDms.vue +++ b/src/pages/Worker/Card/WorkerDms.vue @@ -10,6 +10,6 @@ const route = useRoute(); delete-model="WorkerDms" download-model="WorkerDms" default-dms-code="hhrrData" - filter="worker" + filter="wd.workerFk" /> </template> From 6adcaff5d8330420195f3119706148a420c6dab9 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Thu, 12 Sep 2024 16:48:39 +0200 Subject: [PATCH 38/69] fix: refs #7524 dynamic load --- src/pages/Claim/Card/ClaimDevelopment.vue | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/pages/Claim/Card/ClaimDevelopment.vue b/src/pages/Claim/Card/ClaimDevelopment.vue index f7e8131c6..61d9f5858 100644 --- a/src/pages/Claim/Card/ClaimDevelopment.vue +++ b/src/pages/Claim/Card/ClaimDevelopment.vue @@ -16,7 +16,6 @@ const claimReasons = ref([]); const claimResults = ref([]); const claimResponsibles = ref([]); const claimRedeliveries = ref([]); -const workers = ref([]); const selected = ref([]); const saveButtonRef = ref(); @@ -82,7 +81,9 @@ const columns = computed(() => [ label: t('Worker'), field: (row) => row.workerFk, sortable: true, - options: workers.value, + url: 'Workers/search', + where: { active: 1 }, + sortBy: 'name ASC', model: 'workerFk', optionValue: 'id', optionLabel: 'nickname', @@ -129,13 +130,6 @@ const columns = computed(() => [ @on-fetch="(data) => (claimRedeliveries = data)" auto-load /> - <FetchData - url="Workers/search" - :where="{ active: 1 }" - order="name ASC" - @on-fetch="(data) => (workers = data)" - auto-load - /> <CrudModel data-key="ClaimDevelopments" url="ClaimDevelopments" @@ -165,6 +159,9 @@ const columns = computed(() => [ > <VnSelect v-model="row[col.model]" + :url="col.url" + :where="col.where" + :sort-by="col.sortBy" :options="col.options" :option-value="col.optionValue" :option-label="col.optionLabel" From 5907fedcd68fdbe58c8c45b3a7f64bd2599f3660 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Thu, 12 Sep 2024 17:49:59 +0200 Subject: [PATCH 39/69] fix: refs #7524 test --- .../integration/claim/claimDevelopment.spec.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/cypress/integration/claim/claimDevelopment.spec.js b/test/cypress/integration/claim/claimDevelopment.spec.js index 903f58d4b..3b73a24d9 100755 --- a/test/cypress/integration/claim/claimDevelopment.spec.js +++ b/test/cypress/integration/claim/claimDevelopment.spec.js @@ -8,6 +8,8 @@ describe('ClaimDevelopment', () => { cy.viewport(1920, 1080); cy.login('developer'); cy.visit(`/#/claim/${claimId}/development`); + cy.intercept('GET', /\/api\/Workers\/search/).as('workers'); + cy.intercept('GET', /\/api\/Workers\/search/).as('workers'); cy.waitForElement('tbody'); }); @@ -32,10 +34,19 @@ describe('ClaimDevelopment', () => { }); it('should add and remove new line', () => { + cy.wait(['@workers', '@workers']); cy.addCard(); + cy.get(thirdRow).should('exist'); - const rowData = [false, 'Novato', 'Roces', 'Compradores', 'employeeNick', 'Tour']; + const rowData = [ + false, + 'Novato', + 'Roces', + 'Compradores', + 'administrativeNick', + 'Tour', + ]; cy.fillRow(thirdRow, rowData); cy.saveCard(); From 8fc7e3cfb45291a6b0d2ed0427b371413b6ade2e Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 20:43:50 +0200 Subject: [PATCH 40/69] fix: CustomerSamples --- src/pages/Customer/Card/CustomerSamples.vue | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/pages/Customer/Card/CustomerSamples.vue b/src/pages/Customer/Card/CustomerSamples.vue index 49697aab7..8e2ab92a0 100644 --- a/src/pages/Customer/Card/CustomerSamples.vue +++ b/src/pages/Customer/Card/CustomerSamples.vue @@ -1,7 +1,7 @@ <script setup> import { ref, computed } from 'vue'; import { useI18n } from 'vue-i18n'; -import { useRoute, useRouter } from 'vue-router'; +import { useRoute } from 'vue-router'; import { QBtn, useQuasar } from 'quasar'; @@ -13,7 +13,6 @@ import CustomerSamplesCreate from '../components/CustomerSamplesCreate.vue'; const { t } = useI18n(); const route = useRoute(); -const router = useRouter(); const filter = { include: [ @@ -42,7 +41,16 @@ const columns = computed(() => [ { align: 'left', label: t('Worker'), - name: 'worker', + columnField: { + component: 'userLink', + attrs: ({ row }) => { + return { + defaultName: true, + workerId: row?.user?.id, + name: row?.user?.name, + }; + }, + }, }, { align: 'left', @@ -73,7 +81,9 @@ const tableRef = ref(); :columns="columns" :pagination="{ rowsPerPage: 12 }" :disable-option="{ card: true }" + :right-search="false" :rows="rows" + :order="['created DESC']" class="full-width q-mt-md" row-key="id" :create="false" From 24f4af712ec3ab8e680a32b58619f58d649ef33a Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 20:59:35 +0200 Subject: [PATCH 41/69] fix: CustomerMandates --- src/pages/Customer/Card/CustomerMandates.vue | 108 +++++-------------- 1 file changed, 27 insertions(+), 81 deletions(-) diff --git a/src/pages/Customer/Card/CustomerMandates.vue b/src/pages/Customer/Card/CustomerMandates.vue index 7af3e5828..248515b4a 100644 --- a/src/pages/Customer/Card/CustomerMandates.vue +++ b/src/pages/Customer/Card/CustomerMandates.vue @@ -1,20 +1,19 @@ <script setup> -import { computed, ref } from 'vue'; +import { computed } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRoute } from 'vue-router'; import { toDateTimeFormat } from 'src/filters/date'; -import FetchData from 'components/FetchData.vue'; +import VnTable from 'src/components/VnTable/VnTable.vue'; +import { dashIfEmpty } from 'src/filters'; const { t } = useI18n(); const route = useRoute(); -const rows = ref([]); - const filter = { include: [ - { relation: 'mandateType', scope: { fields: ['id', 'name'] } }, + { relation: 'mandateType', scope: { fields: ['id', 'code'] } }, { relation: 'company', scope: { fields: ['id', 'code'] } }, ], where: { clientFk: route.params.id }, @@ -22,114 +21,61 @@ const filter = { limit: 20, }; -const tableColumnComponents = { - id: { - component: 'span', - props: () => {}, - event: () => {}, - }, - company: { - component: 'span', - props: () => {}, - event: () => {}, - }, - type: { - component: 'span', - props: () => {}, - event: () => {}, - }, - registerDate: { - component: 'span', - props: () => {}, - event: () => {}, - }, - endDate: { - component: 'span', - props: () => {}, - event: () => {}, - }, -}; - const columns = computed(() => [ { align: 'left', - field: 'id', - label: t('Id'), name: 'id', + label: t('globals.id'), + field: 'id', + isId: true, }, { align: 'left', - field: (row) => row.company.code, - label: t('Company'), + cardVisible: true, + format: ({ company }) => company.code, + label: t('globals.company'), name: 'company', }, { align: 'left', - field: (row) => row.mandateType.name, - label: t('Type'), + cardVisible: true, + format: ({ mandateType }) => mandateType.code, + label: t('globals.type'), name: 'type', }, { align: 'left', - field: 'created', + cardVisible: true, label: t('Register date'), - name: 'registerDate', - format: (value) => toDateTimeFormat(value), + name: 'created', + format: ({ created }) => toDateTimeFormat(created), }, { - align: 'left', - field: 'finished', + align: 'right', + cardVisible: true, + name: 'finished', label: t('End date'), - name: 'endDate', - format: (value) => (value ? toDateTimeFormat(value) : '-'), + format: ({ finished }) => dashIfEmpty(toDateTimeFormat(finished)), }, ]); </script> <template> - <FetchData - :filter="filter" - @on-fetch="(data) => (rows = data)" - auto-load - url="Mandates" - /> - <QPage class="column items-center q-pa-md"> - <QTable + <VnTable + :filter="filter" + auto-load + url="Mandates" :columns="columns" - :pagination="{ rowsPerPage: 12 }" - :rows="rows" class="full-width q-mt-md" - row-key="id" - v-if="rows?.length" - > - <template #body-cell="props"> - <QTd :props="props"> - <QTr :props="props" class="cursor-pointer"> - <component - :is="tableColumnComponents[props.col.name].component" - @click="tableColumnComponents[props.col.name].event(props)" - class="rounded-borders q-pa-sm" - v-bind="tableColumnComponents[props.col.name].props(props)" - > - {{ props.value }} - </component> - </QTr> - </QTd> - </template> - </QTable> - - <h5 class="flex justify-center color-vn-label" v-else> - {{ t('globals.noResults') }} - </h5> + :right-search="false" + :row-click="false" + /> </QPage> </template> <i18n> es: - Id: Id - Company: Empresa - Type: Tipo Register date: Fecha alta End date: Fecha baja </i18n> From 70d0132710a4f4075216642399edf94f70de4f6b Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 21:03:19 +0200 Subject: [PATCH 42/69] fix: CustomerWebPayment --- src/pages/Customer/Card/CustomerWebPayment.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Customer/Card/CustomerWebPayment.vue b/src/pages/Customer/Card/CustomerWebPayment.vue index 13ec6b128..482582078 100644 --- a/src/pages/Customer/Card/CustomerWebPayment.vue +++ b/src/pages/Customer/Card/CustomerWebPayment.vue @@ -5,7 +5,7 @@ import { useRoute } from 'vue-router'; import axios from 'axios'; -import { toCurrency, toDateHourMinSec } from 'src/filters'; +import { toCurrency, toDateHourMin } from 'src/filters'; import CustomerCloseIconTooltip from '../components/CustomerCloseIconTooltip.vue'; import CustomerCheckIconTooltip from '../components/CustomerCheckIconTooltip.vue'; @@ -74,7 +74,7 @@ const columns = computed(() => [ field: 'created', label: t('Date'), name: 'date', - format: (value) => toDateHourMinSec(value), + format: (value) => toDateHourMin(value), }, { align: 'left', From 39f2deafc4b879426075095e28167642fd8845aa Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 21:08:41 +0200 Subject: [PATCH 43/69] fix: CustomerCreditOpinion workerDescriptor --- src/pages/Customer/Card/CustomerCreditOpinion.vue | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pages/Customer/Card/CustomerCreditOpinion.vue b/src/pages/Customer/Card/CustomerCreditOpinion.vue index 6a839ff3f..92fef1d76 100644 --- a/src/pages/Customer/Card/CustomerCreditOpinion.vue +++ b/src/pages/Customer/Card/CustomerCreditOpinion.vue @@ -44,7 +44,7 @@ const columns = computed(() => [ { align: 'right', field: 'rating', - label: t('Rating'), + label: t('customer.summary.rating'), name: 'rating', create: true, columnCreate: { @@ -56,7 +56,7 @@ const columns = computed(() => [ align: 'right', field: 'recommendedCredit', format: ({ recommendedCredit }) => toCurrency(recommendedCredit), - label: t('Recommended credit'), + label: t('customer.summary.recommendCredit'), name: 'recommendedCredit', create: true, columnCreate: { @@ -89,8 +89,8 @@ const columns = computed(() => [ }" > <template #column-employee="{ row }"> - <span class="link" @click.stop>{{ row.worker.user.nickname }}</span> - <WorkerDescriptorProxy :id="row.clientFk" /> + <span class="link">{{ row.worker.user.nickname }}</span> + <WorkerDescriptorProxy :id="row.worker.id" /> </template> </VnTable> <!-- <QTable @@ -113,7 +113,6 @@ const columns = computed(() => [ <i18n> es: - Rating: Clasificación Recommended credit: Crédito recomendado Since: Desde Employee: Empleado From 54fc7f6394e2f7bdc2698145c424c948fe0d4fdd Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 21:10:06 +0200 Subject: [PATCH 44/69] fix: CustomerRecovery transalate label --- src/pages/Customer/Card/CustomerRecoveries.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Customer/Card/CustomerRecoveries.vue b/src/pages/Customer/Card/CustomerRecoveries.vue index 3ea8998e9..48576ca20 100644 --- a/src/pages/Customer/Card/CustomerRecoveries.vue +++ b/src/pages/Customer/Card/CustomerRecoveries.vue @@ -92,7 +92,7 @@ function setFinished(id) { :disable-option="{ card: true }" :create="{ urlCreate: 'Recoveries', - title: 'New recovery', + title: t('New recovery'), onDataSaved: () => tableRef.reload(), formInitialData: { clientFk: route.params.id, started: Date.vnNew() }, }" From 6e784bb290d0f472f4e1d2c06a8f92dda8f45b59 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 21:11:51 +0200 Subject: [PATCH 45/69] fix: address-create i18n --- src/i18n/locale/en.yml | 1 + src/i18n/locale/es.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index d29b864b9..213d302cb 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -133,6 +133,7 @@ globals: fiscalData: Fiscal data billingData: Billing data consignees: Consignees + 'address-create': New address notes: Notes credits: Credits greuges: Greuges diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 3d905509d..72d4fb1b1 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -136,6 +136,7 @@ globals: fiscalData: Datos fiscales billingData: Forma de pago consignees: Consignatarios + 'address-create': Nuevo consignatario notes: Notas credits: Créditos greuges: Greuges From fa408dc2267405062175a77c3d561b3a0fae4302 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 21:20:30 +0200 Subject: [PATCH 46/69] fix: CustomerAddress mobile --- src/pages/Customer/Card/CustomerAddress.vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/Customer/Card/CustomerAddress.vue b/src/pages/Customer/Card/CustomerAddress.vue index a9e7affef..d76707079 100644 --- a/src/pages/Customer/Card/CustomerAddress.vue +++ b/src/pages/Customer/Card/CustomerAddress.vue @@ -179,6 +179,13 @@ const toCustomerAddressEdit = (addressId) => { {{ item.postalCode }} - {{ item.city }}, {{ setProvince(item.provinceFk) }} </div> + <div> + {{ item.phone }} + <span v-if="item.mobile" + >, + {{ item.mobile }} + </span> + </div> <div class="flex"> <QCheckbox :label="t('Is equalizated')" From aca13d91196ed8b0b884a211a2323d013e4c6cd3 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 12 Sep 2024 21:26:28 +0200 Subject: [PATCH 47/69] fix: CustomerBillingData --- .../Customer/Card/CustomerBillingData.vue | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/pages/Customer/Card/CustomerBillingData.vue b/src/pages/Customer/Card/CustomerBillingData.vue index 5eeaea50b..a968d0ec8 100644 --- a/src/pages/Customer/Card/CustomerBillingData.vue +++ b/src/pages/Customer/Card/CustomerBillingData.vue @@ -3,7 +3,6 @@ import { ref } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRoute } from 'vue-router'; -import FetchData from 'components/FetchData.vue'; import FormModel from 'components/FormModel.vue'; import VnRow from 'components/ui/VnRow.vue'; import VnInput from 'src/components/common/VnInput.vue'; @@ -14,8 +13,6 @@ import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue'; const { t } = useI18n(); const route = useRoute(); -const payMethods = ref([]); -const bankEntitiesOptions = ref([]); const bankEntitiesRef = ref(null); const filter = { @@ -31,15 +28,6 @@ const getBankEntities = (data, formData) => { </script> <template> - <FetchData @on-fetch="(data) => (payMethods = data)" auto-load url="PayMethods" /> - <FetchData - ref="bankEntitiesRef" - @on-fetch="(data) => (bankEntitiesOptions = data)" - :filter="filter" - auto-load - url="BankEntities" - /> - <FormModel :url-update="`Clients/${route.params.id}`" :url="`Clients/${route.params.id}/getCard`" @@ -49,8 +37,9 @@ const getBankEntities = (data, formData) => { <template #form="{ data, validate }"> <VnRow> <VnSelect + auto-load + url="PayMethods" :label="t('Billing data')" - :options="payMethods" hide-selected option-label="name" option-value="id" @@ -69,7 +58,10 @@ const getBankEntities = (data, formData) => { </VnInput> <VnSelectDialog :label="t('Swift / BIC')" - :options="bankEntitiesOptions" + ref="bankEntitiesRef" + :filter="filter" + auto-load + url="BankEntities" :acls="[{ model: 'BankEntity', props: '*', accessType: 'WRITE' }]" :rules="validate('Worker.bankEntity')" hide-selected From 58be11df046f33259a794effec4bc84b9e0728b0 Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Fri, 13 Sep 2024 10:13:03 +0200 Subject: [PATCH 48/69] chore: refs #7828 fix e2e --- test/cypress/integration/ticket/ticketDescriptor.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cypress/integration/ticket/ticketDescriptor.spec.js b/test/cypress/integration/ticket/ticketDescriptor.spec.js index 516b0f13d..8192b7c7c 100644 --- a/test/cypress/integration/ticket/ticketDescriptor.spec.js +++ b/test/cypress/integration/ticket/ticketDescriptor.spec.js @@ -5,7 +5,7 @@ describe('Ticket descriptor', () => { const warehouseValue = ':nth-child(1) > :nth-child(6) > .value > span'; const summaryHeader = '.summaryHeader > div'; const weight = 25; - const weightValue = ':nth-child(10) > .value > span'; + const weightValue = '.summaryBody.row :nth-child(1) > :nth-child(9) > .value > span'; beforeEach(() => { cy.login('developer'); cy.viewport(1920, 1080); From 5796bc9c0a7e0dc27378b1b053eded6c07a53bbb Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Fri, 13 Sep 2024 10:32:40 +0200 Subject: [PATCH 49/69] fix: emit:updateModelValue --- src/components/common/VnLocation.vue | 4 +++ .../vnComponent/vnLocation.spec.js | 32 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/components/common/VnLocation.vue b/src/components/common/VnLocation.vue index e95d5a043..b6cbfbafd 100644 --- a/src/components/common/VnLocation.vue +++ b/src/components/common/VnLocation.vue @@ -20,6 +20,9 @@ const modelValue = ref( function showLabel(data) { return `${data.code} - ${data.town}(${data.province}), ${data.country}`; } +const handleModelValue = (data) => { + emit('update:model-value', data); +}; </script> <template> <VnSelectDialog @@ -29,6 +32,7 @@ function showLabel(data) { (opt) => (typeof modelValue === 'string' ? modelValue : showLabel(opt)) " url="Postcodes/filter" + @update:model-value="handleModelValue" :use-like="false" :label="t('Location')" :placeholder="t('search_by_postalcode')" diff --git a/test/cypress/integration/vnComponent/vnLocation.spec.js b/test/cypress/integration/vnComponent/vnLocation.spec.js index 614b93a8a..8c187cc7e 100644 --- a/test/cypress/integration/vnComponent/vnLocation.spec.js +++ b/test/cypress/integration/vnComponent/vnLocation.spec.js @@ -33,11 +33,40 @@ describe('VnLocation', () => { cy.login('developer'); cy.visit('/#/supplier/567/fiscal-data', { timeout: 7000 }); cy.waitForElement('.q-form'); - cy.get(createLocationButton).click(); }); + it('Fin by postalCode', () => { + const postCode = '46600'; + const firstOption = '[role="listbox"] .q-item:nth-child(1)'; + + cy.get(inputLocation).click(); + cy.get(inputLocation).clear(); + cy.get(inputLocation).type(postCode); + cy.get(locationOptions).should('have.length.at.least', 2); + cy.get(firstOption).click(); + cy.get('.q-btn-group > .q-btn--standard > .q-btn__content > .q-icon').click(); + cy.reload(); + cy.waitForElement('.q-form'); + // cy.get('[href="#/supplier/567/basic-data"] > .q-item__section--main').click(); + // cy.get( + // '[href="#/supplier/567/fiscal-data"] > .q-item__section--main' + // ).click(); + cy.get(inputLocation).should( + 'have.value', + '46600 - Valencia(Province one), España' + ); + + // cy.get('.q-form > .q-card > .vn-row:nth-child(6)') + // .find('input') + // .invoke('val') + // .then((text) => { + // expect(text).to.contain('46600 - Valencia(Province one), España'); + // }); + }); + it('Create postCode', () => { const postCode = '1234475'; const province = 'Valencia'; + cy.get(createLocationButton).click(); cy.get('.q-card > h1').should('have.text', 'New postcode'); cy.get(dialogInputs).eq(0).clear(); cy.get(dialogInputs).eq(0).type(postCode); @@ -54,6 +83,7 @@ describe('VnLocation', () => { it('Create city', () => { const postCode = '9011'; const province = 'Saskatchew'; + cy.get(createLocationButton).click(); cy.get(dialogInputs).eq(0).type(postCode); // city create button cy.get( From a56dc7aa089c2b46d37bb92aa2c7279316f93b07 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Fri, 13 Sep 2024 10:33:08 +0200 Subject: [PATCH 50/69] test: fix test --- .../integration/vnComponent/vnLocation.spec.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/cypress/integration/vnComponent/vnLocation.spec.js b/test/cypress/integration/vnComponent/vnLocation.spec.js index 8c187cc7e..3533a3c1f 100644 --- a/test/cypress/integration/vnComponent/vnLocation.spec.js +++ b/test/cypress/integration/vnComponent/vnLocation.spec.js @@ -46,21 +46,10 @@ describe('VnLocation', () => { cy.get('.q-btn-group > .q-btn--standard > .q-btn__content > .q-icon').click(); cy.reload(); cy.waitForElement('.q-form'); - // cy.get('[href="#/supplier/567/basic-data"] > .q-item__section--main').click(); - // cy.get( - // '[href="#/supplier/567/fiscal-data"] > .q-item__section--main' - // ).click(); cy.get(inputLocation).should( 'have.value', '46600 - Valencia(Province one), España' ); - - // cy.get('.q-form > .q-card > .vn-row:nth-child(6)') - // .find('input') - // .invoke('val') - // .then((text) => { - // expect(text).to.contain('46600 - Valencia(Province one), España'); - // }); }); it('Create postCode', () => { From 48a5c15b9d8a466676c4b069a0e67b41f4b5c14c Mon Sep 17 00:00:00 2001 From: jorgep <jorgep@verdnatura.es> Date: Fri, 13 Sep 2024 10:54:09 +0200 Subject: [PATCH 51/69] feat: refs #7828 create axios instance which no manage errors --- src/boot/axios.js | 8 ++++++-- src/pages/Worker/Card/WorkerTimeControl.vue | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/boot/axios.js b/src/boot/axios.js index 9b32275bd..99a163cca 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -5,8 +5,10 @@ import useNotify from 'src/composables/useNotify.js'; const session = useSession(); const { notify } = useNotify(); +const baseUrl = '/api/'; -axios.defaults.baseURL = '/api/'; +axios.defaults.baseURL = baseUrl; +const axiosNoError = axios.create({ baseURL: baseUrl }); const onRequest = (config) => { const token = session.getToken(); @@ -79,5 +81,7 @@ const onResponseError = (error) => { axios.interceptors.request.use(onRequest, onRequestError); axios.interceptors.response.use(onResponse, onResponseError); +axiosNoError.interceptors.request.use(onRequest); +axiosNoError.interceptors.response.use(onResponse); -export { onRequest, onResponseError }; +export { onRequest, onResponseError, axiosNoError }; diff --git a/src/pages/Worker/Card/WorkerTimeControl.vue b/src/pages/Worker/Card/WorkerTimeControl.vue index 3893305a5..9ae91f8ce 100644 --- a/src/pages/Worker/Card/WorkerTimeControl.vue +++ b/src/pages/Worker/Card/WorkerTimeControl.vue @@ -2,6 +2,7 @@ import { useI18n } from 'vue-i18n'; import { useRoute } from 'vue-router'; import { onMounted, ref, computed, onBeforeMount, nextTick, reactive } from 'vue'; +import { axiosNoError } from 'src/boot/axios'; import FetchData from 'components/FetchData.vue'; import WorkerTimeHourChip from 'pages/Worker/Card/WorkerTimeHourChip.vue'; @@ -266,10 +267,11 @@ const fetchWeekData = async () => { }; try { const mail = ( - await axios.get(`Workers/${route.params.id}/mail`, { + await axiosNoError.get(`Workers/${route.params.id}/mail`, { params: { filter: { where } }, }) ).data[0]; + if (!mail) state.value = null; else { state.value = mail.state; @@ -277,7 +279,7 @@ const fetchWeekData = async () => { } canResend.value = !!( - await axios.get('WorkerTimeControlMails/count', { params: { where } }) + await axiosNoError.get('WorkerTimeControlMails/count', { params: { where } }) ).data.count; } catch (err) { console.error('Error fetching week data'); From 0f604ea8b5eaf3485a4678326aa5e327f9154a81 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Fri, 13 Sep 2024 11:34:45 +0200 Subject: [PATCH 52/69] fix: refs #7500 fixed e2e test --- test/cypress/integration/entry/entryDms.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cypress/integration/entry/entryDms.spec.js b/test/cypress/integration/entry/entryDms.spec.js index ed4a3d79c..47dcdba9e 100644 --- a/test/cypress/integration/entry/entryDms.spec.js +++ b/test/cypress/integration/entry/entryDms.spec.js @@ -23,7 +23,7 @@ describe('EntryDms', () => { expect(value).to.have.length(newFileTd++); const newRowSelector = `tbody > :nth-child(${newFileTd})`; cy.waitForElement(newRowSelector); - cy.validateRow(newRowSelector, [u, u, u, u, 'ENTRADA ID 1']); + cy.validateRow(newRowSelector, [u, u, u, u, u, 'ENTRADA ID 1']); //Edit new dms const newDescription = 'entry id 1 modified'; @@ -38,7 +38,7 @@ describe('EntryDms', () => { cy.saveCard(); cy.reload(); - cy.validateRow(newRowSelector, [u, u, u, u, newDescription]); + cy.validateRow(newRowSelector, [u, u, u, u, u, newDescription]); }); }); }); From eca34e2c0fb1eef9d4ab4e2d86d4e952d61766bd Mon Sep 17 00:00:00 2001 From: guillermo <guillermo@verdnatura.es> Date: Fri, 13 Sep 2024 14:57:33 +0200 Subject: [PATCH 53/69] feat: refs #7644 Icon --- src/pages/Entry/EntryBuysTableDialog.vue | 4 ++-- src/pages/Entry/locale/en.yml | 2 +- src/pages/Entry/locale/es.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/Entry/EntryBuysTableDialog.vue b/src/pages/Entry/EntryBuysTableDialog.vue index 9a76770aa..0f9be6298 100644 --- a/src/pages/Entry/EntryBuysTableDialog.vue +++ b/src/pages/Entry/EntryBuysTableDialog.vue @@ -116,7 +116,7 @@ const entriesTableColumns = computed(() => [ {{ col.value }} </QTd> <QBtn - icon="print" + icon="visibility" v-if="props.row.stickers > 0" :loading="isLoading" @click=" @@ -126,7 +126,7 @@ const entriesTableColumns = computed(() => [ " unelevated > - <QTooltip>{{ t('printLabel') }}</QTooltip> + <QTooltip>{{ t('viewLabel') }}</QTooltip> </QBtn> </QTr> </template> diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml index f0965b097..a9faa814b 100644 --- a/src/pages/Entry/locale/en.yml +++ b/src/pages/Entry/locale/en.yml @@ -11,4 +11,4 @@ shipped: Shipped fromShipped: Shipped(from) toShipped: Shipped(to) printLabels: Print stickers -printLabel: Print sticker +viewLabel: View sticker diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml index aba04571e..eb1e3f88a 100644 --- a/src/pages/Entry/locale/es.yml +++ b/src/pages/Entry/locale/es.yml @@ -15,4 +15,4 @@ shipped: F. salida fromShipped: F. salida(desde) toShipped: F. salida(hasta) printLabels: Imprimir etiquetas -printLabel: Imprimir etiqueta +viewLabel: Ver etiqueta From 6e6af0af8085fb1e82da7f3c3c17620ba2ecf0e7 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Fri, 13 Sep 2024 15:16:40 +0200 Subject: [PATCH 54/69] perf: improve style --- src/pages/Item/ItemFixedPrice.vue | 110 ++++++++++++------------------ 1 file changed, 44 insertions(+), 66 deletions(-) diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue index d91b5189e..bd8c4b78c 100644 --- a/src/pages/Item/ItemFixedPrice.vue +++ b/src/pages/Item/ItemFixedPrice.vue @@ -76,16 +76,8 @@ const columns = computed(() => [ name: 'rate2', ...defaultColumnAttrs, cardVisible: true, - columnField: { - class: 'expand', - component: 'input', - type: 'number', - }, - columnFilter: { - class: 'expand', - component: 'input', - type: 'number', - }, + component: 'input', + type: 'number', }, { label: t('item.fixedPrice.packingPrice'), @@ -93,35 +85,18 @@ const columns = computed(() => [ name: 'rate3', ...defaultColumnAttrs, cardVisible: true, - columnField: { - class: 'expand', - component: 'input', - type: 'number', - }, - columnFilter: { - class: 'expand', - component: 'input', - type: 'number', - }, + component: 'input', + type: 'number', }, { label: t('item.fixedPrice.minPrice'), field: 'minPrice', - columnClass: 'shrink', name: 'minPrice', ...defaultColumnAttrs, cardVisible: true, - columnField: { - class: 'expand', - component: 'input', - type: 'number', - }, - columnFilter: { - class: 'expand', - component: 'input', - type: 'number', - }, + component: 'input', + type: 'number', }, { label: t('item.fixedPrice.started'), @@ -162,16 +137,9 @@ const columns = computed(() => [ name: 'warehouseFk', ...defaultColumnAttrs, columnClass: 'shrink', - columnFilter: { - component: 'select', - }, - columnField: { - component: 'select', - class: 'expand', - }, - attrs: { - options: warehousesOptions, - }, + component: 'select', + + options: warehousesOptions, }, { align: 'right', @@ -518,29 +486,35 @@ function handleOnDataSave({ CrudModelRef }) { </span> <span class="subName">{{ row.subName }}</span> <ItemDescriptorProxy :id="row.itemFk" /> - <FetchedTags style="width: max-content; max-width: 220px" :item="row" /> + <FetchedTags :item="row" /> </template> <template #column-rate2="props"> - <VnInput - mask="###.##" - v-model.number="props.row.rate2" - v-on="getRowUpdateInputEvents(props)" - > - <template #append>€</template> - </VnInput> + <QTd class="col"> + <VnInput + type="currency" + style="width: 75px" + v-model.number="props.row.rate2" + v-on="getRowUpdateInputEvents(props)" + > + <template #append>€</template> + </VnInput> + </QTd> </template> <template #column-rate3="props"> - <VnInput - mask="###.##" - v-model.number="props.row.rate3" - v-on="getRowUpdateInputEvents(props)" - > - <template #append>€</template> - </VnInput> + <QTd class="col"> + <VnInput + style="width: 75px" + type="currency" + v-model.number="props.row.rate3" + v-on="getRowUpdateInputEvents(props)" + > + <template #append>€</template> + </VnInput> + </QTd> </template> <template #column-minPrice="props"> <QTd class="col"> - <div class="row" style="width: 115px"> + <div class="row"> <QCheckbox :model-value="props.row.hasMinPrice" @update:model-value="updateMinPrice($event, props)" @@ -549,6 +523,8 @@ function handleOnDataSave({ CrudModelRef }) { /> <VnInput class="col" + type="currency" + mask="###.##" :disable="props.row.hasMinPrice === 1" v-model.number="props.row.minPrice" v-on="getRowUpdateInputEvents(props)" @@ -577,15 +553,17 @@ function handleOnDataSave({ CrudModelRef }) { /> </template> <template #column-warehouseFk="props"> - <VnSelect - style="max-width: 150px" - :options="warehousesOptions" - hide-selected - option-label="name" - option-value="id" - v-model="props.row.warehouseFk" - v-on="getRowUpdateInputEvents(props, false, 'select')" - /> + <QTd class="col"> + <VnSelect + style="max-width: 150px" + :options="warehousesOptions" + hide-selected + option-label="name" + option-value="id" + v-model="props.row.warehouseFk" + v-on="getRowUpdateInputEvents(props, false, 'select')" + /> + </QTd> </template> <template #column-deleteAction="{ row, rowIndex }"> <QIcon From 401400bdcfc8b03eab00a4e40dc78ad1ea1fe9e7 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Fri, 13 Sep 2024 22:52:26 +0200 Subject: [PATCH 55/69] fix: remove FetchData --- src/components/common/VnSelect.vue | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue index 837a3d9f6..e767fb201 100644 --- a/src/components/common/VnSelect.vue +++ b/src/components/common/VnSelect.vue @@ -1,6 +1,7 @@ <script setup> -import { ref, toRefs, computed, watch, onMounted } from 'vue'; +import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue'; import { useI18n } from 'vue-i18n'; +import FetchData from 'src/components/FetchData.vue'; import { useValidator } from 'src/composables/useValidator'; const emit = defineEmits(['update:modelValue', 'update:options', 'remove']); @@ -225,6 +226,16 @@ const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val); </script> <template> + <FetchData + ref="dataRef" + :url="$props.url" + @on-fetch="(data) => setOptions(data)" + :where="where || { [optionValue]: value }" + :limit="limit" + :sort-by="sortBy" + :fields="fields" + :params="params" + /> <QSelect v-model="value" :options="myOptions" From b6cce74449dfbf28c95ab36832635d41e20011bd Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Fri, 13 Sep 2024 23:11:18 +0200 Subject: [PATCH 56/69] fix: merge conflicts --- src/components/common/VnInputDate.vue | 53 ++++++++++++++------------- src/components/common/VnInputTime.vue | 6 ++- src/components/common/VnSelect.vue | 12 +++--- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/components/common/VnInputDate.vue b/src/components/common/VnInputDate.vue index 96e47d6d7..7113cadf9 100644 --- a/src/components/common/VnInputDate.vue +++ b/src/components/common/VnInputDate.vue @@ -2,6 +2,7 @@ import { onMounted, watch, computed, ref } from 'vue'; import { date } from 'quasar'; import { useI18n } from 'vue-i18n'; +import { useAttrs } from 'vue'; const model = defineModel({ type: [String, Date] }); const $props = defineProps({ @@ -14,29 +15,19 @@ const $props = defineProps({ default: true, }, }); +import { useValidator } from 'src/composables/useValidator'; +const { validations } = useValidator(); const { t } = useI18n(); -const requiredFieldRule = (val) => !!val || t('globals.fieldRequired'); +const requiredFieldRule = (val) => validations().required($attrs.required, val); const dateFormat = 'DD/MM/YYYY'; const isPopupOpen = ref(); const hover = ref(); const mask = ref(); +const $attrs = useAttrs(); -onMounted(() => { - // fix quasar bug - mask.value = '##/##/####'; -}); - -const styleAttrs = computed(() => { - return $props.isOutlined - ? { - dense: true, - outlined: true, - rounded: true, - } - : {}; -}); +const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])]; const formattedDate = computed({ get() { @@ -48,15 +39,12 @@ const formattedDate = computed({ let newDate; if (value) { // parse input - if (value.includes('/')) { - if (value.length == 6) value = value + new Date().getFullYear(); - if (value.length >= 10) { - if (value.at(2) == '/') value = value.split('/').reverse().join('/'); - value = date.formatDate( - new Date(value).toISOString(), - 'YYYY-MM-DDTHH:mm:ss.SSSZ' - ); - } + if (value.includes('/') && value.length >= 10) { + if (value.at(2) == '/') value = value.split('/').reverse().join('/'); + value = date.formatDate( + new Date(value).toISOString(), + 'YYYY-MM-DDTHH:mm:ss.SSSZ' + ); } const [year, month, day] = value.split('-').map((e) => parseInt(e)); newDate = new Date(year, month - 1, day); @@ -79,12 +67,25 @@ const formattedDate = computed({ const popupDate = computed(() => model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value ); - +onMounted(() => { + // fix quasar bug + mask.value = '##/##/####'; +}); watch( () => model.value, (val) => (formattedDate.value = val), { immediate: true } ); + +const styleAttrs = computed(() => { + return $props.isOutlined + ? { + dense: true, + outlined: true, + rounded: true, + } + : {}; +}); </script> <template> @@ -96,7 +97,7 @@ watch( placeholder="dd/mm/aaaa" v-bind="{ ...$attrs, ...styleAttrs }" :class="{ required: $attrs.required }" - :rules="$attrs.required ? [requiredFieldRule] : null" + :rules="mixinRules" :clearable="false" @click="isPopupOpen = true" > diff --git a/src/components/common/VnInputTime.vue b/src/components/common/VnInputTime.vue index b610dc1e9..27395aa9e 100644 --- a/src/components/common/VnInputTime.vue +++ b/src/components/common/VnInputTime.vue @@ -1,8 +1,10 @@ <script setup> -import { computed, ref } from 'vue'; +import { computed, ref, useAttrs } from 'vue'; import { useI18n } from 'vue-i18n'; import { date } from 'quasar'; - +import { useValidator } from 'src/composables/useValidator'; +const { validations } = useValidator(); +const $attrs = useAttrs(); const model = defineModel({ type: String }); const props = defineProps({ timeOnly: { diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue index e767fb201..ed842103f 100644 --- a/src/components/common/VnSelect.vue +++ b/src/components/common/VnSelect.vue @@ -3,7 +3,6 @@ import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue'; import { useI18n } from 'vue-i18n'; import FetchData from 'src/components/FetchData.vue'; import { useValidator } from 'src/composables/useValidator'; - const emit = defineEmits(['update:modelValue', 'update:options', 'remove']); const $props = defineProps({ @@ -84,10 +83,11 @@ const $props = defineProps({ default: false, }, }); - +const { validations } = useValidator(); +const requiredFieldRule = (val) => validations().required($attrs.required, val); +const $attrs = useAttrs(); const { t } = useI18n(); -const requiredFieldRule = (val) => val ?? t('globals.fieldRequired'); - +const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])]; const { optionLabel, optionValue, optionFilter, optionFilterValue, options, modelValue } = toRefs($props); const myOptions = ref([]); @@ -100,7 +100,6 @@ const noOneOpt = ref({ [optionValue.value]: false, [optionLabel.value]: noOneText, }); -const { validations } = useValidator(); const value = computed({ get() { @@ -251,8 +250,9 @@ const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val); ref="vnSelectRef" lazy-rules :class="{ required: $attrs.required }" - :rules="$attrs.required ? [requiredFieldRule] : null" + :rules="mixinRules" virtual-scroll-slice-size="options.length" + hide-bottom-space > <template v-if="isClearable" #append> <QIcon From 93488a5750b2a3de2c49ddff952defa55a3f3386 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Fri, 13 Sep 2024 23:19:16 +0200 Subject: [PATCH 57/69] fix: styles --- src/components/common/VnInputDate.vue | 1 + src/components/common/VnInputTime.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/src/components/common/VnInputDate.vue b/src/components/common/VnInputDate.vue index 7113cadf9..fd8993d6f 100644 --- a/src/components/common/VnInputDate.vue +++ b/src/components/common/VnInputDate.vue @@ -100,6 +100,7 @@ const styleAttrs = computed(() => { :rules="mixinRules" :clearable="false" @click="isPopupOpen = true" + hide-bottom-space > <template #append> <QIcon diff --git a/src/components/common/VnInputTime.vue b/src/components/common/VnInputTime.vue index 27395aa9e..42ec79479 100644 --- a/src/components/common/VnInputTime.vue +++ b/src/components/common/VnInputTime.vue @@ -79,6 +79,7 @@ function dateToTime(newDate) { :rules="mixinRules" @click="isPopupOpen = false" type="time" + hide-bottom-space > <template #append> <QIcon From deb30ee9551cab217665947ec1fd1df37362536a Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Mon, 16 Sep 2024 08:59:36 +0200 Subject: [PATCH 58/69] feat: refs #7404 travel m3 form --- src/components/VnTable/VnOrder.vue | 2 +- src/pages/Entry/EntryStockBought.vue | 102 +++++++++--------- src/pages/Entry/EntryStockBoughtDetail.vue | 66 +++++++----- src/pages/Entry/EntryStockBoughtFilter.vue | 29 +++-- .../integration/entry/stockBought.spec.js | 15 ++- 5 files changed, 116 insertions(+), 98 deletions(-) diff --git a/src/components/VnTable/VnOrder.vue b/src/components/VnTable/VnOrder.vue index 98c7ab392..7fdd23b78 100644 --- a/src/components/VnTable/VnOrder.vue +++ b/src/components/VnTable/VnOrder.vue @@ -4,7 +4,7 @@ import { useArrayData } from 'composables/useArrayData'; const model = defineModel({ type: Object }); const $props = defineProps({ name: { - type: String, + type: [String, Boolean], default: '', }, label: { diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index ad338acb1..c8f147b1f 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -1,12 +1,13 @@ <script setup> -import { onMounted, ref, watch } from 'vue'; +import { ref } from 'vue'; import { useI18n } from 'vue-i18n'; import { useState } from 'src/composables/useState'; import { useQuasar } from 'quasar'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; -import axios from 'axios'; import FetchData from 'components/FetchData.vue'; +import FormModelPopup from 'components/FormModelPopup.vue'; +import VnInput from 'src/components/common/VnInput.vue'; import VnRow from 'components/ui/VnRow.vue'; import RightMenu from 'src/components/common/RightMenu.vue'; import EntryStockBoughtFilter from './EntryStockBoughtFilter.vue'; @@ -31,7 +32,9 @@ const columns = [ align: 'left', name: 'workerFk', label: t('Buyer'), + isTitle: true, component: 'select', + cardVisible: true, create: true, attrs: { url: 'Workers/activeWithInheritedRole', @@ -82,6 +85,7 @@ const columns = [ component: EntryStockBoughtDetail, componentProps: { workerFk: row.workerFk, + dated: userParams.value.dated, }, }); }, @@ -91,6 +95,7 @@ const columns = [ ]; const fetchDataRef = ref(); +const travelDialogRef = ref(false); const tableRef = ref(); const travel = ref(null); const userParams = ref({ @@ -108,38 +113,21 @@ const filter = ref({ { relation: 'warehouseIn', scope: { - where: { code: 'vnh' }, + fields: ['code'], }, }, ], }); -function getFilter(dated) { - console.log('dated: ', dated); - const shipped = dated ? new Date(dated) : Date.vnNew(); - shipped.setHours(0, 0, 0, 0); - return { - where: { - shipped, - m3: { neq: null }, - }, - include: [ - { - relation: 'warehouseIn', - scope: { - where: { code: 'vnh' }, - }, - }, - ], - }; -} - const setUserParams = async ({ dated }) => { const shipped = (dated ? new Date(dated) : Date.vnNew()).setHours(0, 0, 0, 0); - filter.value.where.shipped = shipped; fetchDataRef.value?.fetch(); }; + +function openDialog() { + travelDialogRef.value = true; +} </script> <template> <VnSubToolbar> @@ -147,35 +135,55 @@ const setUserParams = async ({ dated }) => { <FetchData ref="fetchDataRef" url="Travels" - limit="1" auto-load :filter="filter" - @on-fetch="(data) => (travel = data)" + @on-fetch=" + (data) => { + travel = data.filter((data) => data.warehouseIn.code === 'VNH'); + } + " /> - - <VnRow> - <div v-if="travel" class="q-pa-md"> - <QIcon - name="local_airport" - class="fill-icon q-mr-sm" - size="md" - :title="t('Travel')" - color="primary" - /> + <VnRow class="travel"> + <div v-if="travel"> + <span style="color: var(--vn-label-color)"> + {{ t('Booked trucks') }}: + </span> <span> - {{ t('Booked trucks') + ': ' + travel[0]?.m3 }} + {{ travel[0]?.m3 }} </span> <QBtn + v-if="travel[0]?.m3" style="max-width: 20%" flat icon="edit" - @click="navigate(travel[0]?.id)" + @click="openDialog()" :title="t('Edit travel')" + color="primary" /> </div> </VnRow> </template> </VnSubToolbar> + <QDialog v-model="travelDialogRef" :maximized="true" :class="['vn-row', 'wrap']"> + <FormModelPopup + :url-update="`Travels/${travel[0].id}`" + model="travel" + :title="t('Travel m3')" + :form-initial-data="{ id: travel[0].id, m3: travel[0].m3 }" + @on-data-saved="fetchDataRef.fetch()" + > + <template #form-inputs="{ data }"> + <VnInput + v-model="data.id" + :label="t('id')" + type="number" + disable + readonly + /> + <VnInput v-model="data.m3" :label="t('m3')" type="number" /> + </template> + </FormModelPopup> + </QDialog> <RightMenu> <template #right-panel> <EntryStockBoughtFilter @@ -196,10 +204,7 @@ const setUserParams = async ({ dated }) => { :create="{ urlCreate: 'StockBoughts', title: t('Reserve some space'), - onDataSaved: () => { - tableRef.reload(); - fetchDataRef.reload(); - }, + onDataSaved: () => tableRef.reload(), formInitialData: { workerFk: user.id, dated: Date.vnNow(), @@ -214,17 +219,14 @@ const setUserParams = async ({ dated }) => { <span class="link" @click.stop> {{ row?.worker?.user?.name }} <WorkerDescriptorProxy :id="row?.workerFk" /> - </span> - </template> + </span> </template + >0 </VnTable> </QPage> </template> -<style lang="scss"> -.trucks { - text-align: center; - margin: 3%; - border: 3px solid var(--vn-header-color); - padding: 1%; +<style lang="css" scoped> +.travel { + margin-bottom: 0px; } </style> <i18n> diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue index b9420af71..6d9227ad2 100644 --- a/src/pages/Entry/EntryStockBoughtDetail.vue +++ b/src/pages/Entry/EntryStockBoughtDetail.vue @@ -14,7 +14,7 @@ const $props = defineProps({ required: true, }, dated: { - type: String, + type: Date, required: true, }, }); @@ -63,34 +63,46 @@ const columns = [ ]; </script> <template> - <QDialog> - <VnTable - ref="tableRef" - data-key="StockBoughtsDetail" - :url="customUrl" - order="itemName DESC" - :columns="columns" - :right-search="false" - :disable-infinite-scroll="true" - :disable-option="{ card: true }" - :limit="0" - auto-load - > - <template #column-entryFk="{ row }"> - <span class="link" @click.stop> - {{ row?.entryFk }} - <EntryDescriptorProxy :id="row.entryFk" /> - </span> - </template> - <template #column-itemName="{ row }"> - <span class="link" @click.stop> - {{ row?.itemName }} - <ItemDescriptorProxy :id="row.itemFk" /> - </span> - </template> - </VnTable> + <QDialog position="bottom" :maximized="true"> + <div class="container"> + <VnTable + ref="tableRef" + data-key="StockBoughtsDetail" + :url="customUrl" + order="itemName DESC" + :columns="columns" + :right-search="false" + :disable-infinite-scroll="true" + :disable-option="{ card: true }" + :limit="0" + auto-load + > + <template #column-entryFk="{ row }"> + <span class="link" @click.stop> + {{ row?.entryFk }} + <EntryDescriptorProxy :id="row.entryFk" /> + </span> + </template> + <template #column-itemName="{ row }"> + <span class="link" @click.stop> + {{ row?.itemName }} + <ItemDescriptorProxy :id="row.itemFk" /> + </span> + </template> + </VnTable> + </div> </QDialog> </template> +<style lang="css"> +.q-dialog__inner { + max-width: 50vw; + overflow: auto; + display: flex; + justify-content: center; + align-items: center; + margin: auto; +} +</style> <i18n> es: Buyer: Comprador diff --git a/src/pages/Entry/EntryStockBoughtFilter.vue b/src/pages/Entry/EntryStockBoughtFilter.vue index aaf9e7a5b..7694cfe6c 100644 --- a/src/pages/Entry/EntryStockBoughtFilter.vue +++ b/src/pages/Entry/EntryStockBoughtFilter.vue @@ -1,11 +1,9 @@ <script setup> -import { ref } from 'vue'; import { useI18n } from 'vue-i18n'; import { onMounted } from 'vue'; import { useStateStore } from 'stores/useStateStore'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; -import FetchData from 'components/FetchData.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue'; const { t } = useI18n(); @@ -15,7 +13,6 @@ const props = defineProps({ required: true, }, }); -const companiesOptions = ref([]); const stateStore = useStateStore(); const emit = defineEmits(['set-user-params']); const setUserParams = (params) => { @@ -27,20 +24,10 @@ onMounted(async () => { </script> <template> - <FetchData - ref="buyer" - url="Workers/activeWithInheritedRole" - :filter="{ - fields: ['id', 'name'], - where: { role: 'buyer' }, - }" - order="name" - @on-fetch="(data) => (companiesOptions = data)" - auto-load - /> <VnFilterPanel :data-key="props.dataKey" :search-button="true" + search-url="table" @set-user-params="setUserParams" > <template #tags="{ tag, formatFn }"> @@ -52,13 +39,25 @@ onMounted(async () => { <template #body="{ params }"> <QItem class="q-my-sm"> <QItemSection> - <VnInputDate v-model="params.dated" :label="t('Date')" is-outlined /> + <VnInputDate + id="date" + v-model="params.dated" + :label="t('Date')" + is-outlined + /> </QItemSection> </QItem> </template> </VnFilterPanel> </template> <i18n> + en: + params: + dated: Date + workerFk: Worker es: Date: Fecha + params: + dated: Date + workerFk: Trabajador </i18n> diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js index a18e2bd2e..b93afa520 100644 --- a/test/cypress/integration/entry/stockBought.spec.js +++ b/test/cypress/integration/entry/stockBought.spec.js @@ -1,15 +1,13 @@ describe('EntryStockBought', () => { - const reserveField = 'input[name="reserve"]'; beforeEach(() => { cy.viewport(1920, 1080); cy.login('buyer'); - cy.visit( - `/#/entry/stock-Bought?table={"filter":"{}","dated":"2000-12-31T23:00:00.000Z"}` - ); + cy.visit(`/#/entry/stock-Bought`); }); it('Should edit the reserved space', () => { + cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001'); cy.get('tBody > tr').its('length').should('eq', 2); - cy.get(reserveField).type('10{enter}'); + cy.get('input[name="reserve"]').type('10{enter}'); cy.get('button[title="Save"]').click(); cy.get('.q-notification__message').should('have.text', 'Data saved'); }); @@ -33,4 +31,11 @@ describe('EntryStockBought', () => { 'warningNo data available' ); }); + it('Should edit travel m3 and refresh', () => { + cy.get('.vn-row > div > .q-btn > .q-btn__content > .q-icon').click(); + cy.get('input[aria-label="m3"]').clear(); + cy.get('input[aria-label="m3"]').type('60'); + cy.get('.q-mt-lg > .q-btn--standard > .q-btn__content > .block').click(); + cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60'); + }); }); From 8c4e4a16af99c429d3abbf0a355184df5a6e9769 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Mon, 16 Sep 2024 09:19:08 +0200 Subject: [PATCH 59/69] fix(VnSectionMain): add QPage --- src/components/common/VnSectionMain.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/common/VnSectionMain.vue b/src/components/common/VnSectionMain.vue index 0c1641ce1..97a150cf4 100644 --- a/src/components/common/VnSectionMain.vue +++ b/src/components/common/VnSectionMain.vue @@ -20,6 +20,8 @@ onMounted(() => (stateStore.leftDrawer = $props.leftDrawer)); </QScrollArea> </QDrawer> <QPageContainer> - <RouterView></RouterView> + <QPage> + <RouterView></RouterView> + </QPage> </QPageContainer> </template> From 4c8238455f9a21da8a59376a249d067352052fd0 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Mon, 16 Sep 2024 10:03:12 +0200 Subject: [PATCH 60/69] fix(ClaimList): fix summary --- src/components/VnTable/VnTable.vue | 4 ++-- src/components/common/VnSectionMain.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 899e4d000..6f678d5c1 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -633,7 +633,7 @@ function handleOnDataSaved(_, res) { </QTable> </template> </CrudModel> - <QPageSticky :offset="[20, 20]" style="z-index: 2"> + <QPageSticky v-if="$props.create" :offset="[20, 20]" style="z-index: 2"> <QBtn @click=" () => @@ -645,7 +645,7 @@ function handleOnDataSaved(_, res) { shortcut="+" /> <QTooltip> - {{ createForm.title }} + {{ createForm?.title }} </QTooltip> </QPageSticky> <QDialog v-model="showForm" transition-show="scale" transition-hide="scale"> diff --git a/src/components/common/VnSectionMain.vue b/src/components/common/VnSectionMain.vue index 97a150cf4..9975b1011 100644 --- a/src/components/common/VnSectionMain.vue +++ b/src/components/common/VnSectionMain.vue @@ -21,7 +21,7 @@ onMounted(() => (stateStore.leftDrawer = $props.leftDrawer)); </QDrawer> <QPageContainer> <QPage> - <RouterView></RouterView> + <RouterView /> </QPage> </QPageContainer> </template> From 263dc29d7a4d4ba22d89fb7715a8f69d968bdfed Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Mon, 16 Sep 2024 12:19:03 +0200 Subject: [PATCH 61/69] fix: refs #7404 remove console.log --- src/components/VnTable/VnTable.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index a6a8aec11..b7321fe16 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -692,7 +692,6 @@ function handleOnDataSaved(_) { :column-name="column.name" :label="column.label" > - {{ console.log('data: ', data) }} <VnTableColumn :column="column" :row="{}" From ae76bd0b0e524035a3fe92aa73bd2a819bab1c0c Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Mon, 16 Sep 2024 12:58:06 +0200 Subject: [PATCH 62/69] refactor: refs #6346 wagons to VnTable --- src/pages/Wagon/Type/WagonTypeList.vue | 105 +++++++------- src/pages/Wagon/WagonList.vue | 184 +++++++++++++++++-------- 2 files changed, 186 insertions(+), 103 deletions(-) diff --git a/src/pages/Wagon/Type/WagonTypeList.vue b/src/pages/Wagon/Type/WagonTypeList.vue index 7615dea02..2f0d55fbe 100644 --- a/src/pages/Wagon/Type/WagonTypeList.vue +++ b/src/pages/Wagon/Type/WagonTypeList.vue @@ -2,14 +2,13 @@ import { ref, computed } from 'vue'; import axios from 'axios'; import { useQuasar } from 'quasar'; -import VnPaginate from 'src/components/ui/VnPaginate.vue'; import { useArrayData } from 'src/composables/useArrayData'; import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; -import CardList from 'components/ui/CardList.vue'; import FormModelPopup from 'src/components/FormModelPopup.vue'; import VnInput from 'src/components/common/VnInput.vue'; import VnRow from 'src/components/ui/VnRow.vue'; +import VnTable from 'src/components/VnTable/VnTable.vue'; const quasar = useQuasar(); const arrayData = useArrayData('WagonTypeList'); @@ -17,7 +16,7 @@ const store = arrayData.store; const dialog = ref(); const { push } = useRouter(); const { t } = useI18n(); -const paginate = ref(); +const tableRef = ref(); const initialData = computed(() => { return { @@ -25,10 +24,46 @@ const initialData = computed(() => { }; }); -function reloadData() { - initialData.value.name = null; - paginate.value.fetch(); -} +const columns = computed(() => [ + { + align: 'left', + name: 'id', + label: t('ID'), + isId: true, + cardVisible: true, + }, + { + align: 'left', + name: 'name', + label: t('Name'), + isTitle: true, + }, + { + align: 'left', + name: 'divisible', + label: t('Divisible'), + cardVisible: true, + component: 'checkbox', + }, + { + align: 'right', + name: 'tableActions', + actions: [ + { + title: t('components.smartCard.openCard'), + icon: 'arrow_forward', + isPrimary: true, + action: (row) => navigate(row.id, row.name), + }, + { + title: t('wagon.list.remove'), + icon: 'delete', + isPrimary: true, + action: (row) => remove(row), + }, + ], + }, +]); function navigate(id, name) { push({ path: `/wagon/type/${id}/edit`, query: { name } }); @@ -41,51 +76,25 @@ async function remove(row) { type: 'positive', }); store.data.splice(store.data.indexOf(row), 1); + window.location.reload(); } </script> <template> <QPage class="column items-center q-pa-md"> - <div class="vn-card-list"> - <VnPaginate - ref="paginate" - data-key="WagonTypeList" - url="WagonTypes" - order="id DESC" - auto-load - > - <template #body="{ rows }"> - <CardList - v-for="row of rows" - :key="row.id" - :title="(row.name || '').toString()" - :id="row.id" - @click="navigate(row.id, row.name)" - > - <template #list-items> - <QCheckbox - :label="t('Divisble')" - :model-value="row.divisible" - disable - /> - </template> - <template #actions> - <QBtn - :label="t('components.smartCard.openCard')" - @click.stop="navigate(row.id, row.name)" - outline - /> - <QBtn - :label="t('wagon.list.remove')" - @click.stop="remove(row)" - color="primary" - style="margin-top: 15px" - /> - </template> - </CardList> - </template> - </VnPaginate> - </div> + <VnTable + ref="tableRef" + data-key="WagonTypeList" + url="WagonTypes" + :columns="columns" + auto-load + order="id DESC" + :right-search="false" + :column-search="false" + :default-mode="'card'" + :disable-option="{ table: true }" + > + </VnTable> <QPageSticky :offset="[18, 18]"> <QBtn @click.stop="dialog.show()" color="primary" fab icon="add" shortcut="+"> <QDialog ref="dialog"> @@ -94,7 +103,7 @@ async function remove(row) { url-create="WagonTypes" model="WagonType" :form-initial-data="initialData" - @on-data-saved="reloadData()" + @on-data-saved="window.location.reload()" auto-load > <template #form-inputs="{ data }"> diff --git a/src/pages/Wagon/WagonList.vue b/src/pages/Wagon/WagonList.vue index c4824b861..129e803f5 100644 --- a/src/pages/Wagon/WagonList.vue +++ b/src/pages/Wagon/WagonList.vue @@ -1,12 +1,13 @@ <script setup> import axios from 'axios'; import { useQuasar } from 'quasar'; -import VnPaginate from 'src/components/ui/VnPaginate.vue'; import { useArrayData } from 'src/composables/useArrayData'; import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; -import CardList from 'components/ui/CardList.vue'; -import VnLv from 'components/ui/VnLv.vue'; +import VnTable from 'src/components/VnTable/VnTable.vue'; +import { computed } from 'vue'; +import VnSelect from 'src/components/common/VnSelect.vue'; +import VnInput from 'src/components/common/VnInput.vue'; const quasar = useQuasar(); const arrayData = useArrayData('WagonList'); @@ -23,14 +24,56 @@ const filter = { }, }; +const columns = computed(() => [ + { + align: 'left', + name: 'label', + label: t('Label'), + isTitle: true, + }, + { + align: 'left', + name: 'plate', + label: t('wagon.list.plate'), + cardVisible: true, + }, + { + align: 'left', + name: 'volume', + label: t('wagon.list.volume'), + cardVisible: true, + }, + { + align: 'left', + name: 'name', + label: t('wagon.list.type'), + cardVisible: true, + format: (row) => row?.type?.name, + }, + { + align: 'right', + name: 'tableActions', + actions: [ + { + title: t('components.smartCard.openCard'), + icon: 'arrow_forward', + isPrimary: true, + action: (row) => navigate(row.id), + }, + { + title: t('wagon.list.remove'), + icon: 'delete', + isPrimary: true, + action: (row) => remove(row), + }, + ], + }, +]); + function navigate(id) { router.push({ path: `/wagon/${id}/edit` }); } -function create() { - router.push({ path: `/wagon/create` }); -} - async function remove(row) { try { await axios.delete(`Wagons/${row.id}`).then(async () => { @@ -39,6 +82,7 @@ async function remove(row) { type: 'positive', }); store.data.splice(store.data.indexOf(row), 1); + window.location.reload(); }); } catch (error) { // @@ -48,53 +92,83 @@ async function remove(row) { <template> <QPage class="column items-center q-pa-md"> - <div class="vn-card-list"> - <VnPaginate - data-key="WagonList" - url="/Wagons" - order="id DESC" - :filter="filter" - auto-load - > - <template #body="{ rows }"> - <CardList - v-for="row of rows" - :key="row.id" - :title="(row.label || '').toString()" - :id="row.id" - @click="navigate(row.id)" - > - <template #list-items> - <VnLv - :label="t('wagon.list.plate')" - :title-label="t('wagon.list.plate')" - :value="row.plate" - /> - <VnLv :label="t('wagon.list.volume')" :value="row?.volume" /> - <VnLv - :label="t('wagon.list.type')" - :value="row?.type?.name" - /> - </template> - <template #actions> - <QBtn - :label="t('components.smartCard.openCard')" - @click.stop="navigate(row.id)" - outline - /> - <QBtn - :label="t('wagon.list.remove')" - @click.stop="remove(row)" - color="primary" - style="margin-top: 15px" - /> - </template> - </CardList> - </template> - </VnPaginate> - </div> - <QPageSticky position="bottom-right" :offset="[18, 18]"> - <QBtn @click="create" fab icon="add" color="primary" shortcut="+" /> - </QPageSticky> + <VnTable + ref="tableRef" + data-key="WagonList" + url="Wagons" + :filter="filter" + :columns="columns" + auto-load + order="id DESC" + :right-search="false" + :column-search="false" + :default-mode="'card'" + :disable-option="{ table: true }" + :create="{ + urlCreate: 'Wagons', + title: t('Create new wagon'), + onDataSaved: () => { + window.location.reload(); + }, + formInitialData: {}, + }" + > + <template #more-create-dialog="{ data }"> + <VnInput + filled + v-model="data.label" + :label="t('wagon.create.label')" + type="number" + min="0" + :rules="[(val) => !!val || t('wagon.warnings.labelNotEmpty')]" + /> + <VnInput + filled + v-model="data.plate" + :label="t('wagon.create.plate')" + :rules="[(val) => !!val || t('wagon.warnings.plateNotEmpty')]" + /> + <VnInput + filled + v-model="data.volume" + :label="t('wagon.create.volume')" + type="number" + min="0" + :rules="[(val) => !!val || t('wagon.warnings.volumeNotEmpty')]" + /> + <VnSelect + url="WagonTypes" + filled + v-model="data.typeFk" + use-input + fill-input + hide-selected + input-debounce="0" + option-label="name" + option-value="id" + emit-value + map-options + :label="t('wagon.create.type')" + :options="filteredWagonTypes" + :rules="[(val) => !!val || t('wagon.warnings.typeNotEmpty')]" + @filter="filterType" + > + <template v-if="data.typeFk" #append> + <QIcon + name="cancel" + @click.stop.prevent="data.typeFk = null" + class="cursor-pointer" + /> + </template> + <template #no-option> + <QItem> + <QItemSection class="text-grey"> + {{ t('wagon.warnings.noData') }} + </QItemSection> + </QItem> + </template> + </VnSelect> + </template> + </VnTable> </QPage> </template> From 09cdd2f7e795ec28913cacfa21f0e0f381ade840 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Mon, 16 Sep 2024 15:17:05 +0200 Subject: [PATCH 63/69] chore: changelog --- CHANGELOG.md | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e1d4c433..666d3f4dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,184 @@ +# Version XX.XX - XXXX-XX-XX + +### Added 🆕 + +- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep +- chore: refs #7323 worker changes by:jorgep +- chore: refs #7353 fix warnings by:jorgep +- chore: refs #7353 use Vue component nomenclature by:jorgep +- chore: refs #7356 fix type by:jorgep +- feat(AccountConnections): use VnToken by:alexm +- feat: add key to routerView by:Javier Segarra +- feat: add plus shortcut in VnTable by:Javier Segarra +- feat: add row by:Javier Segarra +- feat: addRow withour dialog by:Javier Segarra +- feat: apply mixin by:Javier Segarra +- feat by:Javier Segarra +- feat: change navBar buttons by:Javier Segarra +- feat: dense rows by:Javier Segarra +- feat: fields with wrong name by:jgallego +- feat: fix bugs and filters by:Javier Segarra +- feat: fix refund parameters by:jgallego +- feat: handle create row by:Javier Segarra +- feat: handle dates by:Javier Segarra +- feat: handle qCheckbox 3rd state by:Javier Segarra +- feat: imrpove VnInputTime to set cursor at start by:Javier Segarra +- feat: keyShortcut directive by:Javier Segarra +- feat: minor fixes by:jgallego +- feat: only filter by isDestiny by:Javier Segarra +- feat: refs #211153 businessDataLinkGrafana by:robert +- feat: refs #7129 add km start and end on create form by:pablone +- feat: refs #7353 add filter & fix customTags by:jorgep +- feat: refs #7353 add locale by:jorgep +- feat: refs #7353 add no one opt by:jorgep +- feat: refs #7353 add right icons by:jorgep +- feat: refs #7353 imporve toDateFormat by:jorgep +- feat: refs #7353 salesPerson nickname & id by:jorgep +- feat: refs #7353 split sections by:jorgep +- feat: refs #7847 remove reload btn by:jorgep +- feat: refs #7847 remove reload fn by:jorgep +- feat: refs #7889 added shortcuts to modules by:Jon +- feat: refs #7911 added shortcut to modules by:Jon +- feat: refuncInvoiceForm component by:jgallego +- feat: remove duplicity by:Javier Segarra +- feat: remove future itemFixedPrices by:Javier Segarra +- feat: replace stickyButtons by subtoolbar by:Javier Segarra +- feat: required validation by:Javier Segarra +- feat: show bad dates by:Javier Segarra +- feat: showdate icons by:Javier Segarra +- feat: solve ItemFixedFilterPanel by:Javier Segarra +- feat: transfer an invoice by:jgallego +- feat: try to fix ItemFixedFilterPanel by:Javier Segarra +- feat: unnecessary changes by:Javier Segarra +- feat: update changelog (origin/7896_down_devToTest_2436) by:Javier Segarra +- feat: updates by:Javier Segarra +- feat: update version and changelog by:Javier Segarra +- feat: vnInput* by:Javier Segarra +- feat: with VnTable by:Javier Segarra +- refs #6772 feat: fix approach by:Javier Segarra +- refs #6772 feat: refresh shelving.basic-data by:Javier Segarra +- style: show subName value by:Javier Segarra + +### Changed 📦 + +- perf: add v-shortcut in VnCard by:Javier Segarra +- perf: approach by:Javier Segarra +- perf: change directive location by:Javier Segarra +- perf: change slots order by:Javier Segarra +- perf: examples by:Javier Segarra +- perf: hide icon for VnInputDate by:Javier Segarra +- perf: improve ItemFixedPricefilterPanel by:Javier Segarra +- perf: improve mainShrotcutMixin by:Javier Segarra +- perf: minor clean code by:Javier Segarra +- perf: onRowchange by:Javier Segarra +- perf: order by by:Javier Segarra +- perf: order components by:Javier Segarra +- perf: refs #7889 perf shortcut test by:Jon +- perf: remove console.log by:Javier Segarra +- perf: remove icons in header slot by:Javier Segarra +- perf: remove print variables by:Javier Segarra +- perf: restore CustomerBasicData by:Javier Segarra +- refactor: deleted useless prop by:Jon +- refactor: deleted useless prop in FetchedTags by:Jon +- refactor: refs #7323 drop useless code by:jorgep +- refactor: refs #7353 clients correction by:jorgep +- refactor: refs #7353 clients correction wip by:jorgep +- refactor: refs #7353 ease logic by:jorgep +- refactor: refs #7353 order correction by:jorgep +- refactor: refs #7353 simplify code by:jorgep +- refactor: refs #7353 tickets correction by:jorgep +- refactor: refs #7353 use global locales by:jorgep +- refactor: refs #7354 changed descriptor menu options by:Jon +- refactor: refs #7354 changed icon color in table and notification when deleting a zone by:Jon +- refactor: refs #7354 fix tableFilters by:Jon +- refactor: refs #7354 modified VnInputTime by:Jon +- refactor: refs #7354 refactor deliveryPanel by:Jon +- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon +- refactor: refs #7354 requested changes by:Jon +- refactor: refs #7354 reverse deliveryPanel changes by:Jon +- refactor: refs #7354 Zone migration changes by:Jon +- refactor: refs #7889 deleted subtitle attr and use keyBinding instead by:Jon +- refactor: refs #7889 modified shortcut and dashboard, and added tootlip in LeftMenu by:Jon +- refs #6722 perf: not fetch when id not exists by:Javier Segarra +- refs #6772 perf: change variable name by:JAVIER SEGARRA MARTINEZ +- refs #6772 perf: use ArrayData (6772_reload_sections) by:Javier Segarra +- refs #7283 refactor fix ItemDescriptor by:carlossa +- refs #7283 refactor ItexDescriptor by:carlossa + +### Fixed 🛠️ + +- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep +- chore: refs #7353 fix warnings by:jorgep +- chore: refs #7356 fix type by:jorgep +- feat: fix bugs and filters by:Javier Segarra +- feat: fix refund parameters by:jgallego +- feat: minor fixes by:jgallego +- feat: refs #7353 add filter & fix customTags by:jorgep +- feat: try to fix ItemFixedFilterPanel by:Javier Segarra +- fix: add border-top by:Javier Segarra +- fix: added missing descriptors and small details by:Jon +- fix branch by:carlossa +- fix: call upsert when crudModel haschanges by:Javier Segarra +- fix(ClaimList): fix summary by:alexm +- fix: cli warnings by:Javier Segarra +- fix: editTableOptions by:Javier Segarra +- fix events and descriptor menu by:Jon +- fix: InvoiceIn sections (origin/6772_reload_sections) by:Javier Segarra +- fix: minor changes by:Javier Segarra +- fix: minor error whit dates by:Javier Segarra +- fix: module icon by:Javier Segarra +- fix: options QDate by:Javier Segarra +- fix: refs #6900 e2e error by:jorgep +- fix: refs #6900 rollback by:jorgep +- fix: refs #7353 css by:jorgep +- fix: refs #7353 hide search param (origin/7353-warmfix-fixSearchbar) by:jorgep +- fix: refs #7353 iron out filter by:jorgep +- fix: refs #7353 iron out ticket table by:jorgep +- fix: refs #7353 padding by:jorgep +- fix: refs #7353 salesClientTable by:jorgep +- fix: refs #7353 salesorderTable by:jorgep +- fix: refs #7353 saleTicketMonitors by:jorgep +- fix: refs #7353 use same datakey by:jorgep +- fix: refs #7353 vnTable colors by:jorgep +- fix: refs #7354 e2e tests by:Jon +- fix: refs #7354 fix delivery days by:Jon +- fix: refs #7354 fix list searchbar and filters by:Jon +- fix: refs #7354 fix VnSearchbar search for zone section & finished basic tests by:Jon +- fix: refs #7354 fix VnTable filters and agency field by:Jon +- fix: refs #7354 fix zoneSearchbar by:Jon +- fix: refs #7354 requested changes by:Jon +- fix: refs #7356 colors by:jorgep +- fix: refs #7356 create claim dialog by:jorgep +- fix: refs #7889 fixed shortcut test by:Jon +- fix: refs #7903 fixed ticket's search bar and keybinding tooltip by:Jon +- fix: refs #7911 fixed shortcut and related files by:Jon +- fix: remove condition duplicated by:Javier Segarra +- fix: remove property by:Javier Segarra +- fix tootltip by:carlossa +- fix traduction by:carlossa +- fix(VnSectionMain): add QPage by:alexm +- fix(zone): zoneLocation and the others searchbar by:alexm +- refactor: refs #7354 fix tableFilters by:Jon +- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon +- refs #6772 feat: fix approach by:Javier Segarra +- refs #6772 fix: claimPhoto reload by:Javier Segarra +- refs #6896 fix searchbar by:carlossa +- refs #6897 fix entry by:carlossa +- refs #6899 fix invoiceFix by:carlossa +- refs #6899 fix order by:carlossa +- refs #7283 fix by:carlossa +- refs #7283 fix ItemDescriptor warehouse by:carlossa +- refs #7283 refactor fix ItemDescriptor by:carlossa +- refs #7355 #7366 fix account, summary, list, travelList, tooltip by:carlossa +- refs #7355 fix accountPrivileges by:carlossa +- refs #7355 fix accounts, vnTable by:carlossa +- refs #7355 fix privileges by:carlossa +- refs #7355 fix roles filters by:carlossa +- refs #7355 fix total by:carlossa +- refs #7355 fix views summarys, entryList, travelList refact by:carlossa +- refs #7366 fix travel hours by:carlossa +- test: fix e2e by:Javier Segarra + # Version 24.36 - 2024-08-27 ### Added 🆕 From dc047435f5c7bed72a3d035690b66d5d30de5baa Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Mon, 16 Sep 2024 15:17:31 +0200 Subject: [PATCH 64/69] chore: changelog --- CHANGELOG.md | 342 +++++++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 172 insertions(+), 172 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 666d3f4dd..f1d10b26e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,183 +1,183 @@ -# Version XX.XX - XXXX-XX-XX +# Version 24.38 - 2024-09-17 ### Added 🆕 -- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep -- chore: refs #7323 worker changes by:jorgep -- chore: refs #7353 fix warnings by:jorgep -- chore: refs #7353 use Vue component nomenclature by:jorgep -- chore: refs #7356 fix type by:jorgep -- feat(AccountConnections): use VnToken by:alexm -- feat: add key to routerView by:Javier Segarra -- feat: add plus shortcut in VnTable by:Javier Segarra -- feat: add row by:Javier Segarra -- feat: addRow withour dialog by:Javier Segarra -- feat: apply mixin by:Javier Segarra -- feat by:Javier Segarra -- feat: change navBar buttons by:Javier Segarra -- feat: dense rows by:Javier Segarra -- feat: fields with wrong name by:jgallego -- feat: fix bugs and filters by:Javier Segarra -- feat: fix refund parameters by:jgallego -- feat: handle create row by:Javier Segarra -- feat: handle dates by:Javier Segarra -- feat: handle qCheckbox 3rd state by:Javier Segarra -- feat: imrpove VnInputTime to set cursor at start by:Javier Segarra -- feat: keyShortcut directive by:Javier Segarra -- feat: minor fixes by:jgallego -- feat: only filter by isDestiny by:Javier Segarra -- feat: refs #211153 businessDataLinkGrafana by:robert -- feat: refs #7129 add km start and end on create form by:pablone -- feat: refs #7353 add filter & fix customTags by:jorgep -- feat: refs #7353 add locale by:jorgep -- feat: refs #7353 add no one opt by:jorgep -- feat: refs #7353 add right icons by:jorgep -- feat: refs #7353 imporve toDateFormat by:jorgep -- feat: refs #7353 salesPerson nickname & id by:jorgep -- feat: refs #7353 split sections by:jorgep -- feat: refs #7847 remove reload btn by:jorgep -- feat: refs #7847 remove reload fn by:jorgep -- feat: refs #7889 added shortcuts to modules by:Jon -- feat: refs #7911 added shortcut to modules by:Jon -- feat: refuncInvoiceForm component by:jgallego -- feat: remove duplicity by:Javier Segarra -- feat: remove future itemFixedPrices by:Javier Segarra -- feat: replace stickyButtons by subtoolbar by:Javier Segarra -- feat: required validation by:Javier Segarra -- feat: show bad dates by:Javier Segarra -- feat: showdate icons by:Javier Segarra -- feat: solve ItemFixedFilterPanel by:Javier Segarra -- feat: transfer an invoice by:jgallego -- feat: try to fix ItemFixedFilterPanel by:Javier Segarra -- feat: unnecessary changes by:Javier Segarra -- feat: update changelog (origin/7896_down_devToTest_2436) by:Javier Segarra -- feat: updates by:Javier Segarra -- feat: update version and changelog by:Javier Segarra -- feat: vnInput* by:Javier Segarra -- feat: with VnTable by:Javier Segarra -- refs #6772 feat: fix approach by:Javier Segarra -- refs #6772 feat: refresh shelving.basic-data by:Javier Segarra -- style: show subName value by:Javier Segarra +- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep +- chore: refs #7323 worker changes by:jorgep +- chore: refs #7353 fix warnings by:jorgep +- chore: refs #7353 use Vue component nomenclature by:jorgep +- chore: refs #7356 fix type by:jorgep +- feat(AccountConnections): use VnToken by:alexm +- feat: add key to routerView by:Javier Segarra +- feat: add plus shortcut in VnTable by:Javier Segarra +- feat: add row by:Javier Segarra +- feat: addRow withour dialog by:Javier Segarra +- feat: apply mixin by:Javier Segarra +- feat by:Javier Segarra +- feat: change navBar buttons by:Javier Segarra +- feat: dense rows by:Javier Segarra +- feat: fields with wrong name by:jgallego +- feat: fix bugs and filters by:Javier Segarra +- feat: fix refund parameters by:jgallego +- feat: handle create row by:Javier Segarra +- feat: handle dates by:Javier Segarra +- feat: handle qCheckbox 3rd state by:Javier Segarra +- feat: imrpove VnInputTime to set cursor at start by:Javier Segarra +- feat: keyShortcut directive by:Javier Segarra +- feat: minor fixes by:jgallego +- feat: only filter by isDestiny by:Javier Segarra +- feat: refs #211153 businessDataLinkGrafana by:robert +- feat: refs #7129 add km start and end on create form by:pablone +- feat: refs #7353 add filter & fix customTags by:jorgep +- feat: refs #7353 add locale by:jorgep +- feat: refs #7353 add no one opt by:jorgep +- feat: refs #7353 add right icons by:jorgep +- feat: refs #7353 imporve toDateFormat by:jorgep +- feat: refs #7353 salesPerson nickname & id by:jorgep +- feat: refs #7353 split sections by:jorgep +- feat: refs #7847 remove reload btn by:jorgep +- feat: refs #7847 remove reload fn by:jorgep +- feat: refs #7889 added shortcuts to modules by:Jon +- feat: refs #7911 added shortcut to modules by:Jon +- feat: refuncInvoiceForm component by:jgallego +- feat: remove duplicity by:Javier Segarra +- feat: remove future itemFixedPrices by:Javier Segarra +- feat: replace stickyButtons by subtoolbar by:Javier Segarra +- feat: required validation by:Javier Segarra +- feat: show bad dates by:Javier Segarra +- feat: showdate icons by:Javier Segarra +- feat: solve ItemFixedFilterPanel by:Javier Segarra +- feat: transfer an invoice by:jgallego +- feat: try to fix ItemFixedFilterPanel by:Javier Segarra +- feat: unnecessary changes by:Javier Segarra +- feat: update changelog (origin/7896_down_devToTest_2436) by:Javier Segarra +- feat: updates by:Javier Segarra +- feat: update version and changelog by:Javier Segarra +- feat: vnInput\* by:Javier Segarra +- feat: with VnTable by:Javier Segarra +- refs #6772 feat: fix approach by:Javier Segarra +- refs #6772 feat: refresh shelving.basic-data by:Javier Segarra +- style: show subName value by:Javier Segarra ### Changed 📦 -- perf: add v-shortcut in VnCard by:Javier Segarra -- perf: approach by:Javier Segarra -- perf: change directive location by:Javier Segarra -- perf: change slots order by:Javier Segarra -- perf: examples by:Javier Segarra -- perf: hide icon for VnInputDate by:Javier Segarra -- perf: improve ItemFixedPricefilterPanel by:Javier Segarra -- perf: improve mainShrotcutMixin by:Javier Segarra -- perf: minor clean code by:Javier Segarra -- perf: onRowchange by:Javier Segarra -- perf: order by by:Javier Segarra -- perf: order components by:Javier Segarra -- perf: refs #7889 perf shortcut test by:Jon -- perf: remove console.log by:Javier Segarra -- perf: remove icons in header slot by:Javier Segarra -- perf: remove print variables by:Javier Segarra -- perf: restore CustomerBasicData by:Javier Segarra -- refactor: deleted useless prop by:Jon -- refactor: deleted useless prop in FetchedTags by:Jon -- refactor: refs #7323 drop useless code by:jorgep -- refactor: refs #7353 clients correction by:jorgep -- refactor: refs #7353 clients correction wip by:jorgep -- refactor: refs #7353 ease logic by:jorgep -- refactor: refs #7353 order correction by:jorgep -- refactor: refs #7353 simplify code by:jorgep -- refactor: refs #7353 tickets correction by:jorgep -- refactor: refs #7353 use global locales by:jorgep -- refactor: refs #7354 changed descriptor menu options by:Jon -- refactor: refs #7354 changed icon color in table and notification when deleting a zone by:Jon -- refactor: refs #7354 fix tableFilters by:Jon -- refactor: refs #7354 modified VnInputTime by:Jon -- refactor: refs #7354 refactor deliveryPanel by:Jon -- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon -- refactor: refs #7354 requested changes by:Jon -- refactor: refs #7354 reverse deliveryPanel changes by:Jon -- refactor: refs #7354 Zone migration changes by:Jon -- refactor: refs #7889 deleted subtitle attr and use keyBinding instead by:Jon -- refactor: refs #7889 modified shortcut and dashboard, and added tootlip in LeftMenu by:Jon -- refs #6722 perf: not fetch when id not exists by:Javier Segarra -- refs #6772 perf: change variable name by:JAVIER SEGARRA MARTINEZ -- refs #6772 perf: use ArrayData (6772_reload_sections) by:Javier Segarra -- refs #7283 refactor fix ItemDescriptor by:carlossa -- refs #7283 refactor ItexDescriptor by:carlossa +- perf: add v-shortcut in VnCard by:Javier Segarra +- perf: approach by:Javier Segarra +- perf: change directive location by:Javier Segarra +- perf: change slots order by:Javier Segarra +- perf: examples by:Javier Segarra +- perf: hide icon for VnInputDate by:Javier Segarra +- perf: improve ItemFixedPricefilterPanel by:Javier Segarra +- perf: improve mainShrotcutMixin by:Javier Segarra +- perf: minor clean code by:Javier Segarra +- perf: onRowchange by:Javier Segarra +- perf: order by by:Javier Segarra +- perf: order components by:Javier Segarra +- perf: refs #7889 perf shortcut test by:Jon +- perf: remove console.log by:Javier Segarra +- perf: remove icons in header slot by:Javier Segarra +- perf: remove print variables by:Javier Segarra +- perf: restore CustomerBasicData by:Javier Segarra +- refactor: deleted useless prop by:Jon +- refactor: deleted useless prop in FetchedTags by:Jon +- refactor: refs #7323 drop useless code by:jorgep +- refactor: refs #7353 clients correction by:jorgep +- refactor: refs #7353 clients correction wip by:jorgep +- refactor: refs #7353 ease logic by:jorgep +- refactor: refs #7353 order correction by:jorgep +- refactor: refs #7353 simplify code by:jorgep +- refactor: refs #7353 tickets correction by:jorgep +- refactor: refs #7353 use global locales by:jorgep +- refactor: refs #7354 changed descriptor menu options by:Jon +- refactor: refs #7354 changed icon color in table and notification when deleting a zone by:Jon +- refactor: refs #7354 fix tableFilters by:Jon +- refactor: refs #7354 modified VnInputTime by:Jon +- refactor: refs #7354 refactor deliveryPanel by:Jon +- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon +- refactor: refs #7354 requested changes by:Jon +- refactor: refs #7354 reverse deliveryPanel changes by:Jon +- refactor: refs #7354 Zone migration changes by:Jon +- refactor: refs #7889 deleted subtitle attr and use keyBinding instead by:Jon +- refactor: refs #7889 modified shortcut and dashboard, and added tootlip in LeftMenu by:Jon +- refs #6722 perf: not fetch when id not exists by:Javier Segarra +- refs #6772 perf: change variable name by:JAVIER SEGARRA MARTINEZ +- refs #6772 perf: use ArrayData (6772_reload_sections) by:Javier Segarra +- refs #7283 refactor fix ItemDescriptor by:carlossa +- refs #7283 refactor ItexDescriptor by:carlossa ### Fixed 🛠️ -- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep -- chore: refs #7353 fix warnings by:jorgep -- chore: refs #7356 fix type by:jorgep -- feat: fix bugs and filters by:Javier Segarra -- feat: fix refund parameters by:jgallego -- feat: minor fixes by:jgallego -- feat: refs #7353 add filter & fix customTags by:jorgep -- feat: try to fix ItemFixedFilterPanel by:Javier Segarra -- fix: add border-top by:Javier Segarra -- fix: added missing descriptors and small details by:Jon -- fix branch by:carlossa -- fix: call upsert when crudModel haschanges by:Javier Segarra -- fix(ClaimList): fix summary by:alexm -- fix: cli warnings by:Javier Segarra -- fix: editTableOptions by:Javier Segarra -- fix events and descriptor menu by:Jon -- fix: InvoiceIn sections (origin/6772_reload_sections) by:Javier Segarra -- fix: minor changes by:Javier Segarra -- fix: minor error whit dates by:Javier Segarra -- fix: module icon by:Javier Segarra -- fix: options QDate by:Javier Segarra -- fix: refs #6900 e2e error by:jorgep -- fix: refs #6900 rollback by:jorgep -- fix: refs #7353 css by:jorgep -- fix: refs #7353 hide search param (origin/7353-warmfix-fixSearchbar) by:jorgep -- fix: refs #7353 iron out filter by:jorgep -- fix: refs #7353 iron out ticket table by:jorgep -- fix: refs #7353 padding by:jorgep -- fix: refs #7353 salesClientTable by:jorgep -- fix: refs #7353 salesorderTable by:jorgep -- fix: refs #7353 saleTicketMonitors by:jorgep -- fix: refs #7353 use same datakey by:jorgep -- fix: refs #7353 vnTable colors by:jorgep -- fix: refs #7354 e2e tests by:Jon -- fix: refs #7354 fix delivery days by:Jon -- fix: refs #7354 fix list searchbar and filters by:Jon -- fix: refs #7354 fix VnSearchbar search for zone section & finished basic tests by:Jon -- fix: refs #7354 fix VnTable filters and agency field by:Jon -- fix: refs #7354 fix zoneSearchbar by:Jon -- fix: refs #7354 requested changes by:Jon -- fix: refs #7356 colors by:jorgep -- fix: refs #7356 create claim dialog by:jorgep -- fix: refs #7889 fixed shortcut test by:Jon -- fix: refs #7903 fixed ticket's search bar and keybinding tooltip by:Jon -- fix: refs #7911 fixed shortcut and related files by:Jon -- fix: remove condition duplicated by:Javier Segarra -- fix: remove property by:Javier Segarra -- fix tootltip by:carlossa -- fix traduction by:carlossa -- fix(VnSectionMain): add QPage by:alexm -- fix(zone): zoneLocation and the others searchbar by:alexm -- refactor: refs #7354 fix tableFilters by:Jon -- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon -- refs #6772 feat: fix approach by:Javier Segarra -- refs #6772 fix: claimPhoto reload by:Javier Segarra -- refs #6896 fix searchbar by:carlossa -- refs #6897 fix entry by:carlossa -- refs #6899 fix invoiceFix by:carlossa -- refs #6899 fix order by:carlossa -- refs #7283 fix by:carlossa -- refs #7283 fix ItemDescriptor warehouse by:carlossa -- refs #7283 refactor fix ItemDescriptor by:carlossa -- refs #7355 #7366 fix account, summary, list, travelList, tooltip by:carlossa -- refs #7355 fix accountPrivileges by:carlossa -- refs #7355 fix accounts, vnTable by:carlossa -- refs #7355 fix privileges by:carlossa -- refs #7355 fix roles filters by:carlossa -- refs #7355 fix total by:carlossa -- refs #7355 fix views summarys, entryList, travelList refact by:carlossa -- refs #7366 fix travel hours by:carlossa -- test: fix e2e by:Javier Segarra +- chore: refs #6772 fix e2e (origin/6772-warmfix-fixE2e) by:jorgep +- chore: refs #7353 fix warnings by:jorgep +- chore: refs #7356 fix type by:jorgep +- feat: fix bugs and filters by:Javier Segarra +- feat: fix refund parameters by:jgallego +- feat: minor fixes by:jgallego +- feat: refs #7353 add filter & fix customTags by:jorgep +- feat: try to fix ItemFixedFilterPanel by:Javier Segarra +- fix: add border-top by:Javier Segarra +- fix: added missing descriptors and small details by:Jon +- fix branch by:carlossa +- fix: call upsert when crudModel haschanges by:Javier Segarra +- fix(ClaimList): fix summary by:alexm +- fix: cli warnings by:Javier Segarra +- fix: editTableOptions by:Javier Segarra +- fix events and descriptor menu by:Jon +- fix: InvoiceIn sections (origin/6772_reload_sections) by:Javier Segarra +- fix: minor changes by:Javier Segarra +- fix: minor error whit dates by:Javier Segarra +- fix: module icon by:Javier Segarra +- fix: options QDate by:Javier Segarra +- fix: refs #6900 e2e error by:jorgep +- fix: refs #6900 rollback by:jorgep +- fix: refs #7353 css by:jorgep +- fix: refs #7353 hide search param (origin/7353-warmfix-fixSearchbar) by:jorgep +- fix: refs #7353 iron out filter by:jorgep +- fix: refs #7353 iron out ticket table by:jorgep +- fix: refs #7353 padding by:jorgep +- fix: refs #7353 salesClientTable by:jorgep +- fix: refs #7353 salesorderTable by:jorgep +- fix: refs #7353 saleTicketMonitors by:jorgep +- fix: refs #7353 use same datakey by:jorgep +- fix: refs #7353 vnTable colors by:jorgep +- fix: refs #7354 e2e tests by:Jon +- fix: refs #7354 fix delivery days by:Jon +- fix: refs #7354 fix list searchbar and filters by:Jon +- fix: refs #7354 fix VnSearchbar search for zone section & finished basic tests by:Jon +- fix: refs #7354 fix VnTable filters and agency field by:Jon +- fix: refs #7354 fix zoneSearchbar by:Jon +- fix: refs #7354 requested changes by:Jon +- fix: refs #7356 colors by:jorgep +- fix: refs #7356 create claim dialog by:jorgep +- fix: refs #7889 fixed shortcut test by:Jon +- fix: refs #7903 fixed ticket's search bar and keybinding tooltip by:Jon +- fix: refs #7911 fixed shortcut and related files by:Jon +- fix: remove condition duplicated by:Javier Segarra +- fix: remove property by:Javier Segarra +- fix tootltip by:carlossa +- fix traduction by:carlossa +- fix(VnSectionMain): add QPage by:alexm +- fix(zone): zoneLocation and the others searchbar by:alexm +- refactor: refs #7354 fix tableFilters by:Jon +- refactor: refs #7354 refactor zones section and fixed e2e tests by:Jon +- refs #6772 feat: fix approach by:Javier Segarra +- refs #6772 fix: claimPhoto reload by:Javier Segarra +- refs #6896 fix searchbar by:carlossa +- refs #6897 fix entry by:carlossa +- refs #6899 fix invoiceFix by:carlossa +- refs #6899 fix order by:carlossa +- refs #7283 fix by:carlossa +- refs #7283 fix ItemDescriptor warehouse by:carlossa +- refs #7283 refactor fix ItemDescriptor by:carlossa +- refs #7355 #7366 fix account, summary, list, travelList, tooltip by:carlossa +- refs #7355 fix accountPrivileges by:carlossa +- refs #7355 fix accounts, vnTable by:carlossa +- refs #7355 fix privileges by:carlossa +- refs #7355 fix roles filters by:carlossa +- refs #7355 fix total by:carlossa +- refs #7355 fix views summarys, entryList, travelList refact by:carlossa +- refs #7366 fix travel hours by:carlossa +- test: fix e2e by:Javier Segarra # Version 24.36 - 2024-08-27 diff --git a/package.json b/package.json index f25e570a3..6a7c1ed55 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "24.36.0", + "version": "24.38.0", "description": "Salix frontend", "productName": "Salix", "author": "Verdnatura", From 37b6a032888abba2695fa6549d327b41bf93dec1 Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Tue, 17 Sep 2024 09:25:53 +0200 Subject: [PATCH 65/69] fix(itemDescriptor): fix redirection to itemDiary --- src/pages/Item/Card/ItemDescriptor.vue | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue index baac0c608..da6859d30 100644 --- a/src/pages/Item/Card/ItemDescriptor.vue +++ b/src/pages/Item/Card/ItemDescriptor.vue @@ -11,7 +11,6 @@ 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 { getUrl } from 'src/composables/getUrl'; import axios from 'axios'; import { dashIfEmpty } from 'src/filters'; @@ -51,10 +50,8 @@ const entityId = computed(() => { const regularizeStockFormDialog = ref(null); const available = ref(null); const visible = ref(null); -const salixUrl = ref(); onMounted(async () => { - salixUrl.value = await getUrl(''); await getItemConfigs(); await updateStock(); }); @@ -200,16 +197,10 @@ const openCloneDialog = async () => { <template #actions="{}"> <QCardActions class="row justify-center"> <QBtn - :href=" - salixUrl + - 'item/' + - entityId + - '/diary?' + - 'warehouseFk=' + - warehouseFk + - '&lineFk=' + - $props.saleFk - " + :to="{ + name: 'ItemDiary', + query: { warehouseFk, lineFk: $props.saleFk }, + }" size="md" icon="vn:transaction" color="primary" From 3d1bb0c67a035e770f6aa02cf84e51307d9a9c8b Mon Sep 17 00:00:00 2001 From: alexm <alexm@verdnatura.es> Date: Tue, 17 Sep 2024 10:20:44 +0200 Subject: [PATCH 66/69] fix(itemDescriptor): fix redirection to itemDiary --- src/components/common/VnCard.vue | 10 +++++++--- src/pages/Item/Card/ItemCard.vue | 2 +- src/pages/Item/Card/ItemDescriptor.vue | 1 + src/pages/Login/ResetPassword.vue | 1 - 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue index 7d29da232..0d80f43ce 100644 --- a/src/components/common/VnCard.vue +++ b/src/components/common/VnCard.vue @@ -24,7 +24,9 @@ const stateStore = useStateStore(); const route = useRoute(); const router = useRouter(); const url = computed(() => { - if (props.baseUrl) return `${props.baseUrl}/${route.params.id}`; + if (props.baseUrl) { + return `${props.baseUrl}/${route.params.id}`; + } return props.customUrl; }); const searchRightDataKey = computed(() => { @@ -40,8 +42,10 @@ onBeforeMount(async () => { try { if (!props.baseUrl) arrayData.store.filter.where = { id: route.params.id }; await arrayData.fetch({ append: false, updateRouter: false }); - } catch (e) { - router.push({ name: 'WorkerList' }); + } catch { + const { matched: matches } = router.currentRoute.value; + const { path } = matches.at(-1); + router.push({ path: path.replace(/:id.*/, '') }); } }); diff --git a/src/pages/Item/Card/ItemCard.vue b/src/pages/Item/Card/ItemCard.vue index 1162327c1..2412f2bf9 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: 'searchbar.label', info: 'searchbar.info', }" /> diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue index da6859d30..ef844824f 100644 --- a/src/pages/Item/Card/ItemDescriptor.vue +++ b/src/pages/Item/Card/ItemDescriptor.vue @@ -199,6 +199,7 @@ const openCloneDialog = async () => { <QBtn :to="{ name: 'ItemDiary', + params: { id: entityId }, query: { warehouseFk, lineFk: $props.saleFk }, }" size="md" diff --git a/src/pages/Login/ResetPassword.vue b/src/pages/Login/ResetPassword.vue index eff718e97..2751f1ceb 100644 --- a/src/pages/Login/ResetPassword.vue +++ b/src/pages/Login/ResetPassword.vue @@ -33,7 +33,6 @@ async function onSubmit() { }; try { - console.log('newPassword: ', newPassword); await axios.post( 'VnUsers/reset-password', { newPassword: newPassword.value }, From 044156356c559eb8660d851bb641f57a4909dd68 Mon Sep 17 00:00:00 2001 From: carlossa <carlossa@verdnatura.es> Date: Tue, 17 Sep 2024 10:37:22 +0200 Subject: [PATCH 67/69] hotfix searchbar --- src/pages/InvoiceOut/InvoiceOutList.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/InvoiceOut/InvoiceOutList.vue b/src/pages/InvoiceOut/InvoiceOutList.vue index 915b58b15..5157d957b 100644 --- a/src/pages/InvoiceOut/InvoiceOutList.vue +++ b/src/pages/InvoiceOut/InvoiceOutList.vue @@ -177,7 +177,7 @@ watchEffect(selectedRows); <VnSearchbar :info="t('youCanSearchByInvoiceReference')" :label="t('searchInvoice')" - data-key="InvoiceOutList" + data-key="invoiceOut" /> <VnSubToolbar> <template #st-actions> From e559ab43d7bbbfb19ad5917255ed271290052cac Mon Sep 17 00:00:00 2001 From: pablone <pablone@verdnatura.es> Date: Tue, 17 Sep 2024 13:40:27 +0200 Subject: [PATCH 68/69] fix: refs #7404 remove some style --- src/components/VnTable/VnTable.vue | 2 +- src/pages/Entry/EntryStockBought.vue | 4 ++-- src/pages/Entry/EntryStockBoughtDetail.vue | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index b7321fe16..648b1fb3b 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -430,7 +430,7 @@ function handleOnDataSaved(_) { /> </template> <template #header-cell="{ col }"> - <QTh table-header-style="max-width:50%" v-if="col.visible ?? true"> + <QTh v-if="col.visible ?? true"> <div class="column self-start q-ml-xs ellipsis" :class="`text-${col?.align ?? 'left'}`" diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index c8f147b1f..5b4d43e06 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -219,8 +219,8 @@ function openDialog() { <span class="link" @click.stop> {{ row?.worker?.user?.name }} <WorkerDescriptorProxy :id="row?.workerFk" /> - </span> </template - >0 + </span> + </template> </VnTable> </QPage> </template> diff --git a/src/pages/Entry/EntryStockBoughtDetail.vue b/src/pages/Entry/EntryStockBoughtDetail.vue index 6d9227ad2..744b9d3fe 100644 --- a/src/pages/Entry/EntryStockBoughtDetail.vue +++ b/src/pages/Entry/EntryStockBoughtDetail.vue @@ -63,7 +63,7 @@ const columns = [ ]; </script> <template> - <QDialog position="bottom" :maximized="true"> + <QDialog :maximized="true"> <div class="container"> <VnTable ref="tableRef" From 4f662375cd34e6e08bfe376b409a6d636611f65b Mon Sep 17 00:00:00 2001 From: carlossa <carlossa@verdnatura.es> Date: Tue, 17 Sep 2024 15:04:58 +0200 Subject: [PATCH 69/69] fix(VnTable): sanitizer value is defined --- src/components/VnTable/VnTable.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 648b1fb3b..55028080c 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -200,7 +200,7 @@ function setUserParams(watchedParams, watchedOrder) { function sanitizer(params) { for (const [key, value] of Object.entries(params)) { - if (typeof value == 'object') { + if (value && typeof value == 'object') { const param = Object.values(value)[0]; if (typeof param == 'string') params[key] = param.replaceAll('%', ''); }