diff --git a/package.json b/package.json index 076cbbb14..017412ef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "25.12.0", + "version": "25.14.0", "description": "Salix frontend", "productName": "Salix", "author": "Verdnatura", diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue index 8c4f70f3b..6303f48ae 100644 --- a/src/components/CrudModel.vue +++ b/src/components/CrudModel.vue @@ -181,9 +181,8 @@ async function saveChanges(data) { return; } let changes = data || getChanges(); - if ($props.beforeSaveFn) { - changes = await $props.beforeSaveFn(changes, getChanges); - } + if ($props.beforeSaveFn) changes = await $props.beforeSaveFn(changes, getChanges); + try { if (changes?.creates?.length === 0 && changes?.updates?.length === 0) { return; @@ -194,7 +193,7 @@ async function saveChanges(data) { isLoading.value = false; } originalData.value = JSON.parse(JSON.stringify(formData.value)); - if (changes.creates?.length) await vnPaginateRef.value.fetch(); + if (changes?.creates?.length) await vnPaginateRef.value.fetch(); hasChanges.value = false; emit('saveChanges', data); diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 78b00d041..6a547d95d 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -595,18 +595,17 @@ function cardClick(_, row) { function removeTextValue(data, getChanges) { let changes = data.updates; - if (!changes) return data; - - for (const change of changes) { - for (const key in change.data) { - if (key.endsWith('VnTableTextValue')) { - delete change.data[key]; + if (changes) { + for (const change of changes) { + for (const key in change.data) { + if (key.endsWith('VnTableTextValue')) { + delete change.data[key]; + } } } + + data.updates = changes.filter((change) => Object.keys(change.data).length > 0); } - - data.updates = changes.filter((change) => Object.keys(change.data).length > 0); - if ($attrs?.beforeSaveFn) data = $attrs.beforeSaveFn(data, getChanges); return data; @@ -776,7 +775,7 @@ const rowCtrlClickFunction = computed(() => { :data-col-field="col?.name" > <div - class="no-padding no-margin peter" + class="no-padding no-margin" style=" overflow: hidden; text-overflow: ellipsis; @@ -978,6 +977,8 @@ const rowCtrlClickFunction = computed(() => { v-for="col of cols.filter((cols) => cols.visible ?? true)" :key="col?.id" :class="getColAlign(col)" + :style="col?.width ? `max-width: ${col?.width}` : ''" + style="font-size: small" > <slot :name="`column-footer-${col.name}`" @@ -1040,38 +1041,43 @@ const rowCtrlClickFunction = computed(() => { @on-data-saved="(_, res) => createForm.onDataSaved(res)" > <template #form-inputs="{ data }"> - <div :style="createComplement?.containerStyle"> - <div - :style="createComplement?.previousStyle" - v-if="!quasar.screen.xs" - > - <slot name="previous-create-dialog" :data="data" /> - </div> - <div class="grid-create" :style="createComplement?.columnGridStyle"> - <slot - v-for="column of splittedColumns.create" - :key="column.name" - :name="`column-create-${column.name}`" - :data="data" - :column-name="column.name" - :label="column.label" + <slot name="alter-create" :data="data"> + <div :style="createComplement?.containerStyle"> + <div + :style="createComplement?.previousStyle" + v-if="!quasar.screen.xs" > - <VnColumn - :column="{ - ...column, - ...{ disable: column?.createDisable ?? false }, - }" - :row="{}" - default="input" - v-model="data[column.name]" - :show-label="true" - component-prop="columnCreate" - :data-cy="`${column.name}-create-popup`" - /> - </slot> - <slot name="more-create-dialog" :data="data" /> + <slot name="previous-create-dialog" :data="data" /> + </div> + <div + class="grid-create" + :style="createComplement?.columnGridStyle" + > + <slot + v-for="column of splittedColumns.create" + :key="column.name" + :name="`column-create-${column.name}`" + :data="data" + :column-name="column.name" + :label="column.label" + > + <VnColumn + :column="{ + ...column, + ...column?.createAttrs, + }" + :row="{}" + default="input" + v-model="data[column.name]" + :show-label="true" + component-prop="columnCreate" + :data-cy="`${column.name}-create-popup`" + /> + </slot> + <slot name="more-create-dialog" :data="data" /> + </div> </div> - </div> + </slot> </template> </FormModelPopup> </QDialog> diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue index 35308c2c4..bee300f4e 100644 --- a/src/components/common/VnDms.vue +++ b/src/components/common/VnDms.vue @@ -177,6 +177,7 @@ function addDefaultData(data) { name="vn:attach" class="cursor-pointer" @click="inputFileRef.pickFiles()" + data-cy="attachFile" > <QTooltip>{{ t('globals.selectFile') }}</QTooltip> </QIcon> diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue index 424781a26..aafa9f4ba 100644 --- a/src/components/common/VnDmsList.vue +++ b/src/components/common/VnDmsList.vue @@ -389,10 +389,7 @@ defineExpose({ </div> </template> </QTable> - <div - v-else - class="info-row q-pa-md text-center" - > + <div v-else class="info-row q-pa-md text-center"> <h5> {{ t('No data to display') }} </h5> @@ -416,6 +413,7 @@ defineExpose({ v-shortcut @click="showFormDialog()" class="fill-icon" + data-cy="addButton" > <QTooltip> {{ t('Upload file') }} diff --git a/src/pages/Entry/Card/EntryBasicData.vue b/src/pages/Entry/Card/EntryBasicData.vue index 6462ed24a..34e4a0f9c 100644 --- a/src/pages/Entry/Card/EntryBasicData.vue +++ b/src/pages/Entry/Card/EntryBasicData.vue @@ -13,6 +13,7 @@ import VnSelect from 'src/components/common/VnSelect.vue'; import VnInputNumber from 'src/components/common/VnInputNumber.vue'; import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue'; import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue'; +import VnCheckbox from 'src/components/common/VnCheckbox.vue'; const route = useRoute(); const { t } = useI18n(); @@ -53,7 +54,7 @@ onMounted(() => { :clear-store-on-unmount="false" > <template #form="{ data }"> - <VnRow> + <VnRow class="q-py-sm"> <VnSelectTravelExtended :data="data" v-model="data.travelFk" @@ -65,7 +66,7 @@ onMounted(() => { :required="true" /> </VnRow> - <VnRow> + <VnRow class="q-py-sm"> <VnInput v-model="data.reference" :label="t('globals.reference')" /> <VnInputNumber v-model="data.invoiceAmount" @@ -73,7 +74,7 @@ onMounted(() => { :positive="false" /> </VnRow> - <VnRow> + <VnRow class="q-py-sm"> <VnInput v-model="data.invoiceNumber" :label="t('entry.summary.invoiceNumber')" @@ -84,12 +85,13 @@ onMounted(() => { :options="companiesOptions" option-value="id" option-label="code" + sort-by="code" map-options hide-selected :required="true" /> </VnRow> - <VnRow> + <VnRow class="q-py-sm"> <VnInputNumber :label="t('entry.summary.commission')" v-model="data.commission" @@ -102,9 +104,10 @@ onMounted(() => { :options="currenciesOptions" option-value="id" option-label="code" + sort-by="code" /> </VnRow> - <VnRow> + <VnRow class="q-py-sm"> <VnInputNumber v-model="data.initialTemperature" name="initialTemperature" @@ -121,8 +124,16 @@ onMounted(() => { :decimal-places="2" :positive="false" /> + <VnSelect + v-model="data.typeFk" + url="entryTypes" + :fields="['code', 'description']" + option-value="code" + optionLabel="description" + sortBy="description" + /> </VnRow> - <VnRow> + <VnRow class="q-py-sm"> <QInput :label="t('entry.basicData.observation')" type="textarea" @@ -132,14 +143,20 @@ onMounted(() => { fill-input /> </VnRow> - <VnRow> - <QCheckbox v-model="data.isOrdered" :label="t('entry.summary.ordered')" /> - <QCheckbox v-model="data.isConfirmed" :label="t('globals.confirmed')" /> - <QCheckbox - v-model="data.isExcludedFromAvailable" - :label="t('entry.summary.excludedFromAvailable')" + <VnRow class="q-py-sm"> + <VnCheckbox + v-model="data.isOrdered" + :label="t('entry.list.tableVisibleColumns.isOrdered')" /> - <QCheckbox + <VnCheckbox + v-model="data.isConfirmed" + :label="t('entry.list.tableVisibleColumns.isConfirmed')" + /> + <VnCheckbox + v-model="data.isExcludedFromAvailable" + :label="t('entry.list.tableVisibleColumns.isExcludedFromAvailable')" + /> + <VnCheckbox :disable="!isAdministrative()" v-model="data.isBooked" :label="t('entry.basicData.booked')" diff --git a/src/pages/Entry/Card/EntryBuys.vue b/src/pages/Entry/Card/EntryBuys.vue index 684ed5f59..44af80a88 100644 --- a/src/pages/Entry/Card/EntryBuys.vue +++ b/src/pages/Entry/Card/EntryBuys.vue @@ -2,7 +2,7 @@ import { useStateStore } from 'stores/useStateStore'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import { onMounted, ref } from 'vue'; +import { onMounted, ref, computed } from 'vue'; import { useState } from 'src/composables/useState'; @@ -16,6 +16,8 @@ import ItemDescriptor from 'src/pages/Item/Card/ItemDescriptor.vue'; import axios from 'axios'; import VnSelectEnum from 'src/components/common/VnSelectEnum.vue'; import { checkEntryLock } from 'src/composables/checkEntryLock'; +import VnRow from 'src/components/ui/VnRow.vue'; +import VnInput from 'src/components/common/VnInput.vue'; const $props = defineProps({ id: { @@ -57,31 +59,6 @@ const columns = [ createOrder: 12, width: '25px', }, - { - label: t('Buyer'), - name: 'workerFk', - component: 'select', - attrs: { - url: 'TicketRequests/getItemTypeWorker', - fields: ['id', 'nickname'], - optionLabel: 'nickname', - sortBy: 'nickname ASC', - optionValue: 'id', - }, - visible: false, - }, - { - label: t('Family'), - name: 'itemTypeFk', - component: 'select', - attrs: { - url: 'itemTypes', - fields: ['id', 'name'], - optionLabel: 'name', - optionValue: 'id', - }, - visible: false, - }, { name: 'id', isId: true, @@ -113,14 +90,8 @@ const columns = [ { align: 'center', label: t('Article'), + component: 'input', name: 'name', - component: 'select', - attrs: { - url: 'Items', - fields: ['id', 'name'], - optionLabel: 'name', - optionValue: 'id', - }, width: '85px', isEditable: false, }, @@ -212,7 +183,6 @@ const columns = [ }, }, { - align: 'center', labelAbbreviation: 'GM', label: t('Grouping selector'), toolTip: t('Grouping selector'), @@ -240,7 +210,6 @@ const columns = [ }, }, { - align: 'center', labelAbbreviation: 'G', label: 'Grouping', toolTip: 'Grouping', @@ -294,7 +263,7 @@ const columns = [ align: 'center', label: t('Amount'), name: 'amount', - width: '45px', + width: '75px', component: 'number', attrs: { positive: false, @@ -310,7 +279,9 @@ const columns = [ toolTip: t('Package'), name: 'price2', component: 'number', - createDisable: true, + createAttrs: { + disable: true, + }, width: '35px', create: true, format: (row) => parseFloat(row['price2']).toFixed(2), @@ -320,7 +291,9 @@ const columns = [ label: t('Box'), name: 'price3', component: 'number', - createDisable: true, + createAttrs: { + disable: true, + }, cellEvent: { 'update:modelValue': async (value, oldValue, row) => { row['price2'] = row['price2'] * (value / oldValue); @@ -340,13 +313,6 @@ const columns = [ toggleIndeterminate: false, }, component: 'checkbox', - cellEvent: { - 'update:modelValue': async (value, oldValue, row) => { - await axios.patch(`Items/${row['itemFk']}`, { - hasMinPrice: value, - }); - }, - }, width: '25px', }, { @@ -356,13 +322,6 @@ const columns = [ toolTip: t('Minimum price'), name: 'minPrice', component: 'number', - cellEvent: { - 'update:modelValue': async (value, oldValue, row) => { - await axios.patch(`Items/${row['itemFk']}`, { - minPrice: value, - }); - }, - }, width: '35px', style: (row) => { if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' }; @@ -425,6 +384,23 @@ const columns = [ }, }, ]; +const buyerFk = ref(null); +const itemTypeFk = ref(null); +const inkFk = ref(null); +const tag1 = ref(null); +const tag2 = ref(null); +const tag1Filter = ref(null); +const tag2Filter = ref(null); +const filter = computed(() => { + const where = {}; + where.workerFk = buyerFk.value; + where.itemTypeFk = itemTypeFk.value; + where.inkFk = inkFk.value; + where.tag1 = tag1.value; + where.tag2 = tag2.value; + + return { where }; +}); function getQuantityStyle(row) { if (row?.quantity !== row?.stickers * row?.packing) @@ -610,6 +586,7 @@ onMounted(() => { :url="`Entries/${entityId}/getBuyList`" search-url="EntryBuys" save-url="Buys/crud" + :filter="filter" :disable-option="{ card: true }" v-model:selected="selectedRows" @on-fetch="() => footerFetchDataRef.fetch()" @@ -655,7 +632,7 @@ onMounted(() => { :is-editable="editableMode" :without-header="!editableMode" :with-filters="editableMode" - :right-search="editableMode" + :right-search="false" :row-click="false" :columns="columns" :beforeSaveFn="beforeSave" @@ -666,6 +643,46 @@ onMounted(() => { data-cy="entry-buys" overlay > + <template #top-left> + <VnRow> + <VnSelect + :label="t('Buyer')" + v-model="buyerFk" + url="TicketRequests/getItemTypeWorker" + :fields="['id', 'nickname']" + option-label="nickname" + sort-by="nickname ASC" + /> + <VnSelect + :label="t('Family')" + v-model="itemTypeFk" + url="ItemTypes" + :fields="['id', 'name']" + option-label="name" + sort-by="name ASC" + /> + <VnSelect + :label="t('Color')" + v-model="inkFk" + url="Inks" + :fields="['id', 'name']" + option-label="name" + sort-by="name ASC" + /> + <VnInput + v-model="tag1Filter" + :label="t('Tag')" + @keyup.enter="tag1 = tag1Filter" + @remove="tag1 = null" + /> + <VnInput + v-model="tag2Filter" + :label="t('Tag')" + @keyup.enter="tag2 = tag2Filter" + @remove="tag2 = null" + /> + </VnRow> + </template> <template #column-hex="{ row }"> <VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" /> </template> @@ -696,7 +713,7 @@ onMounted(() => { </div> </template> <template #column-footer-weight> - {{ footer?.weight }} + <span class="q-pr-xs">{{ footer?.weight }}</span> </template> <template #column-footer-quantity> <span :style="getQuantityStyle(footer)" data-cy="footer-quantity"> @@ -704,9 +721,8 @@ onMounted(() => { </span> </template> <template #column-footer-amount> - <span :style="getAmountStyle(footer)" data-cy="footer-amount"> - {{ footer?.amount }} - </span> + <span data-cy="footer-amount">{{ footer?.amount }} / </span> + <span style="color: var(--q-positive)">{{ footer?.checkedAmount }}</span> </template> <template #column-create-itemFk="{ data }"> <VnSelect @@ -767,6 +783,8 @@ onMounted(() => { </template> <i18n> es: + Buyer: Comprador + Family: Familia Article: Artículo Siz.: Med. Size: Medida diff --git a/src/pages/Entry/Card/EntryNotes.vue b/src/pages/Entry/Card/EntryNotes.vue index 459c3b069..4159ed5ca 100644 --- a/src/pages/Entry/Card/EntryNotes.vue +++ b/src/pages/Entry/Card/EntryNotes.vue @@ -2,153 +2,82 @@ import { ref, computed } from 'vue'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; - -import FetchData from 'components/FetchData.vue'; -import CrudModel from 'components/CrudModel.vue'; -import VnInput from 'src/components/common/VnInput.vue'; -import VnSelect from 'src/components/common/VnSelect.vue'; +import VnTable from 'src/components/VnTable/VnTable.vue'; const { params } = useRoute(); const { t } = useI18n(); - +const selectedRows = ref([]); const entryObservationsRef = ref(null); -const entryObservationsOptions = ref([]); -const selected = ref([]); - -const sortEntryObservationOptions = (data) => { - entryObservationsOptions.value = [...data].sort((a, b) => - a.description.localeCompare(b.description), - ); -}; - +const entityId = ref(params.id); const columns = computed(() => [ { - name: 'observationType', - label: t('entry.notes.observationType'), - field: (row) => row.observationTypeFk, - sortable: true, - options: entryObservationsOptions.value, - required: true, - model: 'observationTypeFk', - optionValue: 'id', - optionLabel: 'description', - tabIndex: 1, - align: 'left', + name: 'id', + isId: true, + visible: false, + isEditable: false, + columnFilter: false, }, { + name: 'observationTypeFk', + label: t('entry.notes.observationType'), + component: 'select', + columnFilter: { inWhere: true }, + attrs: { + inWhere: true, + url: 'ObservationTypes', + fields: ['id', 'description'], + optionValue: 'id', + optionLabel: 'description', + sortBy: 'description', + }, + width: '30px', + create: true, + }, + { + align: 'left', name: 'description', label: t('globals.description'), - field: (row) => row.description, - tabIndex: 2, - align: 'left', + component: 'input', + columnFilter: false, + attrs: { autogrow: true }, + create: true, }, ]); + +const filter = computed(() => ({ + fields: ['id', 'entryFk', 'observationTypeFk', 'description'], + include: ['observationType'], + where: { entryFk: entityId }, +})); </script> <template> - <FetchData - url="ObservationTypes" - @on-fetch="(data) => sortEntryObservationOptions(data)" + <VnTable + ref="entryObservationsRef" + data-key="EntryObservations" + :columns="columns" + url="EntryObservations" + :user-filter="filter" + order="id ASC" + :disable-option="{ card: true }" + :is-editable="true" + :right-search="true" + v-model:selected="selectedRows" + :create="{ + urlCreate: 'EntryObservations', + title: t('Create note'), + onDataSaved: () => { + entryObservationsRef.reload(); + }, + formInitialData: { entryFk: entityId }, + }" + :table="{ + 'row-key': 'id', + selection: 'multiple', + }" auto-load /> - <CrudModel - data-key="EntryAccount" - url="EntryObservations" - model="EntryAccount" - :filter="{ - fields: ['id', 'entryFk', 'observationTypeFk', 'description'], - where: { entryFk: params.id }, - }" - ref="entryObservationsRef" - :data-required="{ entryFk: params.id }" - v-model:selected="selected" - auto-load - > - <template #body="{ rows, validate }"> - <QTable - v-model:selected="selected" - :columns="columns" - :rows="rows" - :pagination="{ rowsPerPage: 0 }" - row-key="$index" - selection="multiple" - hide-pagination - :grid="$q.screen.lt.md" - table-header-class="text-left" - > - <template #body-cell-observationType="{ row, col }"> - <QTd> - <VnSelect - v-model="row[col.model]" - :options="col.options" - :option-value="col.optionValue" - :option-label="col.optionLabel" - :autofocus="col.tabIndex == 1" - input-debounce="0" - hide-selected - :required="true" - /> - </QTd> - </template> - <template #body-cell-description="{ row, col }"> - <QTd> - <VnInput - :label="t('globals.description')" - v-model="row[col.name]" - :rules="validate('EntryObservation.description')" - /> - </QTd> - </template> - <template #item="props"> - <div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition"> - <QCard bordered flat> - <QCardSection> - <QCheckbox v-model="props.selected" dense /> - </QCardSection> - <QSeparator /> - <QList dense> - <QItem> - <QItemSection> - <VnSelect - v-model="props.row.observationTypeFk" - :options="entryObservationsOptions" - option-value="id" - option-label="description" - input-debounce="0" - hide-selected - :required="true" - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <VnInput - :label="t('globals.description')" - v-model="props.row.description" - :rules=" - validate('EntryObservation.description') - " - /> - </QItemSection> - </QItem> - </QList> - </QCard> - </div> - </template> - </QTable> - </template> - </CrudModel> - <QPageSticky position="bottom-right" :offset="[25, 25]"> - <QBtn - fab - color="primary" - icon="add" - v-shortcut="'+'" - @click="entryObservationsRef.insert()" - /> - </QPageSticky> </template> <i18n> es: - Add note: Añadir nota - Remove note: Quitar nota + Create note: Crear nota </i18n> diff --git a/src/pages/Entry/Card/EntrySummary.vue b/src/pages/Entry/Card/EntrySummary.vue index c40e2ba46..53967e66f 100644 --- a/src/pages/Entry/Card/EntrySummary.vue +++ b/src/pages/Entry/Card/EntrySummary.vue @@ -92,13 +92,13 @@ onMounted(async () => { </div> <div class="card-content"> <VnCheckbox - :label="t('entry.summary.ordered')" + :label="t('entry.list.tableVisibleColumns.isOrdered')" v-model="entry.isOrdered" :disable="true" size="xs" /> <VnCheckbox - :label="t('globals.confirmed')" + :label="t('entry.list.tableVisibleColumns.isConfirmed')" v-model="entry.isConfirmed" :disable="true" size="xs" @@ -110,7 +110,11 @@ onMounted(async () => { size="xs" /> <VnCheckbox - :label="t('entry.summary.excludedFromAvailable')" + :label=" + t( + 'entry.list.tableVisibleColumns.isExcludedFromAvailable', + ) + " v-model="entry.isExcludedFromAvailable" :disable="true" size="xs" diff --git a/src/pages/Entry/EntryFilter.vue b/src/pages/Entry/EntryFilter.vue index c283e4a0b..82bcb1a79 100644 --- a/src/pages/Entry/EntryFilter.vue +++ b/src/pages/Entry/EntryFilter.vue @@ -85,7 +85,7 @@ const entryFilterPanel = ref(); </QItemSection> <QItemSection> <QCheckbox - :label="t('entry.list.tableVisibleColumns.isConfirmed')" + label="LE" v-model="params.isConfirmed" toggle-indeterminate > @@ -102,6 +102,7 @@ const entryFilterPanel = ref(); v-model="params.landed" @update:model-value="searchFn()" is-outlined + data-cy="landed" /> </QItemSection> </QItem> @@ -121,13 +122,6 @@ const entryFilterPanel = ref(); rounded /> </QItemSection> - <QItemSection> - <VnInput - v-model="params.invoiceNumber" - :label="t('params.invoiceNumber')" - is-outlined - /> - </QItemSection> </QItem> <QItem> <QItemSection> @@ -171,6 +165,7 @@ const entryFilterPanel = ref(); @update:model-value="searchFn()" url="Warehouses" :fields="['id', 'name']" + sort-by="name ASC" hide-selected dense outlined @@ -186,6 +181,7 @@ const entryFilterPanel = ref(); @update:model-value="searchFn()" url="Warehouses" :fields="['id', 'name']" + sort-by="name ASC" hide-selected dense outlined @@ -233,15 +229,6 @@ const entryFilterPanel = ref(); /> </QItemSection> </QItem> - <QItem> - <QItemSection> - <VnInput - v-model="params.evaNotes" - :label="t('params.evaNotes')" - is-outlined - /> - </QItemSection> - </QItem> </template> </VnFilterPanel> </template> @@ -267,7 +254,7 @@ en: hasToShowDeletedEntries: Show deleted entries es: params: - isExcludedFromAvailable: Inventario + isExcludedFromAvailable: Excluida isOrdered: Pedida isConfirmed: Confirmado isReceived: Recibida diff --git a/src/pages/Entry/EntryLatestBuys.vue b/src/pages/Entry/EntryLatestBuys.vue deleted file mode 100644 index 73fdcbbbf..000000000 --- a/src/pages/Entry/EntryLatestBuys.vue +++ /dev/null @@ -1,264 +0,0 @@ -<script setup> -import { onMounted, onUnmounted, ref } from 'vue'; -import { useI18n } from 'vue-i18n'; -import { useStateStore } from 'stores/useStateStore'; -import { toDate } from 'src/filters'; - -import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; -import RightMenu from 'src/components/common/RightMenu.vue'; -import EntryLatestBuysFilter from './EntryLatestBuysFilter.vue'; -import VnTable from 'components/VnTable/VnTable.vue'; -import VnImg from 'src/components/ui/VnImg.vue'; - -const stateStore = useStateStore(); -const { t } = useI18n(); -const tableRef = ref(); -const columns = [ - { - align: 'center', - label: t('entry.latestBuys.tableVisibleColumns.image'), - name: 'itemFk', - columnField: { - component: VnImg, - attrs: ({ row }) => { - return { - id: row.id, - size: '50x50', - }; - }, - }, - columnFilter: false, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.itemFk'), - name: 'itemFk', - isTitle: true, - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.summary.packing'), - name: 'packing', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.summary.grouping'), - name: 'grouping', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('globals.quantity'), - name: 'quantity', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('globals.description'), - name: 'description', - }, - { - align: 'left', - label: t('globals.size'), - name: 'size', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('globals.tags'), - name: 'tags', - }, - { - align: 'left', - label: t('globals.type'), - name: 'type', - }, - { - align: 'left', - label: t('globals.intrastat'), - name: 'intrastat', - }, - { - align: 'left', - label: t('globals.origin'), - name: 'origin', - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.weightByPiece'), - name: 'weightByPiece', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.isActive'), - name: 'isActive', - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.family'), - name: 'family', - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.entryFk'), - name: 'entryFk', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.summary.buyingValue'), - name: 'buyingValue', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.freightValue'), - name: 'freightValue', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.comissionValue'), - name: 'comissionValue', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.packageValue'), - name: 'packageValue', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.isIgnored'), - name: 'isIgnored', - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.price2'), - name: 'price2', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.price3'), - name: 'price3', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.minPrice'), - name: 'minPrice', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.ektFk'), - name: 'ektFk', - }, - { - align: 'left', - label: t('globals.weight'), - name: 'weight', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.buys.packagingFk'), - name: 'packagingFk', - columnFilter: { - component: 'number', - inWhere: true, - }, - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.packingOut'), - name: 'packingOut', - }, - { - align: 'left', - label: t('entry.latestBuys.tableVisibleColumns.landing'), - name: 'landing', - component: 'date', - columnField: { - component: null, - }, - format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landing)), - }, -]; - -onMounted(async () => { - stateStore.rightDrawer = true; -}); - -onUnmounted(() => (stateStore.rightDrawer = false)); -</script> - -<template> - <RightMenu> - <template #right-panel> - <EntryLatestBuysFilter data-key="LatestBuys" /> - </template> - </RightMenu> - <VnSubToolbar /> - <VnTable - ref="tableRef" - data-key="LatestBuys" - url="Buys/latestBuysFilter" - order="id DESC" - :columns="columns" - redirect="entry" - :row-click="({ entryFk }) => tableRef.redirect(entryFk)" - auto-load - :right-search="false" - /> -</template> diff --git a/src/pages/Entry/EntryLatestBuysFilter.vue b/src/pages/Entry/EntryLatestBuysFilter.vue deleted file mode 100644 index 19b457524..000000000 --- a/src/pages/Entry/EntryLatestBuysFilter.vue +++ /dev/null @@ -1,168 +0,0 @@ -<script setup> -import { ref } from 'vue'; -import { useI18n } from 'vue-i18n'; -import VnInputDate from 'src/components/common/VnInputDate.vue'; -import VnInput from 'components/common/VnInput.vue'; -import VnSelect from 'components/common/VnSelect.vue'; -import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue'; -import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue'; - -const { t } = useI18n(); - -defineProps({ - dataKey: { - type: String, - required: true, - }, -}); - -const tagValues = ref([]); -</script> - -<template> - <FetchData - url="TicketRequests/getItemTypeWorker" - auto-load - :filter="{ fields: ['id', 'nickname'], order: 'nickname ASC' }" - @on-fetch="(data) => (itemTypeWorkersOptions = data)" - /> - <ItemsFilterPanel :data-key="dataKey" :custom-tags="['tags']"> - <template #body="{ params, searchFn }"> - <QItem class="q-my-md"> - <QItemSection> - <VnSelect - :label="t('components.itemsFilterPanel.buyerFk')" - v-model="params.buyerFk" - :options="itemTypeWorkersOptions" - option-value="id" - option-label="nickname" - :fields="['id', 'nickname']" - sort-by="nickname ASC" - dense - outlined - rounded - use-input - @update:model-value="searchFn()" - /> - </QItemSection> - </QItem> - <QItem class="q-my-md"> - <QItemSection> - <VnSelectSupplier - v-model="params.supplierFk" - url="Suppliers" - :fields="['id', 'name', 'nickname']" - sort-by="name ASC" - dense - outlined - rounded - /> - </QItemSection> - </QItem> - <QItem class="q-my-md"> - <QItemSection> - <VnInputDate - :label="t('components.itemsFilterPanel.started')" - v-model="params.from" - is-outlined - @update:model-value="searchFn()" - /> - </QItemSection> - </QItem> - <QItem class="q-my-md"> - <QItemSection> - <VnInputDate - :label="t('components.itemsFilterPanel.ended')" - v-model="params.to" - is-outlined - @update:model-value="searchFn()" - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <QCheckbox - :label="t('components.itemsFilterPanel.active')" - v-model="params.active" - toggle-indeterminate - @update:model-value="searchFn()" - /> - </QItemSection> - <QItemSection> - <QCheckbox - :label="t('globals.visible')" - v-model="params.visible" - toggle-indeterminate - @update:model-value="searchFn()" - /> - </QItemSection> - </QItem> - <QItem> - <QItemSection> - <QCheckbox - :label="t('components.itemsFilterPanel.floramondo')" - v-model="params.floramondo" - toggle-indeterminate - @update:model-value="searchFn()" - /> - </QItemSection> - </QItem> - - <QItem - v-for="(value, index) in tagValues" - :key="value" - class="q-mt-md filter-value" - > - <QItemSection class="col"> - <VnSelect - :label="t('params.tag')" - v-model="value.selectedTag" - :options="tagOptions" - option-label="name" - dense - outlined - rounded - :emit-value="false" - use-input - :is-clearable="false" - @update:model-value="getSelectedTagValues(value)" - /> - </QItemSection> - <QItemSection class="col"> - <VnSelect - v-if="!value?.selectedTag?.isFree && value.valueOptions" - :label="t('params.value')" - v-model="value.value" - :options="value.valueOptions || []" - option-value="value" - option-label="value" - dense - outlined - rounded - emit-value - use-input - :disable="!value" - :is-clearable="false" - class="filter-input" - @update:model-value="applyTags(params, searchFn)" - /> - <VnInput - v-else - v-model="value.value" - :label="t('params.value')" - :disable="!value" - is-outlined - class="filter-input" - :is-clearable="false" - @keyup.enter="applyTags(params, searchFn)" - /> - </QItemSection> - <QIcon - name="delete" - class="filter-icon" - @click="removeTag(index, params, searchFn)" - /> - </QItem> - </template> - </ItemsFilterPanel> -</template> diff --git a/src/pages/Entry/EntryList.vue b/src/pages/Entry/EntryList.vue index 3b5434cb8..5ebad3144 100644 --- a/src/pages/Entry/EntryList.vue +++ b/src/pages/Entry/EntryList.vue @@ -107,9 +107,8 @@ const columns = computed(() => [ attrs: { url: 'suppliers', fields: ['id', 'name'], - where: { order: 'name DESC' }, + sortBy: 'name ASC', }, - format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName), width: '110px', }, { @@ -145,6 +144,7 @@ const columns = computed(() => [ attrs: { url: 'agencyModes', fields: ['id', 'name'], + sortBy: 'name ASC', }, columnField: { component: null, @@ -158,7 +158,6 @@ const columns = computed(() => [ component: 'input', }, { - align: 'left', label: t('entry.list.tableVisibleColumns.warehouseOutFk'), name: 'warehouseOutFk', cardVisible: true, @@ -166,6 +165,7 @@ const columns = computed(() => [ attrs: { url: 'warehouses', fields: ['id', 'name'], + sortBy: 'name ASC', }, columnField: { component: null, @@ -174,7 +174,6 @@ const columns = computed(() => [ width: '65px', }, { - align: 'left', label: t('entry.list.tableVisibleColumns.warehouseInFk'), name: 'warehouseInFk', cardVisible: true, @@ -182,6 +181,7 @@ const columns = computed(() => [ attrs: { url: 'warehouses', fields: ['id', 'name'], + sortBy: 'name ASC', }, columnField: { component: null, @@ -190,7 +190,6 @@ const columns = computed(() => [ width: '65px', }, { - align: 'left', labelAbbreviation: t('Type'), label: t('entry.list.tableVisibleColumns.entryTypeDescription'), toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'), @@ -201,6 +200,7 @@ const columns = computed(() => [ fields: ['code', 'description'], optionValue: 'code', optionLabel: 'description', + sortBy: 'description', }, width: '65px', format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription), diff --git a/src/pages/Entry/EntryStockBought.vue b/src/pages/Entry/EntryStockBought.vue index 41f78617c..5da51d5a6 100644 --- a/src/pages/Entry/EntryStockBought.vue +++ b/src/pages/Entry/EntryStockBought.vue @@ -1,24 +1,23 @@ <script setup> import { ref, computed } from 'vue'; import { useI18n } from 'vue-i18n'; -import { useState } from 'src/composables/useState'; -import { useQuasar } from 'quasar'; +import { useQuasar, date } from 'quasar'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; 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'; 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 TravelDescriptorProxy from '../Travel/Card/TravelDescriptorProxy.vue'; +import { useFilterParams } from 'src/composables/useFilterParams'; +import axios from 'axios'; const { t } = useI18n(); const quasar = useQuasar(); -const state = useState(); -const user = state.getUser(); +const filterDate = ref(useFilterParams('StockBoughts').params); const footer = ref({ bought: 0, reserve: 0 }); const columns = computed(() => [ { @@ -46,7 +45,7 @@ const columns = computed(() => [ optionValue: 'id', }, columnFilter: false, - width: '50px', + width: '60%', }, { align: 'center', @@ -56,20 +55,20 @@ const columns = computed(() => [ create: true, component: 'number', summation: true, - width: '50px', format: ({ reserve }, dashIfEmpty) => dashIfEmpty(round(reserve)), + width: '20%', }, { - align: 'center', + align: 'right', label: t('entryStockBought.bought'), name: 'bought', summation: true, cardVisible: true, style: ({ reserve, bought }) => boughtStyle(bought, reserve), columnFilter: false, + width: '20%', }, { - align: 'left', label: t('entryStockBought.date'), name: 'dated', component: 'date', @@ -77,7 +76,7 @@ const columns = computed(() => [ create: true, }, { - align: 'left', + align: 'center', name: 'tableActions', actions: [ { @@ -90,7 +89,7 @@ const columns = computed(() => [ component: EntryStockBoughtDetail, componentProps: { workerFk: row.workerFk, - dated: userParams.value.dated, + dated: filterDate.value.dated, }, }); }, @@ -98,39 +97,29 @@ const columns = computed(() => [ ], }, ]); - const fetchDataRef = ref(); const travelDialogRef = ref(false); const tableRef = ref(); const travel = ref(null); -const userParams = ref({ - dated: Date.vnNew().toJSON(), -}); - -const filter = ref({ - fields: ['id', 'm3', 'warehouseInFk'], +const filter = computed(() => ({ + fields: ['id', 'm3', 'ref', 'warehouseInFk'], include: [ { relation: 'warehouseIn', scope: { - fields: ['code'], + fields: ['code', 'name'], }, }, ], where: { - shipped: (userParams.value.dated - ? new Date(userParams.value.dated) - : Date.vnNew() - ).setHours(0, 0, 0, 0), + shipped: date.adjustDate(filterDate.value.dated, { + hour: 0, + minute: 0, + second: 0, + }), m3: { neq: null }, }, -}); - -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; @@ -151,6 +140,31 @@ function round(value) { function boughtStyle(bought, reserve) { return reserve < bought ? { color: 'var(--q-negative)' } : ''; } + +async function beforeSave(data, getChanges) { + const changes = data.creates; + if (!changes) return data; + const patchPromises = []; + + for (const change of changes) { + if (change?.isReal === false && change?.reserve > 0) { + const postData = { + workerFk: change.workerFk, + reserve: change.reserve, + dated: filterDate.value.dated, + }; + const promise = axios.post('StockBoughts', postData).catch((error) => { + console.error('Error processing change: ', change, error); + }); + + patchPromises.push(promise); + } + } + + await Promise.all(patchPromises); + const filteredChanges = changes.filter((change) => change?.isReal !== false); + data.creates = filteredChanges; +} </script> <template> <VnSubToolbar> @@ -158,18 +172,17 @@ function boughtStyle(bought, reserve) { <FetchData ref="fetchDataRef" url="Travels" - auto-load :filter="filter" @on-fetch=" (data) => { travel = data.find( - (data) => data.warehouseIn?.code.toLowerCase() === 'vnh', + (data) => data.warehouseIn?.code?.toLowerCase() === 'vnh', ); } " /> <VnRow class="travel"> - <div v-if="travel"> + <div v-show="travel"> <span style="color: var(--vn-label-color)"> {{ t('entryStockBought.purchaseSpaces') }}: </span> @@ -180,7 +193,7 @@ function boughtStyle(bought, reserve) { v-if="travel?.m3" style="max-width: 20%" flat - icon="edit" + icon="search" @click="openDialog()" :title="t('entryStockBought.editTravel')" color="primary" @@ -195,57 +208,42 @@ function boughtStyle(bought, reserve) { :url-update="`Travels/${travel?.id}`" model="travel" :title="t('Travel m3')" - :form-initial-data="{ id: travel?.id, m3: travel?.m3 }" + :form-initial-data="travel" @on-data-saved="fetchDataRef.fetch()" > <template #form-inputs="{ data }"> - <VnInput - v-model="data.id" - :label="t('id')" - type="number" - disable - readonly - /> + <span class="link"> + {{ data.ref }} + <TravelDescriptorProxy :id="data.id" /> + </span> <VnInput v-model="data.m3" :label="t('m3')" type="number" /> </template> </FormModelPopup> </QDialog> - <RightMenu> - <template #right-panel> - <EntryStockBoughtFilter - data-key="StockBoughts" - @set-user-params="setUserParams" - /> - </template> - </RightMenu> <div class="table-container"> <div class="column items-center"> <VnTable ref="tableRef" data-key="StockBoughts" url="StockBoughts/getStockBought" + :beforeSaveFn="beforeSave" save-url="StockBoughts/crud" search-url="StockBoughts" - order="reserve DESC" - :right-search="false" + order="bought DESC" :is-editable="true" - @on-fetch="(data) => setFooter(data)" - :create="{ - urlCreate: 'StockBoughts', - title: t('entryStockBought.reserveSomeSpace'), - onDataSaved: () => tableRef.reload(), - formInitialData: { - workerFk: user.id, - dated: Date.vnNow(), - }, - }" + @on-fetch=" + async (data) => { + setFooter(data); + await fetchDataRef.fetch(); + } + " :columns="columns" - :user-params="userParams" :footer="true" table-height="80vh" - auto-load :column-search="false" :without-header="true" + :user-params="{ dated: Date.vnNew() }" + auto-load > <template #column-workerFk="{ row }"> <span class="link" @click.stop> @@ -278,9 +276,6 @@ function boughtStyle(bought, reserve) { .column { min-width: 35%; margin-top: 5%; - display: flex; - flex-direction: column; - align-items: center; } .text-negative { color: $negative !important; diff --git a/src/pages/Entry/EntryStockBoughtFilter.vue b/src/pages/Entry/EntryStockBoughtFilter.vue deleted file mode 100644 index 136881f17..000000000 --- a/src/pages/Entry/EntryStockBoughtFilter.vue +++ /dev/null @@ -1,70 +0,0 @@ -<script setup> -import { useI18n } from 'vue-i18n'; -import { onMounted } from 'vue'; -import { useStateStore } from 'stores/useStateStore'; - -import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; -import VnInputDate from 'src/components/common/VnInputDate.vue'; - -const { t } = useI18n(); -const props = defineProps({ - dataKey: { - type: String, - required: true, - }, -}); -const stateStore = useStateStore(); -const emit = defineEmits(['set-user-params']); -const setUserParams = (params) => { - emit('set-user-params', params); -}; -onMounted(async () => { - stateStore.rightDrawer = true; -}); -</script> - -<template> - <VnFilterPanel - :data-key="props.dataKey" - :search-button="true" - search-url="StockBoughts" - @set-user-params="setUserParams" - > - <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, searchFn }"> - <QItem class="q-my-sm"> - <QItemSection> - <VnInputDate - id="date" - v-model="params.dated" - @update:model-value=" - (value) => { - params.dated = value; - setUserParams(params); - searchFn(); - } - " - :label="t('Date')" - is-outlined - /> - </QItemSection> - </QItem> - </template> - </VnFilterPanel> -</template> -<i18n> - en: - params: - dated: Date - workerFk: Worker - es: - Date: Fecha - params: - dated: Fecha - workerFk: Trabajador -</i18n> diff --git a/src/pages/Entry/MyEntries.vue b/src/pages/Entry/EntrySupplier.vue similarity index 67% rename from src/pages/Entry/MyEntries.vue rename to src/pages/Entry/EntrySupplier.vue index 3f7566ae0..d8b17007f 100644 --- a/src/pages/Entry/MyEntries.vue +++ b/src/pages/Entry/EntrySupplier.vue @@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import { toDate } from 'src/filters/index'; import { useQuasar } from 'quasar'; -import EntryBuysTableDialog from './EntryBuysTableDialog.vue'; +import EntrySupplierlDetail from './EntrySupplierlDetail.vue'; import VnTable from 'components/VnTable/VnTable.vue'; const { t } = useI18n(); @@ -18,18 +18,28 @@ const columns = computed(() => [ { align: 'left', name: 'id', - label: t('myEntries.id'), + label: t('entrySupplier.id'), columnFilter: false, + isId: true, + chip: { + condition: () => true, + }, + }, + { + align: 'left', + name: 'supplierName', + label: t('entrySupplier.supplierName'), + cardVisible: true, isTitle: true, }, { visible: false, align: 'right', - label: t('myEntries.shipped'), + label: t('entrySupplier.shipped'), name: 'shipped', columnFilter: { name: 'fromShipped', - label: t('myEntries.fromShipped'), + label: t('entrySupplier.fromShipped'), component: 'date', }, format: ({ shipped }) => toDate(shipped), @@ -37,26 +47,26 @@ const columns = computed(() => [ { visible: false, align: 'left', - label: t('myEntries.shipped'), + label: t('entrySupplier.shipped'), name: 'shipped', columnFilter: { name: 'toShipped', - label: t('myEntries.toShipped'), + label: t('entrySupplier.toShipped'), component: 'date', }, format: ({ shipped }) => toDate(shipped), cardVisible: true, }, { - align: 'right', - label: t('myEntries.shipped'), + align: 'left', + label: t('entrySupplier.shipped'), name: 'shipped', columnFilter: false, format: ({ shipped }) => toDate(shipped), }, { - align: 'right', - label: t('myEntries.landed'), + align: 'left', + label: t('entrySupplier.landed'), name: 'landed', columnFilter: false, format: ({ landed }) => toDate(landed), @@ -64,15 +74,13 @@ const columns = computed(() => [ { align: 'right', - label: t('myEntries.wareHouseIn'), + label: t('entrySupplier.wareHouseIn'), name: 'warehouseInFk', - format: (row) => { - row.warehouseInName; - }, + format: ({ warehouseInName }) => warehouseInName, cardVisible: true, columnFilter: { name: 'warehouseInFk', - label: t('myEntries.warehouseInFk'), + label: t('entrySupplier.warehouseInFk'), component: 'select', attrs: { url: 'warehouses', @@ -86,13 +94,13 @@ const columns = computed(() => [ }, { align: 'left', - label: t('myEntries.daysOnward'), + label: t('entrySupplier.daysOnward'), name: 'daysOnward', visible: false, }, { align: 'left', - label: t('myEntries.daysAgo'), + label: t('entrySupplier.daysAgo'), name: 'daysAgo', visible: false, }, @@ -101,8 +109,8 @@ const columns = computed(() => [ name: 'tableActions', actions: [ { - title: t('myEntries.printLabels'), - icon: 'move_item', + title: t('entrySupplier.printLabels'), + icon: 'search', isPrimary: true, action: (row) => printBuys(row.id), }, @@ -112,7 +120,7 @@ const columns = computed(() => [ const printBuys = (rowId) => { quasar.dialog({ - component: EntryBuysTableDialog, + component: EntrySupplierlDetail, componentProps: { id: rowId, }, @@ -121,19 +129,18 @@ const printBuys = (rowId) => { </script> <template> <VnSearchbar - data-key="myEntriesList" + data-key="entrySupplierList" url="Entries/filter" - :label="t('myEntries.search')" - :info="t('myEntries.searchInfo')" + :label="t('entrySupplier.search')" + :info="t('entrySupplier.searchInfo')" /> <VnTable - data-key="myEntriesList" + data-key="entrySupplierList" url="Entries/filter" :columns="columns" :user-params="params" default-mode="card" order="shipped DESC" auto-load - chip-locale="myEntries" /> </template> diff --git a/src/pages/Entry/EntryBuysTableDialog.vue b/src/pages/Entry/EntrySupplierlDetail.vue similarity index 87% rename from src/pages/Entry/EntryBuysTableDialog.vue rename to src/pages/Entry/EntrySupplierlDetail.vue index 7a6c4ac43..01f6012c5 100644 --- a/src/pages/Entry/EntryBuysTableDialog.vue +++ b/src/pages/Entry/EntrySupplierlDetail.vue @@ -30,7 +30,7 @@ const entriesTableColumns = computed(() => [ align: 'left', name: 'itemFk', field: 'itemFk', - label: t('entry.latestBuys.tableVisibleColumns.itemFk'), + label: t('entrySupplier.itemId'), }, { align: 'left', @@ -65,7 +65,15 @@ const entriesTableColumns = computed(() => [ ]); function downloadCSV(rows) { - const headers = ['id', 'itemFk', 'name', 'stickers', 'packing', 'grouping', 'comment']; + const headers = [ + 'id', + 'itemFk', + 'name', + 'stickers', + 'packing', + 'grouping', + 'comment', + ]; const csvRows = rows.map((row) => { const buy = row; @@ -119,17 +127,18 @@ function downloadCSV(rows) { > <template #top-left> <QBtn - :label="t('myEntries.downloadCsv')" + :label="t('entrySupplier.downloadCsv')" color="primary" icon="csv" @click="downloadCSV(rows)" unelevated + data-cy="downloadCsvBtn" /> </template> <template #top-right> <QBtn class="q-mr-lg" - :label="t('myEntries.printLabels')" + :label="t('entrySupplier.printLabels')" color="primary" icon="print" @click=" @@ -148,13 +157,18 @@ function downloadCSV(rows) { v-if="props.row.stickers > 0" @click=" openReport( - `Entries/${props.row.id}/buy-label-supplier` + `Entries/${props.row.id}/buy-label-supplier`, + {}, + true, ) " unelevated + color="primary" + flat + data-cy="seeLabelBtn" > <QTooltip>{{ - t('myEntries.viewLabel') + t('entrySupplier.viewLabel') }}</QTooltip> </QBtn> </QTr> diff --git a/src/pages/Entry/EntryWasteRecalc.vue b/src/pages/Entry/EntryWasteRecalc.vue index 6ae200ed7..2fcd0f843 100644 --- a/src/pages/Entry/EntryWasteRecalc.vue +++ b/src/pages/Entry/EntryWasteRecalc.vue @@ -38,7 +38,7 @@ const recalc = async () => { <template> <div class="q-pa-lg row justify-center"> - <QCard class="bg-light" style="width: 300px"> + <QCard class="bg-light" style="width: 300px" data-cy="wasteRecalc"> <QCardSection> <VnInputDate class="q-mb-lg" @@ -46,6 +46,7 @@ const recalc = async () => { :label="$t('globals.from')" rounded dense + data-cy="dateFrom" /> <VnInputDate class="q-mb-lg" @@ -55,6 +56,7 @@ const recalc = async () => { :disable="!dateFrom" rounded dense + data-cy="dateTo" /> <QBtn color="primary" @@ -63,6 +65,7 @@ const recalc = async () => { :loading="isLoading" :disable="isLoading || !(dateFrom && dateTo)" @click="recalc()" + data-cy="recalc" /> </QCardSection> </QCard> diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml index 88b16cb03..0bc92a5ea 100644 --- a/src/pages/Entry/locale/en.yml +++ b/src/pages/Entry/locale/en.yml @@ -6,7 +6,7 @@ entry: list: newEntry: New entry tableVisibleColumns: - isExcludedFromAvailable: Exclude from inventory + isExcludedFromAvailable: Excluded from available isOrdered: Ordered isConfirmed: Ready to label isReceived: Received @@ -33,7 +33,7 @@ entry: invoiceAmount: Invoice amount ordered: Ordered booked: Booked - excludedFromAvailable: Inventory + excludedFromAvailable: Excluded travelReference: Reference travelAgency: Agency travelShipped: Shipped @@ -55,7 +55,7 @@ entry: commission: Commission observation: Observation booked: Booked - excludedFromAvailable: Inventory + excludedFromAvailable: Excluded initialTemperature: Ini °C finalTemperature: Fin °C buys: @@ -65,27 +65,10 @@ entry: printedStickers: Printed stickers notes: observationType: Observation type - latestBuys: - tableVisibleColumns: - image: Picture - itemFk: Item ID - weightByPiece: Weight/Piece - isActive: Active - family: Family - entryFk: Entry - freightValue: Freight value - comissionValue: Commission value - packageValue: Package value - isIgnored: Is ignored - price2: Grouping - price3: Packing - minPrice: Min - ektFk: Ekt - packingOut: Package out - landing: Landing - isExcludedFromAvailable: Es inventory params: - isExcludedFromAvailable: Exclude from inventory + entryFk: Entry + observationTypeFk: Observation type + isExcludedFromAvailable: Excluded from available isOrdered: Ordered isConfirmed: Ready to label isReceived: Received @@ -127,13 +110,17 @@ entry: company_name: Company name itemTypeFk: Item type workerFk: Worker id + daysAgo: Days ago + toShipped: T. shipped + fromShipped: F. shipped + supplierName: Supplier search: Search entries searchInfo: You can search by entry reference descriptorMenu: showEntryReport: Show entry report entryFilter: params: - isExcludedFromAvailable: Exclude from inventory + isExcludedFromAvailable: Excluded from available invoiceNumber: Invoice number travelFk: Travel companyFk: Company @@ -155,7 +142,7 @@ entryFilter: warehouseOutFk: Origin warehouseInFk: Destiny entryTypeCode: Entry type -myEntries: +entrySupplier: id: ID landed: Landed shipped: Shipped @@ -170,6 +157,8 @@ myEntries: downloadCsv: Download CSV search: Search entries searchInfo: You can search by entry reference + supplierName: Supplier + itemId: Item id entryStockBought: travel: Travel editTravel: Edit travel diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml index 3025d64cb..10d863ea2 100644 --- a/src/pages/Entry/locale/es.yml +++ b/src/pages/Entry/locale/es.yml @@ -6,7 +6,7 @@ entry: list: newEntry: Nueva entrada tableVisibleColumns: - isExcludedFromAvailable: Excluir del inventario + isExcludedFromAvailable: Excluir del disponible isOrdered: Pedida isConfirmed: Lista para etiquetar isReceived: Recibida @@ -33,7 +33,7 @@ entry: invoiceAmount: Importe ordered: Pedida booked: Contabilizada - excludedFromAvailable: Inventario + excludedFromAvailable: Excluido travelReference: Referencia travelAgency: Agencia travelShipped: F. envio @@ -56,7 +56,7 @@ entry: observation: Observación commission: Comisión booked: Contabilizada - excludedFromAvailable: Inventario + excludedFromAvailable: Excluido initialTemperature: Ini °C finalTemperature: Fin °C buys: @@ -66,30 +66,12 @@ entry: printedStickers: Etiquetas impresas notes: observationType: Tipo de observación - latestBuys: - tableVisibleColumns: - image: Foto - itemFk: Id Artículo - weightByPiece: Peso (gramos)/tallo - isActive: Activo - family: Familia - entryFk: Entrada - freightValue: Porte - comissionValue: Comisión - packageValue: Embalaje - isIgnored: Ignorado - price2: Grouping - price3: Packing - minPrice: Min - ektFk: Ekt - packingOut: Embalaje envíos - landing: Llegada - isExcludedFromAvailable: Es inventario - search: Buscar entradas searchInfo: Puedes buscar por referencia de entrada params: - isExcludedFromAvailable: Excluir del inventario + entryFk: Entrada + observationTypeFk: Tipo de observación + isExcludedFromAvailable: Excluir del disponible isOrdered: Pedida isConfirmed: Lista para etiquetar isReceived: Recibida @@ -131,9 +113,13 @@ entry: company_name: Nombre empresa itemTypeFk: Familia workerFk: Comprador + daysAgo: Días atras + toShipped: F. salida(hasta) + fromShipped: F. salida(desde) + supplierName: Proveedor entryFilter: params: - isExcludedFromAvailable: Inventario + isExcludedFromAvailable: Excluido isOrdered: Pedida isConfirmed: Confirmado isReceived: Recibida @@ -149,7 +135,7 @@ entryFilter: warehouseInFk: Destino entryTypeCode: Tipo de entrada hasToShowDeletedEntries: Mostrar entradas eliminadas -myEntries: +entrySupplier: id: ID landed: F. llegada shipped: F. salida @@ -164,10 +150,12 @@ myEntries: downloadCsv: Descargar CSV search: Buscar entradas searchInfo: Puedes buscar por referencia de la entrada + supplierName: Proveedor + itemId: Id artículo entryStockBought: travel: Envío editTravel: Editar envío - purchaseSpaces: Espacios de compra + purchaseSpaces: Camiones reservados buyer: Comprador reserve: Reservado bought: Comprado diff --git a/src/router/modules/entry.js b/src/router/modules/entry.js index b5656dc5f..02eea8c6c 100644 --- a/src/router/modules/entry.js +++ b/src/router/modules/entry.js @@ -81,7 +81,7 @@ export default { keyBinding: 'e', menu: [ 'EntryList', - 'MyEntries', + 'EntrySupplier', 'EntryLatestBuys', 'EntryStockBought', 'EntryWasteRecalc', @@ -125,21 +125,12 @@ export default { }, { path: 'my', - name: 'MyEntries', + name: 'EntrySupplier', meta: { title: 'labeler', icon: 'sell', }, - component: () => import('src/pages/Entry/MyEntries.vue'), - }, - { - path: 'latest-buys', - name: 'EntryLatestBuys', - meta: { - title: 'latestBuys', - icon: 'contact_support', - }, - component: () => import('src/pages/Entry/EntryLatestBuys.vue'), + component: () => import('src/pages/Entry/EntrySupplier.vue'), }, { path: 'stock-Bought', diff --git a/test/cypress/integration/Order/orderCatalog.spec.js b/test/cypress/integration/Order/orderCatalog.spec.js index a106d0e8a..386e3b2aa 100644 --- a/test/cypress/integration/Order/orderCatalog.spec.js +++ b/test/cypress/integration/Order/orderCatalog.spec.js @@ -34,7 +34,7 @@ describe('OrderCatalog', () => { searchByCustomTagInput('Silver'); }); - it('filters by custom value dialog', () => { + it.skip('filters by custom value dialog', () => { Cypress.on('uncaught:exception', (err) => { if (err.message.includes('canceled')) { return false; diff --git a/test/cypress/integration/claim/claimDevelopment.spec.js b/test/cypress/integration/claim/claimDevelopment.spec.js index e60ecd7b4..097d870df 100755 --- a/test/cypress/integration/claim/claimDevelopment.spec.js +++ b/test/cypress/integration/claim/claimDevelopment.spec.js @@ -1,5 +1,5 @@ /// <reference types="cypress" /> -describe('ClaimDevelopment', () => { +describe.skip('ClaimDevelopment', () => { const claimId = 1; const firstLineReason = 'tbody > :nth-child(1) > :nth-child(2)'; const thirdRow = 'tbody > :nth-child(3)'; @@ -19,7 +19,7 @@ describe('ClaimDevelopment', () => { cy.getValue(firstLineReason).should('equal', lastReason); }); - it('should edit line', () => { + it.skip('should edit line', () => { cy.selectOption(firstLineReason, newReason); cy.saveCard(); diff --git a/test/cypress/integration/entry/commands.js b/test/cypress/integration/entry/commands.js new file mode 100644 index 000000000..7c96a5440 --- /dev/null +++ b/test/cypress/integration/entry/commands.js @@ -0,0 +1,21 @@ +Cypress.Commands.add('selectTravel', (warehouse = '1') => { + cy.get('i[data-cy="Travel_icon"]').click(); + cy.get('input[data-cy="Warehouse Out_select"]').type(warehouse); + cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click(); + cy.get('button[data-cy="save-filter-travel-form"]').click(); + cy.get('tr').eq(1).click(); +}); + +Cypress.Commands.add('deleteEntry', () => { + cy.get('[data-cy="descriptor-more-opts"]').should('be.visible').click(); + cy.waitForElement('div[data-cy="delete-entry"]').click(); + cy.url().should('include', 'list'); +}); + +Cypress.Commands.add('createEntry', () => { + cy.get('button[data-cy="vnTableCreateBtn"]').click(); + cy.selectTravel('one'); + cy.get('button[data-cy="FormModelPopup_save"]').click(); + cy.url().should('include', 'summary'); + cy.get('.q-notification__message').eq(0).should('have.text', 'Data created'); +}); diff --git a/test/cypress/integration/entry/entryCard/entryBasicData.spec.js b/test/cypress/integration/entry/entryCard/entryBasicData.spec.js new file mode 100644 index 000000000..ba689b8c7 --- /dev/null +++ b/test/cypress/integration/entry/entryCard/entryBasicData.spec.js @@ -0,0 +1,19 @@ +import '../commands.js'; + +describe('EntryBasicData', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/list`); + }); + + it('Change Travel', () => { + cy.createEntry(); + cy.waitForElement('[data-cy="entry-buys"]'); + cy.get('a[data-cy="EntryBasicData-menu-item"]').click(); + cy.selectTravel('two'); + cy.saveCard(); + cy.get('.q-notification__message').eq(0).should('have.text', 'Data created'); + cy.deleteEntry(); + }); +}); diff --git a/test/cypress/integration/entry/entryCard/entryBuys.spec.js b/test/cypress/integration/entry/entryCard/entryBuys.spec.js new file mode 100644 index 000000000..f8f5e6b80 --- /dev/null +++ b/test/cypress/integration/entry/entryCard/entryBuys.spec.js @@ -0,0 +1,96 @@ +import '../commands.js'; +describe('EntryBuys', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/list`); + }); + + it('Edit buys and use toolbar actions', () => { + const COLORS = { + negative: 'rgb(251, 82, 82)', + positive: 'rgb(200, 228, 132)', + enabled: 'rgb(255, 255, 255)', + disable: 'rgb(168, 168, 168)', + }; + + const selectCell = (field, row = 0) => + cy.get(`td[data-col-field="${field}"][data-row-index="${row}"]`); + const selectSpan = (field, row = 0) => selectCell(field, row).find('div > span'); + const selectButton = (cySelector) => cy.get(`button[data-cy="${cySelector}"]`); + const clickAndType = (field, value, row = 0) => { + selectCell(field, row).click().type(`${value}{esc}`); + }; + const checkText = (field, expectedText, row = 0) => + selectCell(field, row).should('have.text', expectedText); + const checkColor = (field, expectedColor, row = 0) => + selectSpan(field, row).should('have.css', 'color', expectedColor); + + cy.createEntry(); + createBuy(); + + selectCell('isIgnored').click().click().type('{esc}'); + checkText('isIgnored', 'close'); + + clickAndType('stickers', '1'); + checkText('stickers', '0/01'); + checkText('quantity', '1'); + checkText('amount', '50.00'); + clickAndType('packing', '2'); + checkText('packing', '12'); + checkText('weight', '12.0'); + checkText('quantity', '12'); + checkText('amount', '600.00'); + checkColor('packing', COLORS.enabled); + + selectCell('groupingMode').click().click().click(); + checkColor('packing', COLORS.disable); + checkColor('grouping', COLORS.enabled); + + selectCell('buyingValue').click().clear().type('{backspace}{backspace}1'); + checkText('amount', '12.00'); + checkColor('minPrice', COLORS.disable); + + selectCell('hasMinPrice').click().click(); + checkColor('minPrice', COLORS.enabled); + selectCell('hasMinPrice').click(); + + cy.saveCard(); + cy.get('span[data-cy="footer-stickers"]').should('have.text', '1'); + cy.get('.q-notification__message').contains('Data saved'); + + selectButton('change-quantity-sign').should('be.disabled'); + selectButton('check-buy-amount').should('be.disabled'); + cy.get('tr.cursor-pointer > .q-table--col-auto-width > .q-checkbox').click(); + selectButton('change-quantity-sign').should('be.enabled'); + selectButton('check-buy-amount').should('be.enabled'); + + selectButton('change-quantity-sign').click(); + selectButton('set-negative-quantity').click(); + checkText('quantity', '-12'); + selectButton('set-positive-quantity').click(); + checkText('quantity', '12'); + checkColor('amount', COLORS.disable); + + selectButton('check-buy-amount').click(); + selectButton('uncheck-amount').click(); + checkColor('amount', COLORS.disable); + + selectButton('check-amount').click(); + checkColor('amount', COLORS.positive); + cy.saveCard(); + + cy.deleteEntry(); + }); + + function createBuy() { + cy.waitForElement('[data-cy="entry-buys"]'); + cy.get('a[data-cy="EntryBuys-menu-item"]').click(); + cy.get('button[data-cy="vnTableCreateBtn"]').click(); + + cy.get('input[data-cy="itemFk-create-popup"]').type('1'); + cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click(); + cy.get('input[data-cy="Grouping mode_select"]').should('have.value', 'packing'); + cy.get('button[data-cy="FormModelPopup_save"]').click(); + } +}); diff --git a/test/cypress/integration/entry/entryCard/entryDescriptor.spec.js b/test/cypress/integration/entry/entryCard/entryDescriptor.spec.js new file mode 100644 index 000000000..554471008 --- /dev/null +++ b/test/cypress/integration/entry/entryCard/entryDescriptor.spec.js @@ -0,0 +1,44 @@ +import '../commands.js'; +describe('EntryDescriptor', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/list`); + }); + + it('Clone entry and recalculate rates', () => { + cy.createEntry(); + + cy.waitForElement('[data-cy="entry-buys"]'); + + cy.url().then((previousUrl) => { + cy.get('[data-cy="descriptor-more-opts"]').click(); + cy.get('div[data-cy="clone-entry"]').should('be.visible').click(); + + cy.get('.q-notification__message').eq(1).should('have.text', 'Entry cloned'); + + cy.url() + .should('not.eq', previousUrl) + .then(() => { + cy.waitForElement('[data-cy="entry-buys"]'); + + cy.get('[data-cy="descriptor-more-opts"]').click(); + cy.get('div[data-cy="recalculate-rates"]').click(); + + cy.get('.q-notification__message') + .eq(2) + .should('have.text', 'Entry prices recalculated'); + + cy.get('[data-cy="descriptor-more-opts"]').click(); + cy.deleteEntry(); + + cy.log(previousUrl); + + cy.visit(previousUrl); + + cy.waitForElement('[data-cy="entry-buys"]'); + cy.deleteEntry(); + }); + }); + }); +}); diff --git a/test/cypress/integration/entry/entryCard/entryDms.spec.js b/test/cypress/integration/entry/entryCard/entryDms.spec.js new file mode 100644 index 000000000..f3f0ef20b --- /dev/null +++ b/test/cypress/integration/entry/entryCard/entryDms.spec.js @@ -0,0 +1,22 @@ +import '../commands.js'; +describe('EntryDms', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/list`); + }); + + it('should create edit and remove new dms', () => { + cy.createEntry(); + cy.waitForElement('[data-cy="entry-buys"]'); + cy.dataCy('EntryDms-menu-item').click(); + cy.dataCy('addButton').click(); + cy.dataCy('attachFile').click(); + cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', { + force: true, + }); + cy.dataCy('FormModelPopup_save').click(); + cy.get('.q-notification__message').eq(0).should('have.text', 'Data created'); + cy.deleteEntry(); + }); +}); diff --git a/test/cypress/integration/entry/entryCard/entryLock.spec.js b/test/cypress/integration/entry/entryCard/entryLock.spec.js new file mode 100644 index 000000000..6ba4392ae --- /dev/null +++ b/test/cypress/integration/entry/entryCard/entryLock.spec.js @@ -0,0 +1,44 @@ +import '../commands.js'; +describe('EntryLock', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/list`); + }); + + it('Should notify when entry is lock by another user', () => { + const checkLockMessage = () => { + cy.get('[role="dialog"]').should('be.visible'); + cy.get('[data-cy="VnConfirm_message"] > span').should( + 'contain.text', + 'This entry has been locked by buyerNick', + ); + }; + + cy.createEntry(); + goToEntryBuys(); + cy.get('.q-notification__message') + .eq(1) + .should('have.text', 'The entry has been locked successfully'); + + cy.login('logistic'); + cy.reload(); + checkLockMessage(); + cy.get('[data-cy="VnConfirm_cancel"]').click(); + cy.url().should('include', 'summary'); + + goToEntryBuys(); + checkLockMessage(); + cy.get('[data-cy="VnConfirm_confirm"]').click(); + cy.url().should('include', 'buys'); + + cy.deleteEntry(); + + function goToEntryBuys() { + const entryBuySelector = 'a[data-cy="EntryBuys-menu-item"]'; + cy.get(entryBuySelector).should('be.visible'); + cy.waitForElement('[data-cy="entry-buys"]'); + cy.get(entryBuySelector).click(); + } + }); +}); diff --git a/test/cypress/integration/entry/entryCard/entryNotes.spec.js b/test/cypress/integration/entry/entryCard/entryNotes.spec.js new file mode 100644 index 000000000..544ac23b0 --- /dev/null +++ b/test/cypress/integration/entry/entryCard/entryNotes.spec.js @@ -0,0 +1,50 @@ +import '../commands.js'; + +describe('EntryNotes', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/list`); + }); + + const createObservation = (type, description) => { + cy.dataCy('vnTableCreateBtn').click(); + cy.dataCy('Observation type_select').eq(1).should('be.visible').type(type); + cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click(); + cy.dataCy('Description_input').should('be.visible').type(description); + cy.dataCy('FormModelPopup_save').should('be.enabled').click(); + }; + + const editObservation = (rowIndex, type, description) => { + cy.get(`td[data-col-field="description"][data-row-index="${rowIndex}"]`) + .click() + .clear() + .type(description); + cy.get(`td[data-col-field="observationTypeFk"][data-row-index="${rowIndex}"]`) + .click() + .clear() + .type(type); + cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click(); + cy.saveCard(); + }; + + it('Create, delete, and edit observations', () => { + cy.createEntry(); + cy.waitForElement('[data-cy="entry-buys"]'); + + cy.dataCy('EntryNotes-menu-item').click(); + + createObservation('Packager', 'test'); + cy.get('.q-notification__message').eq(0).should('have.text', 'Data created'); + + editObservation(0, 'Administrative', 'test2'); + + createObservation('Administrative', 'test'); + cy.get('.q-notification__message') + .eq(2) + .should('have.text', "The observation type can't be repeated"); + cy.dataCy('FormModelPopup_cancel').click(); + + cy.deleteEntry(); + }); +}); diff --git a/test/cypress/integration/entry/entryDms.spec.js b/test/cypress/integration/entry/entryDms.spec.js deleted file mode 100644 index 06f057258..000000000 --- a/test/cypress/integration/entry/entryDms.spec.js +++ /dev/null @@ -1,44 +0,0 @@ -describe.skip('EntryDms', () => { - const entryId = 1; - - beforeEach(() => { - cy.viewport(1920, 1080); - cy.login('developer'); - cy.visit(`/#/entry/${entryId}/dms`); - }); - - it('should create edit and remove new dms', () => { - cy.addRow(); - cy.get('.icon-attach').click(); - cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', { - force: true, - }); - - cy.get('tbody > tr').then((value) => { - const u = undefined; - - //Create and check if exist new row - let newFileTd = Cypress.$(value).length; - cy.get('.q-btn--standard > .q-btn__content > .block').click(); - expect(value).to.have.length(newFileTd++); - const newRowSelector = `tbody > :nth-child(${newFileTd})`; - cy.waitForElement(newRowSelector); - cy.validateRow(newRowSelector, [u, u, u, u, u, 'ENTRADA ID 1']); - - //Edit new dms - const newDescription = 'entry id 1 modified'; - const textAreaSelector = - '.q-textarea > .q-field__inner > .q-field__control > .q-field__control-container'; - cy.get( - `tbody :nth-child(${newFileTd}) > .text-right > .no-wrap > :nth-child(2) > .q-btn > .q-btn__content > .q-icon`, - ).click(); - - cy.get(textAreaSelector).clear(); - cy.get(textAreaSelector).type(newDescription); - cy.saveCard(); - cy.reload(); - - cy.validateRow(newRowSelector, [u, u, u, u, u, newDescription]); - }); - }); -}); diff --git a/test/cypress/integration/entry/entryList.spec.js b/test/cypress/integration/entry/entryList.spec.js index bdaa66f79..990f74261 100644 --- a/test/cypress/integration/entry/entryList.spec.js +++ b/test/cypress/integration/entry/entryList.spec.js @@ -1,223 +1,54 @@ -describe.skip('Entry', () => { +import './commands'; + +describe('EntryList', () => { beforeEach(() => { cy.viewport(1920, 1080); cy.login('buyer'); cy.visit(`/#/entry/list`); }); - it('Filter deleted entries and other fields', () => { - createEntry(); + it('View popup summary', () => { + cy.createEntry(); cy.get('.q-notification__message').eq(0).should('have.text', 'Data created'); cy.waitForElement('[data-cy="entry-buys"]'); - deleteEntry(); + cy.deleteEntry(); cy.typeSearchbar('{enter}'); - cy.get('span[title="Date"]').click().click(); - cy.typeSearchbar('{enter}'); - cy.url().should('include', 'order'); - cy.get('td[data-row-index="0"][data-col-field="landed"]').should( - 'have.text', - '-', - ); + cy.get('button[title="Summary"]').eq(1).should('be.visible').click(); + cy.dataCy('entry-summary').should('be.visible'); }); - it('Create entry, modify travel and add buys', () => { - createEntryAndBuy(); - cy.get('a[data-cy="EntryBasicData-menu-item"]').click(); - selectTravel('two'); - cy.saveCard(); - cy.get('.q-notification__message').eq(0).should('have.text', 'Data created'); - deleteEntry(); + it('Show supplierDescriptor on click on supplierDescriptor', () => { + cy.typeSearchbar('{enter}'); + cy.get('td[data-col-field="supplierFk"] > div > span').eq(0).click(); + cy.get('div[role="menu"] > div[class="descriptor"]').should('be.visible'); }); - it('Clone entry and recalculate rates', () => { - createEntry(); + it('Landed badge should display the right color', () => { + cy.typeSearchbar('{enter}'); - cy.waitForElement('[data-cy="entry-buys"]'); - - cy.url().then((previousUrl) => { - cy.get('[data-cy="descriptor-more-opts"]').click(); - cy.get('div[data-cy="clone-entry"]').should('be.visible').click(); - - cy.get('.q-notification__message').eq(1).should('have.text', 'Entry cloned'); - - cy.url() - .should('not.eq', previousUrl) - .then(() => { - cy.waitForElement('[data-cy="entry-buys"]'); - - cy.get('[data-cy="descriptor-more-opts"]').click(); - cy.get('div[data-cy="recalculate-rates"]').click(); - - cy.get('.q-notification__message') - .eq(2) - .should('have.text', 'Entry prices recalculated'); - - cy.get('[data-cy="descriptor-more-opts"]').click(); - deleteEntry(); - - cy.log(previousUrl); - - cy.visit(previousUrl); - - cy.waitForElement('[data-cy="entry-buys"]'); - deleteEntry(); + const checkBadgeDate = (selector, comparisonFn) => { + cy.get(selector) + .should('exist') + .each(($badge) => { + const badgeText = $badge.text().trim(); + const badgeDate = new Date(badgeText); + const compareDate = new Date('01/01/2001'); + comparisonFn(badgeDate, compareDate); }); - }); - }); - - it('Should notify when entry is lock by another user', () => { - const checkLockMessage = () => { - cy.get('[role="dialog"]').should('be.visible'); - cy.get('[data-cy="VnConfirm_message"] > span').should( - 'contain.text', - 'This entry has been locked by buyerNick', - ); }; - createEntry(); - goToEntryBuys(); - cy.get('.q-notification__message') - .eq(1) - .should('have.text', 'The entry has been locked successfully'); - - cy.login('logistic'); - cy.reload(); - checkLockMessage(); - cy.get('[data-cy="VnConfirm_cancel"]').click(); - cy.url().should('include', 'summary'); - - goToEntryBuys(); - checkLockMessage(); - cy.get('[data-cy="VnConfirm_confirm"]').click(); - cy.url().should('include', 'buys'); - - deleteEntry(); - }); - - it('Edit buys and use toolbar actions', () => { - const COLORS = { - negative: 'rgb(251, 82, 82)', - positive: 'rgb(200, 228, 132)', - enabled: 'rgb(255, 255, 255)', - disable: 'rgb(168, 168, 168)', - }; - - const selectCell = (field, row = 0) => - cy.get(`td[data-col-field="${field}"][data-row-index="${row}"]`); - const selectSpan = (field, row = 0) => selectCell(field, row).find('div > span'); - const selectButton = (cySelector) => cy.get(`button[data-cy="${cySelector}"]`); - const clickAndType = (field, value, row = 0) => { - selectCell(field, row).click().type(`${value}{esc}`); - }; - const checkText = (field, expectedText, row = 0) => - selectCell(field, row).should('have.text', expectedText); - const checkColor = (field, expectedColor, row = 0) => - selectSpan(field, row).should('have.css', 'color', expectedColor); - - createEntryAndBuy(); - - selectCell('isIgnored').click().click().type('{esc}'); - checkText('isIgnored', 'close'); - - clickAndType('stickers', '1'); - checkText('stickers', '0/01'); - checkText('quantity', '1'); - checkText('amount', '50.00'); - clickAndType('packing', '2'); - checkText('packing', '12'); - checkText('weight', '12.0'); - checkText('quantity', '12'); - checkText('amount', '600.00'); - checkColor('packing', COLORS.enabled); - - selectCell('groupingMode').click().click().click(); - checkColor('packing', COLORS.disable); - checkColor('grouping', COLORS.enabled); - - selectCell('buyingValue').click().clear().type('{backspace}{backspace}1'); - checkText('amount', '12.00'); - checkColor('minPrice', COLORS.disable); - - selectCell('hasMinPrice').click().click(); - checkColor('minPrice', COLORS.enabled); - selectCell('hasMinPrice').click(); - - cy.saveCard(); - cy.get('span[data-cy="footer-stickers"]').should('have.text', '1'); - cy.get('.q-notification__message').contains('Data saved'); - - selectButton('change-quantity-sign').should('be.disabled'); - selectButton('check-buy-amount').should('be.disabled'); - cy.get('tr.cursor-pointer > .q-table--col-auto-width > .q-checkbox').click(); - selectButton('change-quantity-sign').should('be.enabled'); - selectButton('check-buy-amount').should('be.enabled'); - - selectButton('change-quantity-sign').click(); - selectButton('set-negative-quantity').click(); - checkText('quantity', '-12'); - selectButton('set-positive-quantity').click(); - checkText('quantity', '12'); - checkColor('amount', COLORS.disable); - - selectButton('check-buy-amount').click(); - selectButton('uncheck-amount').click(); - checkColor('amount', COLORS.disable); - - selectButton('check-amount').click(); - checkColor('amount', COLORS.positive); - cy.saveCard(); - - cy.get('span[data-cy="footer-amount"]').should( - 'have.css', - 'color', - COLORS.positive, + checkBadgeDate( + 'td[data-col-field="landed"] > div .bg-warning', + (badgeDate, compareDate) => { + expect(badgeDate.getTime()).to.be.greaterThan(compareDate.getTime()); + }, ); - deleteEntry(); + checkBadgeDate( + 'td[data-col-field="landed"] > div .bg-info', + (badgeDate, compareDate) => { + expect(badgeDate.getTime()).to.be.lessThan(compareDate.getTime()); + }, + ); }); - - function goToEntryBuys() { - const entryBuySelector = 'a[data-cy="EntryBuys-menu-item"]'; - cy.get(entryBuySelector).should('be.visible'); - cy.waitForElement('[data-cy="entry-buys"]'); - cy.get(entryBuySelector).click(); - } - - function deleteEntry() { - cy.get('[data-cy="descriptor-more-opts"]').should('be.visible').click(); - cy.waitForElement('div[data-cy="delete-entry"]').click(); - cy.url().should('include', 'list'); - } - - function createEntryAndBuy() { - createEntry(); - createBuy(); - } - - function createEntry() { - cy.get('button[data-cy="vnTableCreateBtn"]').click(); - selectTravel('one'); - cy.get('button[data-cy="FormModelPopup_save"]').click(); - cy.url().should('include', 'summary'); - cy.get('.q-notification__message').eq(0).should('have.text', 'Data created'); - } - - function selectTravel(warehouse) { - cy.get('i[data-cy="Travel_icon"]').click(); - cy.get('input[data-cy="Warehouse Out_select"]').type(warehouse); - cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click(); - cy.get('button[data-cy="save-filter-travel-form"]').click(); - cy.get('tr').eq(1).click(); - } - - function createBuy() { - cy.get('a[data-cy="EntryBuys-menu-item"]').click(); - cy.get('a[data-cy="EntryBuys-menu-item"]').click(); - cy.get('button[data-cy="vnTableCreateBtn"]').click(); - - cy.get('input[data-cy="itemFk-create-popup"]').type('1'); - cy.get('div[role="listbox"] > div > div[role="option"]').eq(0).click(); - cy.get('input[data-cy="Grouping mode_select"]').should('have.value', 'packing'); - cy.get('button[data-cy="FormModelPopup_save"]').click(); - } }); diff --git a/test/cypress/integration/entry/entryStockBought.spec.js b/test/cypress/integration/entry/entryStockBought.spec.js new file mode 100644 index 000000000..3fad44d91 --- /dev/null +++ b/test/cypress/integration/entry/entryStockBought.spec.js @@ -0,0 +1,23 @@ +describe('EntryStockBought', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyer'); + cy.visit(`/#/entry/stock-Bought`); + }); + + it('Should edit the reserved space adjust the purchased spaces and check detail', () => { + cy.get('[data-cy="edit-travel"]').should('be.visible').click(); + cy.get('input[aria-label="m3"]').clear().type('60'); + cy.get('[data-cy="FormModelPopup_save"]').click(); + cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60'); + + cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001'); + cy.get('[data-col-field="reserve"][data-row-index="0"]').click(); + cy.get('input[name="reserve"]').type('10{enter}'); + cy.get('button[title="Save"]').click(); + cy.checkNotification('Data saved'); + + cy.get('[data-cy="searchBtn"]').eq(0).click(); + cy.get('tBody > tr').eq(1).its('length').should('eq', 1); + }); +}); diff --git a/test/cypress/integration/entry/myEntry.spec.js b/test/cypress/integration/entry/entrySupplier.spec.js similarity index 71% rename from test/cypress/integration/entry/myEntry.spec.js rename to test/cypress/integration/entry/entrySupplier.spec.js index ed469d9e2..83deecea5 100644 --- a/test/cypress/integration/entry/myEntry.spec.js +++ b/test/cypress/integration/entry/entrySupplier.spec.js @@ -1,4 +1,4 @@ -describe('EntryMy when is supplier', () => { +describe('EntrySupplier when is supplier', () => { beforeEach(() => { cy.viewport(1920, 1080); cy.login('supplier'); @@ -13,5 +13,7 @@ describe('EntryMy when is supplier', () => { cy.dataCy('cardBtn').eq(2).click(); cy.dataCy('printLabelsBtn').click(); cy.window().its('open').should('be.called'); + cy.dataCy('seeLabelBtn').eq(0).should('be.visible').click(); + cy.window().its('open').should('be.called'); }); }); diff --git a/test/cypress/integration/entry/entryWasteRecalc.spec.js b/test/cypress/integration/entry/entryWasteRecalc.spec.js new file mode 100644 index 000000000..1b358676c --- /dev/null +++ b/test/cypress/integration/entry/entryWasteRecalc.spec.js @@ -0,0 +1,22 @@ +import './commands'; +describe('EntryDms', () => { + beforeEach(() => { + cy.viewport(1920, 1080); + cy.login('buyerBoss'); + cy.visit(`/#/entry/waste-recalc`); + }); + + it('should recalc waste for today', () => { + cy.waitForElement('[data-cy="wasteRecalc"]'); + cy.dataCy('recalc').should('be.disabled'); + + cy.dataCy('dateFrom').should('be.visible').click().type('01-01-2001'); + cy.dataCy('dateTo').should('be.visible').click().type('01-01-2001'); + + cy.dataCy('recalc').should('be.enabled').click(); + cy.get('.q-notification__message').should( + 'have.text', + 'The wastes were successfully recalculated', + ); + }); +}); diff --git a/test/cypress/integration/entry/stockBought.spec.js b/test/cypress/integration/entry/stockBought.spec.js deleted file mode 100644 index 2a8431cf0..000000000 --- a/test/cypress/integration/entry/stockBought.spec.js +++ /dev/null @@ -1,50 +0,0 @@ -describe.skip('EntryStockBought', () => { - beforeEach(() => { - cy.viewport(1920, 1080); - cy.login('buyer'); - 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('[data-col-field="reserve"][data-row-index="0"]').click(); - cy.get('input[name="reserve"]').type('10{enter}'); - cy.get('button[title="Save"]').click(); - cy.checkNotification('Data saved'); - }); - it('Should add a new reserved space for buyerBoss', () => { - cy.addBtnClick(); - 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('itNick'); - cy.get('div[role="listbox"] > div > div[role="option"]') - .eq(1) - .should('be.visible') - .click(); - - cy.get('[data-cy="FormModelPopup_save"]').click(); - cy.get('.q-notification__message').should('have.text', 'Data created'); - - cy.get('[data-col-field="reserve"][data-row-index="1"]').click().clear(); - cy.get('[data-cy="searchBtn"]').eq(1).click(); - cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata') - .should('have.text', 'warningNo data available') - .type('{esc}'); - cy.get('[data-col-field="reserve"][data-row-index="1"]') - .click() - .type('{backspace}{enter}'); - cy.get('[data-cy="crudModelDefaultSaveBtn"]').should('be.enabled').click(); - cy.get('.q-notification__message').eq(1).should('have.text', 'Data saved'); - }); - it('Should check detail for the buyer', () => { - cy.get('[data-cy="searchBtn"]').eq(0).click(); - cy.get('tBody > tr').eq(1).its('length').should('eq', 1); - }); - - it('Should edit travel m3 and refresh', () => { - cy.get('[data-cy="edit-travel"]').should('be.visible').click(); - cy.get('input[aria-label="m3"]').clear().type('60'); - cy.get('[data-cy="FormModelPopup_save"]').click(); - cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60'); - }); -}); diff --git a/test/cypress/integration/order/orderList.spec.js b/test/cypress/integration/order/orderList.spec.js index c48b317a8..34cd2bffc 100644 --- a/test/cypress/integration/order/orderList.spec.js +++ b/test/cypress/integration/order/orderList.spec.js @@ -30,7 +30,7 @@ describe('OrderList', () => { cy.url().should('include', `/order`); }); - it('filter list and create order', () => { + it.skip('filter list and create order', () => { cy.dataCy('Customer ID_input').type('1101{enter}'); cy.dataCy('vnTableCreateBtn').click(); cy.dataCy('landedDate').find('input').type('06/01/2001'); diff --git a/test/cypress/integration/outLogin/logout.spec.js b/test/cypress/integration/outLogin/logout.spec.js index b17e42794..9f022617d 100644 --- a/test/cypress/integration/outLogin/logout.spec.js +++ b/test/cypress/integration/outLogin/logout.spec.js @@ -1,5 +1,5 @@ /// <reference types="cypress" /> -describe('Logout', () => { +describe.skip('Logout', () => { beforeEach(() => { cy.login('developer'); cy.visit(`/#/dashboard`); diff --git a/test/cypress/integration/ticket/ticketList.spec.js b/test/cypress/integration/ticket/ticketList.spec.js index 2409dd149..a3d8fe908 100644 --- a/test/cypress/integration/ticket/ticketList.spec.js +++ b/test/cypress/integration/ticket/ticketList.spec.js @@ -35,7 +35,7 @@ describe('TicketList', () => { cy.get('.summaryBody').should('exist'); }); - it('filter client and create ticket', () => { + it.skip('filter client and create ticket', () => { cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar'); searchResults(); cy.wait('@ticketSearchbar'); diff --git a/test/cypress/integration/zone/zoneWarehouse.spec.js b/test/cypress/integration/zone/zoneWarehouse.spec.js index bca5ced22..d7a9854bb 100644 --- a/test/cypress/integration/zone/zoneWarehouse.spec.js +++ b/test/cypress/integration/zone/zoneWarehouse.spec.js @@ -18,7 +18,7 @@ describe('ZoneWarehouse', () => { cy.checkNotification(dataError); }); - it('should create & remove a warehouse', () => { + it.skip('should create & remove a warehouse', () => { cy.addBtnClick(); cy.fillInForm(data); cy.get(saveBtn).click(); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index 1ca2b2392..45e17654e 100755 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -395,6 +395,7 @@ Cypress.Commands.add('clickButtonWith', (type, value) => { break; } }); + Cypress.Commands.add('clickButtonWithIcon', (iconClass) => { cy.waitForElement('[data-cy="descriptor_actions"]'); cy.get('[data-cy="loading-spinner"]', { timeout: 10000 }).should('not.be.visible');