Item requests #297

Merged
jsegarra merged 24 commits from :feature/ItemRequests into dev 2024-04-26 06:22:11 +00:00
2 changed files with 484 additions and 108 deletions
Showing only changes of commit fcce2b5070 - Show all commits

View File

@ -1,24 +1,28 @@
<script setup>
import { onMounted, ref, computed } from 'vue';
import { ref, computed, onMounted, onBeforeMount } from 'vue';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnInput from 'src/components/common/VnInput.vue';
import ItemRequestDenyForm from './ItemRequestDenyForm.vue';
import ItemRequestFilter from './ItemRequestFilter.vue';
import VnPaginate from 'components/ui/VnPaginate.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useStateStore } from 'stores/useStateStore';
import { toDateFormat } from 'src/filters/date';
import { toCurrency } from 'filters/index';
import useNotify from 'src/composables/useNotify.js';
import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js';
import axios from 'axios';
const { t } = useI18n();
const { notify } = useNotify();
const stateStore = useStateStore();
let filterParams = ref({});
const denyFormRef = ref(null);
const denyRequestId = ref(null);
const denyRequestIndex = ref(null);
@ -169,118 +173,182 @@ const onDenyAccept = (_, responseData) => {
denyRequestIndex.value = null;
};
onMounted(async () => {});
onMounted(async () => {
stateStore.rightDrawer = true;
});
onBeforeMount(() => {
const today = Date.vnNew();
today.setHours(0, 0, 0, 0);
const nextWeek = Date.vnNew();
nextWeek.setHours(23, 59, 59, 59);
nextWeek.setDate(nextWeek.getDate() + 7);
filterParams.value = {
from: today,
to: nextWeek,
state: 'pending',
};
});
</script>
<template>
<FetchData
url="TicketRequests/filter"
:filter="{ order: ['shippedDate ASC', 'isOk ASC'] }"
auto-load
@on-fetch="(data) => (itemRequestsOptions = data)"
/>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#searchbar">
<VnSearchbar
data-key="ItemRequests"
url="TicketRequests/filter"
:label="t('globals.search')"
:info="t('You can search by Id or alias')"
:redirect="false"
/>
</Teleport>
</template>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
flat
@click="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</Teleport>
</template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
<QScrollArea class="fit text-grey-8">
<ItemRequestFilter data-key="ItemRequests" />
</QScrollArea>
</QDrawer>
<QPage class="column items-center q-pa-md">
<QTable
:rows="itemRequestsOptions"
:columns="columns"
row-key="id"
:pagination="{ rowsPerPage: 0 }"
class="full-width q-mt-md"
:no-data-label="t('globals.noResults')"
<VnPaginate
ref="paginateRef"
data-key="ItemRequests"
url="TicketRequests/filter"
:order="['shippedDate ASC', 'isOk ASC']"
:user-params="filterParams"
:limit="12"
:offset="50"
auto-load
>
<template #body-cell-id="{ row }">
<QTd>
<QBtn flat color="primary"> {{ row.id }}</QBtn>
<TicketDescriptorProxy :id="row.id" />
</QTd>
</template>
<template #body="{ rows }">
<QTable
:rows="rows"
:columns="columns"
row-key="id"
:pagination="{ rowsPerPage: 0 }"
class="full-width q-mt-md"
:no-data-label="t('globals.noResults')"
>
<template #body-cell-id="{ row }">
<QTd>
<QBtn flat color="primary"> {{ row.ticketFk }}</QBtn>
<TicketDescriptorProxy :id="row.ticketFk" />
</QTd>
</template>
<template #body-cell-shipped="{ row }">
<QTd>
<QBadge
v-if="getDateQBadgeColor(row.shipped)"
:color="getDateQBadgeColor(row.shipped)"
text-color="black"
class="q-ma-none"
dense
style="font-size: 14px"
>
{{ toDateFormat(row.shipped) }}
</QBadge>
<span v-else>{{ toDateFormat(row.shipped) }}</span>
</QTd>
<template #body-cell-shipped="{ row }">
<QTd>
<QBadge
v-if="getDateQBadgeColor(row.shipped)"
:color="getDateQBadgeColor(row.shipped)"
text-color="black"
class="q-ma-none"
dense
style="font-size: 14px"
>
{{ toDateFormat(row.shipped) }}
</QBadge>
<span v-else>{{ toDateFormat(row.shipped) }}</span>
</QTd>
</template>
<template #body-cell-requester="{ row }">
<QTd>
<QBtn flat dense color="primary">
{{ row.requesterName }}</QBtn
>
<WorkerDescriptorProxy :id="row.requesterFk" />
</QTd>
</template>
<template #body-cell-attender="{ row }">
<QTd>
<QBtn flat dense color="primary">
{{ row.attenderName }}</QBtn
>
<WorkerDescriptorProxy :id="row.attenderFk" />
</QTd>
</template>
<template #body-cell-item="{ row }">
<QTd>
<VnInput
class="dense"
v-model.number="row.itemFk"
type="number"
:disable="row.isOk != null"
/>
</QTd>
</template>
<template #body-cell-achieved="{ row }">
<QTd>
<VnInput
class="dense"
v-model.number="row.saleQuantity"
@change="changeQuantity(row)"
type="number"
:disable="!row.itemFk || row.isOk != null"
/>
jsegarra marked this conversation as resolved
Review

A mi tampoco me lo abre.
Y es correcto porque es body-cell-description, y no concept

He conseguido que me aparezca el concepto como si fuese un descriptor y no me lo abre.

A mi tampoco me lo abre. Y es correcto porque es body-cell-description, y no concept He conseguido que me aparezca el concepto como si fuese un descriptor y no me lo abre.
</QTd>
</template>
<template #body-cell-concept="{ row }">
jsegarra marked this conversation as resolved
Review

No me lo abre

No me lo abre
Review

Mmm.. que raro, yo si puedo abrirlo

Mmm.. que raro, yo si puedo abrirlo
Review

No me lo abre

@alexm en salix no se abre. Resulta que itemFk es null

> No me lo abre @alexm en salix no se abre. Resulta que itemFk es null
Review

En lilium está bien hecho, el fallo se corrige desde Salix en la verdnatura/salix#2355

En lilium está bien hecho, el fallo se corrige desde Salix en la https://gitea.verdnatura.es/verdnatura/salix/pulls/2355
<QTd>
<QBtn flat dense color="primary">
{{ row.itemDescription }}</QBtn
>
<ItemDescriptorProxy :id="row.itemFk" />
</QTd>
</template>
<template #body-cell-state="{ row }">
<QTd>
<span>{{ getState(row.isOk) }}</span>
</QTd>
</template>
<template #body-cell-action="{ row, rowIndex }">
<QTd>
<QIcon
v-if="row.response?.length"
name="insert_drive_file"
color="primary"
size="sm"
>
<QTooltip>
{{ row.response }}
</QTooltip>
</QIcon>
<QIcon
jsegarra marked this conversation as resolved Outdated

falta la clase fill para la mano y para el icono de archivo

falta la clase fill para la mano y para el icono de archivo

Fill agregado al icon de la mano.
El icon de archivo no cambia con hover state en salix y lo veo bien ya que no tiene ninguna accion mas que mostrar un tooltip.

Commit: 4396f7d6ba

Fill agregado al icon de la mano. El icon de archivo no cambia con hover state en salix y lo veo bien ya que no tiene ninguna accion mas que mostrar un tooltip. Commit: https://gitea.verdnatura.es/verdnatura/salix-front/commit/4396f7d6ba7ff40d3f819daab34f5cf017c40458

sorry :(, aparece FILL por defecto, sin hacer hover

sorry :(, aparece FILL por defecto, sin hacer hover
v-if="row.isOk == null"
name="thumb_down"
color="primary"
size="sm"
class="cursor-pointer"
@click="showDenyRequestForm(row.id, rowIndex)"
>
<QTooltip>
{{ t('Discard') }}
</QTooltip>
</QIcon>
</QTd>
</template>
</QTable>
</template>
<template #body-cell-requester="{ row }">
<QTd>
<QBtn flat dense color="primary"> {{ row.requesterName }}</QBtn>
<WorkerDescriptorProxy :id="row.requesterFk" />
</QTd>
</template>
<template #body-cell-attender="{ row }">
<QTd>
<QBtn flat dense color="primary"> {{ row.attenderName }}</QBtn>
<WorkerDescriptorProxy :id="row.attenderFk" />
</QTd>
</template>
<template #body-cell-item="{ row }">
<QTd>
<VnInput
class="dense"
v-model.number="row.itemFk"
type="number"
:disable="row.isOk != null"
/>
</QTd>
</template>
<template #body-cell-achieved="{ row }">
<QTd>
<VnInput
class="dense"
v-model.number="row.saleQuantity"
@change="changeQuantity(row)"
type="number"
:disable="!row.itemFk || row.isOk != null"
/>
</QTd>
</template>
<template #body-cell-concept="{ row }">
<QTd>
<QBtn flat dense color="primary"> {{ row.itemDescription }}</QBtn>
<ItemDescriptorProxy :id="row.itemFk" />
</QTd>
</template>
<template #body-cell-state="{ row }">
<QTd>
<span>{{ getState(row.isOk) }}</span>
</QTd>
</template>
<template #body-cell-action="{ row, rowIndex }">
<QTd>
<QIcon
v-if="row.response?.length"
name="insert_drive_file"
color="primary"
size="sm"
>
<QTooltip>
{{ row.response }}
</QTooltip>
</QIcon>
<QIcon
v-if="row.isOk == null"
name="thumb_down"
color="primary"
size="sm"
class="cursor-pointer"
@click="showDenyRequestForm(row.id, rowIndex)"
>
<QTooltip>
{{ t('Discard') }}
</QTooltip>
</QIcon>
</QTd>
</template>
</QTable>
</VnPaginate>
<QDialog ref="denyFormRef" transition-show="scale" transition-hide="scale">
<ItemRequestDenyForm
:request-id="denyRequestId"
@ -293,4 +361,5 @@ onMounted(async () => {});
<i18n>
es:
Discard: Descartar
You can search by Id or alias: Buscar peticiones por identificador o alias
</i18n>

View File

@ -0,0 +1,307 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import VnInput from 'src/components/common/VnInput.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 stateOptions = [
jsegarra marked this conversation as resolved
Review

No se traducen

No se traducen
Review

Corregido.

Commit: 81a630d6cd

Corregido. Commit: https://gitea.verdnatura.es/verdnatura/salix-front/commit/81a630d6cd9bb0f85d3031a0f22dcf87b85936cd
{ code: 'pending', name: t('Pending') },
{ code: 'accepted', name: t('Accepted') },
{ code: 'denied', name: t('Denied') },
];
const itemTypesOptions = ref([]);
const warehousesOptions = ref([]);
const workersOptions = ref([]);
const exprBuilder = (param, value) => {
switch (param) {
case 'ticketFk':
case 'quantity':
case 'price':
case 'isOk':
return { [`tr.${param}`]: value };
case 'attenderName':
return { [`ua.name`]: value };
case 'shipped':
return {
't.shipped': {
between: dateRange(value),
},
};
}
};
const dateRange = (value) => {
const minHour = new Date(value);
minHour.setHours(0, 0, 0, 0);
const maxHour = new Date(value);
maxHour.setHours(23, 59, 59, 59);
return [minHour, maxHour];
};
const add = (paramsObj, key) => {
if (paramsObj[key] === undefined) {
paramsObj[key] = 1;
} else {
paramsObj[key]++;
}
};
const decrement = (paramsObj, key) => {
if (paramsObj[key] === 0) return;
paramsObj[key]--;
};
</script>
<template>
<FetchData
url="TicketRequests/getItemTypeWorker"
:filter="{ fields: ['id', 'nickname'], order: 'nickname ASC' }"
@on-fetch="(data) => (itemTypesOptions = data)"
auto-load
/>
<FetchData
url="warehouses"
:filter="{ order: 'name ASC' }"
@on-fetch="(data) => (warehousesOptions = data)"
auto-load
/>
<FetchData
url="Workers/search"
:filter="{
fields: ['id', 'name'],
order: 'name ASC',
}"
:params="{
departmentCodes: ['VT'],
}"
@on-fetch="(data) => (workersOptions = data)"
auto-load
/>
<VnFilterPanel
:data-key="props.dataKey"
:search-button="true"
:expr-builder="exprBuilder"
>
<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>
<QItemSection>
<VnInput
v-model="params.search"
:label="t('params.search')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.ticketFk"
:label="t('params.ticketFk')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelectFilter
v-model="params.attenderFk"
:label="t('params.attenderFk')"
@update:model-value="searchFn()"
:options="itemTypesOptions"
option-value="id"
option-label="nickname"
hide-selected
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.clientFk"
:label="t('params.clientFk')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelectFilter
:label="t('params.warehouseFk')"
v-model="params.warehouseFk"
@update:model-value="searchFn()"
:options="warehousesOptions"
option-value="id"
option-label="name"
hide-selected
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelectFilter
:label="t('params.requesterFk')"
v-model="params.requesterFk"
@update:model-value="searchFn()"
:options="workersOptions"
option-value="id"
option-label="name"
hide-selected
dense
outlined
rounded
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelectFilter>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('params.from')"
v-model="params.from"
@update:model-value="searchFn()"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('params.to')"
v-model="params.to"
@update:model-value="searchFn()"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.scopeDays"
:label="t('params.scopeDays')"
type="number"
dense
outlined
rounded
:min="0"
>
<template #append>
<QBtn
icon="add"
flat
dense
size="12px"
@click="add(params, 'scopeDays')"
/>
<QBtn
icon="remove"
flat
dense
size="12px"
@click="decrement(params, 'scopeDays')"
/>
</template>
</VnInput>
</QItemSection>
</QItem>
<!-- <vn-icon color-marginal
jsegarra marked this conversation as resolved Outdated
Outdated
Review

Quitar?

Quitar?

Lo había dejado a modo recordatorio para aplicarlo pero se me pasó. Ahora si lo apliqué.

Commit: a3cc6ed95b

Lo había dejado a modo recordatorio para aplicarlo pero se me pasó. Ahora si lo apliqué. Commit: https://gitea.verdnatura.es/verdnatura/salix-front/commit/a3cc6ed95b1da98c014fbf23a73eaf0b67315b12
icon="info"
vn-tooltip="Cannot choose a range of dates and days onward at the same time">
</vn-icon> -->
<QItem>
<QItemSection>
<QCheckbox
:label="t('params.mine')"
v-model="params.mine"
toggle-indeterminate
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelectFilter
:label="t('params.state')"
v-model="params.state"
@update:model-value="searchFn()"
:options="stateOptions"
option-value="code"
option-label="name"
hide-selected
dense
outlined
rounded
/>
</QItemSection>
</QItem>
</template>
</VnFilterPanel>
</template>
<i18n>
en:
params:
search: General search
ticketFk: Ticket id
attenderFk: Atender
clientFk: Client id
warehouseFk: Warehouse
requesterFk: Salesperson
from: From
to: To
scopeDays: Days onward
mine: For me
state: State
es:
params:
search: Búsqueda general
ticketFk: Id ticket
attenderFk: Comprador
clientFk: Id cliente
warehouseFk: Almacén
requesterFk: Comercial
from: Desde
to: Hasta
scopeDays: Días adelante
mine: Para mi
state: Estado
</i18n>