Weekly tickets #459

Merged
jsegarra merged 8 commits from :feature/WeeklyTickets into dev 2024-06-25 21:02:08 +00:00
12 changed files with 397 additions and 41 deletions

View File

@ -32,7 +32,7 @@ const url = computed(
() =>
`/api/${$props.storage}/${$props.collection}/${$props.size}/${$props.id}/download?access_token=${token}&${timeStamp.value}`
);
const reload = (emit = false) => {
const reload = () => {
timeStamp.value = `timestamp=${Date.now()}`;
};
defineExpose({

View File

@ -447,6 +447,7 @@ ticket:
ticketAdvance: Advance tickets
futureTickets: Future tickets
purchaseRequest: Purchase request
weeklyTickets: Weekly tickets
list:
nickname: Nickname
state: State

View File

@ -446,6 +446,7 @@ ticket:
ticketAdvance: Adelantar tickets
futureTickets: Tickets a futuro
purchaseRequest: Petición de compra
weeklyTickets: Tickets programados
list:
nickname: Alias
state: Estado

View File

@ -3,7 +3,6 @@ import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import VnSelect from 'src/components/common/VnSelect.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import { ref, watch } from 'vue';

View File

@ -1,5 +1,4 @@
<script setup>
import { useStateStore } from 'stores/useStateStore';
import { useI18n } from 'vue-i18n';
import { computed, onMounted, ref } from 'vue';
import { dashIfEmpty, toHour } from 'src/filters';

View File

@ -128,8 +128,8 @@ function confirmRemove() {
.onOk(() => refreshKey.value++);
}
function navigateToRoadmapSummary(event, row) {
router.push({ name: 'RoadmapSummary', params: { id: 1 } });
function navigateToRoadmapSummary(_, { id }) {
router.push({ name: 'RoadmapSummary', params: { id } });
}
</script>

View File

@ -1,7 +1,10 @@
<script setup>
import VnLog from 'src/components/common/VnLog.vue';
import { useRoute } from 'vue-router';
const route = useRoute();
</script>
<template>
<VnLog model="Ticket" url="/TicketLogs"></VnLog>
<VnLog model="Ticket" url="/TicketLogs" :key="route.params.id"></VnLog>
</template>

View File

@ -353,15 +353,14 @@ const newOrderFromTicket = async () => {
};
const goToLog = (saleId) => {
//TODO: Redireccionar cuando exista la vista TicketLog
// router.push({
// name: 'TicketLog',
// params: {
// originId: route.params.id,
// changedModel: 'Sale',
// changedModelId: saleId,
// },
// });
router.push({
name: 'TicketLog',
params: {
originId: route.params.id,
changedModel: 'Sale',
changedModelId: saleId,
},
});
};
const changeTicketState = async (val) => {
@ -725,8 +724,9 @@ onUnmounted(() => (stateStore.rightDrawer = false));
</QTd>
</template>
<template #body-cell-history="{ row }">
<QTd v-if="row.hasLogs">
<QTd>
<QBtn
v-if="row.$hasLogs"
@click.stop="goToLog(row.id)"
color="primary"
icon="history"

View File

@ -0,0 +1,326 @@
<script setup>
import { onMounted, ref, computed, reactive, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import FetchData from 'components/FetchData.vue';
import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import VnPaginate from 'components/ui/VnPaginate.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useStateStore } from 'stores/useStateStore';
import { dashIfEmpty } from 'src/filters';
import { useVnConfirm } from 'composables/useVnConfirm';
import { useArrayData } from 'composables/useArrayData';
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
const router = useRouter();
const stateStore = useStateStore();
const { t } = useI18n();
const { openConfirmationModal } = useVnConfirm();
const { notify } = useNotify();
const paginateRef = ref(null);
const agencyModesOptions = ref([]);
const visibleColumns = ref([]);
const allColumnNames = ref([]);
const arrayData = useArrayData('WeeklyTickets');
const { store } = arrayData;
const weekdays = [
Review

porque no usamos useWeekDayStore? Tendria sentido usarla?

porque no usamos useWeekDayStore? Tendria sentido usarla?
Review

Si tiene sentido, lo intente, pero los index que se setean en useWeekDayStore no coinciden con los que se requiere en esta tabla

Si tiene sentido, lo intente, pero los index que se setean en useWeekDayStore no coinciden con los que se requiere en esta tabla
{ id: 0, name: t('weekdays.mon') },
{ id: 1, name: t('weekdays.tue') },
{ id: 2, name: t('weekdays.wed') },
{ id: 3, name: t('weekdays.thu') },
{ id: 4, name: t('weekdays.fri') },
{ id: 5, name: t('weekdays.sat') },
{ id: 6, name: t('weekdays.sun') },
];
const exprBuilder = (param, value) => {
switch (param) {
case 'clientName':
return { 'c.name': value };
case 'nickName':
return { 'u.name': value };
}
};
const params = reactive({});
const applyColumnFilter = async (col) => {
try {
const paramKey = col.columnFilter?.filterParamKey || col.field;
params[paramKey] = col.columnFilter.filterValue;
await paginateRef.value.addFilter(null, params);
jsegarra marked this conversation as resolved
Review

👀💣🚩

👀💣🚩
Review

Removido.

Commit: de0ef06d92

Removido. Commit: https://gitea.verdnatura.es/verdnatura/salix-front/commit/de0ef06d926b01293350fe5a4ce76ad16307464e
} catch (err) {
console.error('Error applying column filter', err);
}
};
const getInputEvents = (col) => ({ 'keyup.enter': () => applyColumnFilter(col) });
const columns = computed(() => [
{
label: t('weeklyTickets.id'),
name: 'id',
field: 'ticketFk',
align: 'left',
sortable: true,
columnFilter: null,
},
{
label: t('weeklyTickets.client'),
name: 'client',
field: 'clientName',
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
format: (val) => dashIfEmpty(val),
},
{
label: t('weeklyTickets.shipment'),
name: 'shipment',
field: 'weekDay',
align: 'left',
sortable: true,
columnFilter: null,
},
{
label: t('weeklyTickets.agency'),
name: 'agency',
field: 'agencyModeFk',
align: 'left',
sortable: true,
columnFilter: null,
},
{
label: t('weeklyTickets.warehouse'),
name: 'warehouse',
field: 'warehouseName',
align: 'left',
sortable: true,
columnFilter: null,
},
{
label: t('weeklyTickets.salesperson'),
field: 'salesperson',
name: 'salesperson',
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
filterParamKey: 'nickName',
attrs: {
dense: true,
},
},
},
{
label: '',
name: 'actions',
align: 'left',
columnFilter: null,
},
]);
const redirectToTicketSummary = (ticketFk) =>
router.push({ name: 'TicketSummary', params: { id: ticketFk } });
const deleteWeekly = async (ticketFk) => {
try {
await axios.delete(`TicketWeeklies/${ticketFk}`);
notify(t('globals.dataSaved'), 'positive');
const ticketIndex = store.data.findIndex((e) => e.ticketFk == ticketFk);
store.data.splice(ticketIndex, 1);
} catch (err) {
console.error('Error deleting weekly', err);
}
};
const onUpdate = async (ticketFk, field, value) => {
try {
const params = { ticketFk, [field]: value };
await axios.patch('TicketWeeklies', params);
} catch (err) {
console.error('Error updating weekly', err);
}
};
onMounted(async () => {
stateStore.rightDrawer = true;
const filteredColumns = columns.value.filter((col) => col.name !== 'actions');
allColumnNames.value = filteredColumns.map((col) => col.name);
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>
<FetchData
url="AgencyModes/isActive"
:filter="{ fields: ['id', 'name'], order: 'name' }"
auto-load
@on-fetch="(data) => (agencyModesOptions = data)"
/>
<VnSearchbar
data-key="WeeklyTickets"
:label="t('weeklyTickets.search')"
:info="t('weeklyTickets.searchInfo')"
/>
<VnSubToolbar>
<template #st-data>
<TableVisibleColumns
:all-columns="allColumnNames"
table-code="itemsIndex"
labels-traductions-path="weeklyTickets"
@on-config-saved="visibleColumns = [...$event, 'actions']"
/>
</template>
</VnSubToolbar>
<QPage class="column items-center q-pa-md">
<VnPaginate
ref="paginateRef"
data-key="WeeklyTickets"
url="TicketWeeklies/filter"
:order="['weekDay', 'ticketFk']"
:limit="20"
:expr-builder="exprBuilder"
:user-params="params"
:offset="50"
Review

offset?

offset?
Review

He probado a tener 20 registros y el limit del componente a 5.
Puede ser casualidad, pero creo que queda mejor poniendo esta propiedad para que la animación del loading del botón no se vea tanto

He probado a tener 20 registros y el limit del componente a 5. Puede ser casualidad, pero creo que queda mejor poniendo esta propiedad para que la animación del loading del botón no se vea tanto
auto-load
>
<template #body="{ rows }">
<QTable
:rows="rows"
:columns="columns"
row-key="id"
:pagination="{ rowsPerPage: 0 }"
class="full-width q-mt-md"
:visible-columns="visibleColumns"
:no-data-label="t('globals.noResults')"
@row-click="(_, row) => redirectToTicketSummary(row.ticketFk)"
>
<template #top-row="{ cols }">
<QTr>
<QTd
v-for="(col, index) in cols"
:key="index"
style="max-width: 100px"
>
<component
:is="col.columnFilter.component"
v-if="col.columnFilter"
v-model="col.columnFilter.filterValue"
v-bind="col.columnFilter.attrs"
v-on="col.columnFilter.event(col)"
dense
/>
</QTd>
</QTr>
</template>
<template #body-cell-id="{ row }">
<QTd @click.stop>
<QBtn flat color="primary">
{{ row.ticketFk }}
<TicketDescriptorProxy :id="row.ticketFk" />
</QBtn>
</QTd>
</template>
<template #body-cell-salesperson="{ row }">
<QTd @click.stop>
<QBtn flat color="primary">
{{ row.userName }}
<WorkerDescriptorProxy :id="row.workerFk" />
</QBtn>
</QTd>
</template>
<template #body-cell-client="{ row }">
<QTd @click.stop>
<QBtn flat color="primary" dense>
{{ row.clientName }}
<CustomerDescriptorProxy :id="row.clientFk" />
</QBtn>
</QTd>
</template>
<template #body-cell-shipment="{ row }">
<QTd @click.stop>
<VnSelect
:options="weekdays"
hide-selected
option-label="name"
option-value="id"
v-model="row.weekDay"
@update:model-value="
onUpdate(row.ticketFk, 'weekDay', $event)
"
/>
</QTd>
</template>
<template #body-cell-agency="{ row }">
<QTd @click.stop>
<VnSelect
:options="agencyModesOptions"
hide-selected
option-label="name"
option-value="id"
v-model="row.agencyModeFk"
@update:model-value="
onUpdate(row.ticketFk, 'agencyModeFk', $event)
"
/>
</QTd>
</template>
<template #body-cell-actions="{ row }">
<QTd>
<QIcon
@click.stop="
openConfirmationModal(
t('You are going to delete this weekly ticket'),
t(
'This ticket will be removed from weekly tickets! Continue anyway?'
),
() => deleteWeekly(row.ticketFk)
)
"
class="q-ml-sm cursor-pointer"
color="primary"
name="delete"
size="sm"
>
<QTooltip>
{{ t('globals.delete') }}
</QTooltip>
</QIcon>
</QTd>
</template>
</QTable>
</template>
</VnPaginate>
</QPage>
</template>
<i18n>
es:
You are going to delete this weekly ticket: Vas a eliminar este ticket programado
This ticket will be removed from weekly tickets! Continue anyway?: Este ticket se eliminará de tickets programados! ¿Continuar de todas formas?
</i18n>

View File

@ -127,3 +127,12 @@ purchaseRequest:
saleFk: Item id
state: State
newRequest: New request
weeklyTickets:
id: Ticket ID
client: Client
shipment: Shipment
agency: Agency
warehouse: Warehouse
salesperson: Salesperson
search: Search weekly tickets
searchInfo: Search weekly tickets by id or client id

View File

@ -48,6 +48,15 @@ basicData:
negativesConfirmMessage: Se van a generar negativos, ¿seguro que quieres adelantar todas las líneas?
chooseAnOption: Elige una opción
unroutedTicket: El ticket ha sido desenrutado
weeklyTickets:
id: ID Ticket
client: Cliente
shipment: Salida
agency: Agencia
warehouse: Almacén
salesperson: Comercial
search: Buscar por tickets programados
searchInfo: Buscar tickets programados por el identificador o el identificador del cliente
advanceTickets:
origin: Origen
destination: Destinatario

View File

@ -11,7 +11,7 @@ export default {
component: RouterView,
redirect: { name: 'TicketMain' },
menus: {
main: ['TicketList', 'TicketAdvance', 'TicketFuture'],
main: ['TicketList', 'TicketAdvance', 'TicketWeekly', 'TicketFuture'],
card: [
'TicketBasicData',
'TicketBoxing',
@ -48,13 +48,13 @@ export default {
component: () => import('src/pages/Ticket/TicketCreate.vue'),
},
{
name: 'TicketAdvance',
path: 'advance',
name: 'TicketWeekly',
path: 'weekly',
meta: {
title: 'ticketAdvance',
icon: 'keyboard_double_arrow_left',
title: 'weeklyTickets',
icon: 'access_time',
},
component: () => import('src/pages/Ticket/TicketAdvance.vue'),
component: () => import('src/pages/Ticket/TicketWeekly.vue'),
},
{
name: 'TicketFuture',
@ -65,6 +65,15 @@ export default {
},
component: () => import('src/pages/Ticket/TicketFuture.vue'),
},
{
name: 'TicketAdvance',
path: 'advance',
meta: {
title: 'ticketAdvance',
icon: 'keyboard_double_arrow_left',
},
component: () => import('src/pages/Ticket/TicketAdvance.vue'),
},
],
},
{
@ -101,6 +110,25 @@ export default {
},
component: () => import('src/pages/Ticket/Card/TicketSale.vue'),
},
{
path: 'request',
name: 'TicketPurchaseRequest',
meta: {
title: 'purchaseRequest',
icon: 'vn:buyrequest',
},
component: () =>
import('src/pages/Ticket/Card/TicketPurchaseRequest.vue'),
},
{
path: 'log',
name: 'TicketLog',
meta: {
title: 'log',
icon: 'history',
},
component: () => import('src/pages/Ticket/Card/TicketLog.vue'),
},
{
path: 'boxing',
name: 'TicketBoxing',
@ -119,25 +147,6 @@ export default {
},
component: () => import('src/pages/Ticket/Card/TicketSms.vue'),
},
{
path: 'log',
name: 'TicketLog',
meta: {
title: 'log',
icon: 'history',
},
component: () => import('src/pages/Ticket/Card/TicketLog.vue'),
},
{
path: 'request',
name: 'TicketPurchaseRequest',
meta: {
title: 'purchaseRequest',
icon: 'vn:buyrequest',
},
component: () =>
import('src/pages/Ticket/Card/TicketPurchaseRequest.vue'),
},
],
},
],