Compare commits
17 Commits
dev
...
6564-enhan
Author | SHA1 | Date |
---|---|---|
|
36f2328656 | |
|
bed4763e88 | |
|
7b1e126966 | |
|
304a039ebd | |
|
acddcd58b8 | |
|
90d556c892 | |
|
3c2c40c8e6 | |
|
345dc4bfbc | |
|
5325095297 | |
|
76b914e6be | |
|
aa91209ab7 | |
|
4ba57a1ca3 | |
|
498e8c385e | |
|
fda024d6fe | |
|
35dac33ff9 | |
|
82fa3b4648 | |
|
aa3810a4c0 |
src
components
pages
Entry
Monitor
Ticket
Travel
test/cypress/integration/entry
|
@ -1,65 +1,63 @@
|
|||
import { vi, describe, expect, it, beforeEach, afterEach } from 'vitest';
|
||||
import { vi, describe, expect, it, beforeEach, beforeAll, afterEach } from 'vitest';
|
||||
import { createWrapper } from 'app/test/vitest/helper';
|
||||
import UserPanel from 'src/components/UserPanel.vue';
|
||||
import axios from 'axios';
|
||||
import { useState } from 'src/composables/useState';
|
||||
|
||||
vi.mock('src/utils/quasarLang', () => ({
|
||||
default: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('UserPanel', () => {
|
||||
let wrapper;
|
||||
let vm;
|
||||
let state;
|
||||
let wrapper;
|
||||
let vm;
|
||||
let state;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = createWrapper(UserPanel, {});
|
||||
state = useState();
|
||||
state.setUser({
|
||||
id: 115,
|
||||
name: 'itmanagement',
|
||||
nickname: 'itManagementNick',
|
||||
lang: 'en',
|
||||
darkMode: false,
|
||||
companyFk: 442,
|
||||
warehouseFk: 1,
|
||||
beforeEach(() => {
|
||||
wrapper = createWrapper(UserPanel, {});
|
||||
state = useState();
|
||||
state.setUser({
|
||||
id: 115,
|
||||
name: 'itmanagement',
|
||||
nickname: 'itManagementNick',
|
||||
lang: 'en',
|
||||
darkMode: false,
|
||||
companyFk: 442,
|
||||
warehouseFk: 1,
|
||||
});
|
||||
wrapper = wrapper.wrapper;
|
||||
vm = wrapper.vm;
|
||||
});
|
||||
wrapper = wrapper.wrapper;
|
||||
vm = wrapper.vm;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fetch warehouses data on mounted', async () => {
|
||||
const fetchData = wrapper.findComponent({ name: 'FetchData' });
|
||||
expect(fetchData.props('url')).toBe('Warehouses');
|
||||
expect(fetchData.props('autoLoad')).toBe(true);
|
||||
});
|
||||
it('should fetch warehouses data on mounted', async () => {
|
||||
const fetchData = wrapper.findComponent({ name: 'FetchData' });
|
||||
expect(fetchData.props('url')).toBe('Warehouses');
|
||||
expect(fetchData.props('autoLoad')).toBe(true);
|
||||
});
|
||||
|
||||
it('should toggle dark mode correctly and update preferences', async () => {
|
||||
await vm.saveDarkMode(true);
|
||||
expect(axios.patch).toHaveBeenCalledWith('/UserConfigs/115', { darkMode: true });
|
||||
expect(vm.user.darkMode).toBe(true);
|
||||
await vm.updatePreferences();
|
||||
expect(vm.darkMode).toBe(true);
|
||||
});
|
||||
it('should toggle dark mode correctly and update preferences', async () => {
|
||||
await vm.saveDarkMode(true);
|
||||
expect(axios.patch).toHaveBeenCalledWith('/UserConfigs/115', { darkMode: true });
|
||||
expect(vm.user.darkMode).toBe(true);
|
||||
vm.updatePreferences();
|
||||
expect(vm.darkMode).toBe(true);
|
||||
});
|
||||
|
||||
it('should change user language and update preferences', async () => {
|
||||
const userLanguage = 'es';
|
||||
await vm.saveLanguage(userLanguage);
|
||||
expect(axios.patch).toHaveBeenCalledWith('/VnUsers/115', { lang: userLanguage });
|
||||
expect(vm.user.lang).toBe(userLanguage);
|
||||
await vm.updatePreferences();
|
||||
expect(vm.locale).toBe(userLanguage);
|
||||
});
|
||||
it('should change user language and update preferences', async () => {
|
||||
const userLanguage = 'es';
|
||||
await vm.saveLanguage(userLanguage);
|
||||
expect(axios.patch).toHaveBeenCalledWith('/VnUsers/115', { lang: userLanguage });
|
||||
expect(vm.user.lang).toBe(userLanguage);
|
||||
vm.updatePreferences();
|
||||
expect(vm.locale).toBe(userLanguage);
|
||||
});
|
||||
|
||||
it('should update user data', async () => {
|
||||
const key = 'name';
|
||||
const value = 'itboss';
|
||||
await vm.saveUserData(key, value);
|
||||
expect(axios.post).toHaveBeenCalledWith('UserConfigs/setUserConfig', { [key]: value });
|
||||
});
|
||||
});
|
||||
it('should update user data', async () => {
|
||||
const key = 'name';
|
||||
const value = 'itboss';
|
||||
await vm.saveUserData(key, value);
|
||||
expect(axios.post).toHaveBeenCalledWith('UserConfigs/setUserConfig', {
|
||||
[key]: value,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -57,5 +57,4 @@ function handleClick() {
|
|||
{{ capitalize(type).replace('-', '') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
{{ phoneNumber }}
|
||||
</template>
|
||||
|
|
|
@ -43,7 +43,7 @@ const val = computed(() => $props.value);
|
|||
<span style="color: var(--vn-label-color)">{{ label }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="value" v-if="value || $slots.value">
|
||||
<div class="value">
|
||||
<slot name="value">
|
||||
<span :title="value" style="text-overflow: ellipsis">
|
||||
{{ dash ? dashIfEmpty(value) : value }}
|
||||
|
|
|
@ -248,7 +248,7 @@ function getBadgeAttrs(row) {
|
|||
|
||||
let timeDiff = today - timeTicket;
|
||||
|
||||
if (timeDiff < 0) return { color: 'warning', 'text-color': 'black' };
|
||||
if (timeDiff > 0) return { color: 'info', 'text-color': 'black' };
|
||||
switch (row.entryTypeCode) {
|
||||
case 'regularization':
|
||||
case 'life':
|
||||
|
@ -273,7 +273,7 @@ function getBadgeAttrs(row) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (timeDiff > 0) return { color: 'info', 'text-color': 'black' };
|
||||
if (timeDiff < 0) return { color: 'warning', 'text-color': 'black' };
|
||||
return { color: 'transparent' };
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import DepartmentDescriptorProxy from '../Worker/Department/Card/DepartmentDescriptorProxy.vue';
|
||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||
import { toDateFormat } from 'src/filters/date.js';
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
import VnRow from 'src/components/ui/VnRow.vue';
|
||||
import { dateRange } from 'src/filters';
|
||||
import useOpenURL from 'src/composables/useOpenURL';
|
||||
const { t } = useI18n();
|
||||
|
||||
const dates = dateRange(Date.vnNew());
|
||||
|
@ -95,7 +94,6 @@ const columns = computed(() => [
|
|||
columnClass: 'no-padding',
|
||||
},
|
||||
]);
|
||||
const openTab = (id) => useOpenURL(`#/customer/${id}/summary`);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -115,8 +113,6 @@ const openTab = (id) => useOpenURL(`#/customer/${id}/summary`);
|
|||
:disable-option="{ card: true }"
|
||||
dense
|
||||
class="q-px-none"
|
||||
:row-click="({ id }) => openTab(id)"
|
||||
:row-ctrl-click="(_, { id }) => openTab(id)"
|
||||
>
|
||||
<template #top-left>
|
||||
<VnRow>
|
||||
|
@ -125,16 +121,12 @@ const openTab = (id) => useOpenURL(`#/customer/${id}/summary`);
|
|||
</VnRow>
|
||||
</template>
|
||||
<template #column-departmentFk="{ row }">
|
||||
<span @click.stop.prevent class="link" :title="row.department">
|
||||
{{ row.department }}
|
||||
<DepartmentDescriptorProxy :id="row.departmentFk" dense
|
||||
/></span>
|
||||
<span class="link" :title="row.department" v-text="row.department" />
|
||||
<WorkerDescriptorProxy :id="row.departmentFk" dense />
|
||||
</template>
|
||||
<template #column-clientFk="{ row }">
|
||||
<span @click.stop.prevent class="link" :title="row.clientName">
|
||||
{{ row.clientName }}
|
||||
<CustomerDescriptorProxy :id="row.clientFk" dense
|
||||
/></span>
|
||||
<span class="link" :title="row.clientName" v-text="row.clientName" />
|
||||
<CustomerDescriptorProxy :id="row.clientFk" />
|
||||
</template>
|
||||
</VnTable>
|
||||
</template>
|
||||
|
|
|
@ -9,7 +9,6 @@ import { toDateFormat, toDateTimeFormat } from 'src/filters/date.js';
|
|||
import { toCurrency } from 'src/filters';
|
||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||
import axios from 'axios';
|
||||
import useOpenURL from 'src/composables/useOpenURL';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openConfirmationModal } = useVnConfirm();
|
||||
|
@ -109,7 +108,8 @@ const removeOrders = async () => {
|
|||
await table.value.reload();
|
||||
};
|
||||
|
||||
const openTab = (id) => useOpenURL(`#/order/${id}/summary`);
|
||||
const openTab = (id) =>
|
||||
window.open(`#/order/${id}/summary`, '_blank', 'noopener, noreferrer');
|
||||
</script>
|
||||
<template>
|
||||
<VnTable
|
||||
|
@ -129,7 +129,6 @@ const openTab = (id) => useOpenURL(`#/order/${id}/summary`);
|
|||
}"
|
||||
default-mode="table"
|
||||
:row-click="({ id }) => openTab(id)"
|
||||
:row-ctrl-click="(_, { id }) => openTab(id)"
|
||||
v-model:selected="selectedRows"
|
||||
:disable-option="{ card: true }"
|
||||
>
|
||||
|
@ -178,16 +177,16 @@ const openTab = (id) => useOpenURL(`#/order/${id}/summary`);
|
|||
</template>
|
||||
|
||||
<template #column-clientFk="{ row }">
|
||||
<span class="link" @click.stop :title="row.clientName">
|
||||
{{ row.clientName }}
|
||||
<CustomerDescriptorProxy :id="row.clientFk" dense
|
||||
/></span>
|
||||
<QTd @click.stop>
|
||||
<span class="link" v-text="row.clientName" :title="row.clientName" />
|
||||
<CustomerDescriptorProxy :id="row.clientFk" />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #column-departmentFk="{ row }">
|
||||
<span class="link" @click.stop :title="row.departmentName">
|
||||
{{ row.departmentName }}
|
||||
<DepartmentDescriptorProxy :id="row.departmentFk" dense
|
||||
/></span>
|
||||
<QTd @click.stop>
|
||||
<span class="link" v-text="row.departmentName" />
|
||||
<DepartmentDescriptorProxy :id="row.departmentFk" dense />
|
||||
</QTd>
|
||||
</template>
|
||||
</VnTable>
|
||||
</template>
|
||||
|
|
|
@ -449,19 +449,21 @@ const openTab = (id) => useOpenURL(`#/ticket/${id}/sale`);
|
|||
<span :title="row.province" v-text="row.province" />
|
||||
</template>
|
||||
<template #column-state="{ row }">
|
||||
<div v-if="row.refFk" @click.stop.prevent>
|
||||
<span class="link">{{ row.refFk }}</span>
|
||||
<InvoiceOutDescriptorProxy :id="row.invoiceOutId" />
|
||||
<div @click.stop.prevent>
|
||||
<div v-if="row.refFk">
|
||||
<span class="link">{{ row.refFk }}</span>
|
||||
<InvoiceOutDescriptorProxy :id="row.invoiceOutId" />
|
||||
</div>
|
||||
<QBadge
|
||||
v-else
|
||||
:color="stateColors[row.classColor] || 'transparent'"
|
||||
:text-color="stateColors[row.classColor] ? 'black' : 'white'"
|
||||
class="q-pa-sm"
|
||||
style="font-size: 14px"
|
||||
>
|
||||
{{ row.state }}
|
||||
</QBadge>
|
||||
</div>
|
||||
<QBadge
|
||||
v-else
|
||||
:color="stateColors[row.classColor] || 'transparent'"
|
||||
:text-color="stateColors[row.classColor] ? 'black' : 'white'"
|
||||
class="q-pa-sm"
|
||||
style="font-size: 14px"
|
||||
>
|
||||
{{ row.state }}
|
||||
</QBadge>
|
||||
</template>
|
||||
<template #column-isFragile="{ row }">
|
||||
<QIcon v-if="row.isFragile" name="local_bar" color="primary" size="sm">
|
||||
|
|
|
@ -216,23 +216,27 @@ onMounted(async () => {
|
|||
:value="toDate(entity.landed)"
|
||||
/>
|
||||
<VnLv :label="t('globals.packages')" :value="entity.packages" />
|
||||
<VnLv :label="t('ticket.summary.consigneePhone')">
|
||||
<template #value>
|
||||
<VnLv :value="entity.address.phone">
|
||||
<template #label>
|
||||
{{ t('ticket.summary.consigneePhone') }}
|
||||
<VnLinkPhone :phone-number="entity.address.phone" />
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv :label="t('ticket.summary.consigneeMobile')">
|
||||
<template #value>
|
||||
<VnLv :value="entity.address.mobile">
|
||||
<template #label>
|
||||
{{ t('ticket.summary.consigneeMobile') }}
|
||||
<VnLinkPhone :phone-number="entity.address.mobile" />
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv :label="t('ticket.summary.clientPhone')">
|
||||
<template #value>
|
||||
<VnLv :value="entity.client.phone">
|
||||
<template #label>
|
||||
{{ t('ticket.summary.clientPhone') }}
|
||||
<VnLinkPhone :phone-number="entity.client.phone" />
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv :label="t('ticket.summary.clientMobile')">
|
||||
<template #value>
|
||||
<VnLv :value="entity.client.mobile">
|
||||
<template #label>
|
||||
{{ t('ticket.summary.clientMobile') }}
|
||||
<VnLinkPhone :phone-number="entity.client.mobile" />
|
||||
</template>
|
||||
</VnLv>
|
||||
|
|
|
@ -14,6 +14,8 @@ import { useState } from 'src/composables/useState';
|
|||
import { toDateFormat } from 'src/filters/date.js';
|
||||
import axios from 'axios';
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
import { QTable } from 'quasar';
|
||||
import TicketProblems from 'src/components/TicketProblems.vue';
|
||||
|
||||
const state = useState();
|
||||
const { t } = useI18n();
|
||||
|
@ -27,6 +29,16 @@ const selectedTickets = ref([]);
|
|||
const vnTableRef = ref({});
|
||||
const originElRef = ref(null);
|
||||
const destinationElRef = ref(null);
|
||||
const actions = {
|
||||
advance: {
|
||||
title: t('advanceTickets.advanceTickets'),
|
||||
cb: moveTicketsAdvance,
|
||||
},
|
||||
advanceWithoutNegative: {
|
||||
title: t('advanceTickets.advanceTicketsWithoutNegatives'),
|
||||
cb: splitTickets,
|
||||
},
|
||||
};
|
||||
let today = Date.vnNew().toISOString();
|
||||
const tomorrow = new Date(today);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
@ -78,6 +90,15 @@ const ticketColumns = computed(() => [
|
|||
headerClass: 'horizontal-separator',
|
||||
hidden: true,
|
||||
},
|
||||
{
|
||||
label: t('globals.agency'),
|
||||
name: 'agency',
|
||||
field: 'agency',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
headerClass: 'horizontal-separator',
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
label: t('advanceTickets.preparation'),
|
||||
name: 'preparation',
|
||||
|
@ -85,7 +106,6 @@ const ticketColumns = computed(() => [
|
|||
align: 'left',
|
||||
sortable: true,
|
||||
headerClass: 'horizontal-separator',
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -110,11 +130,17 @@ const ticketColumns = computed(() => [
|
|||
},
|
||||
{
|
||||
align: 'left',
|
||||
label: t('advanceTickets.futureId'),
|
||||
name: 'futureId',
|
||||
label: t('advanceTickets.problems'),
|
||||
name: 'totalProblems',
|
||||
headerClass: 'vertical-separator horizontal-separator',
|
||||
columnClass: 'vertical-separator',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
label: t('advanceTickets.futureId'),
|
||||
name: 'futureId',
|
||||
headerClass: 'horizontal-separator',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
label: t('advanceTickets.futureIpt'),
|
||||
|
@ -242,7 +268,7 @@ const requestComponentUpdate = async (ticket, isWithoutNegatives) => {
|
|||
return { query, params };
|
||||
};
|
||||
|
||||
const moveTicketsAdvance = async () => {
|
||||
async function moveTicketsAdvance() {
|
||||
let ticketsToMove = [];
|
||||
for (const ticket of selectedTickets.value) {
|
||||
if (!ticket.id) {
|
||||
|
@ -267,7 +293,7 @@ const moveTicketsAdvance = async () => {
|
|||
vnTableRef.value.reload();
|
||||
selectedTickets.value = [];
|
||||
if (ticketsToMove.length) notify(t('advanceTickets.moveTicketSuccess'), 'positive');
|
||||
};
|
||||
}
|
||||
|
||||
const progressLength = ref(0);
|
||||
const progressPercentage = computed(() => {
|
||||
|
@ -290,7 +316,7 @@ const progressAdd = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const splitTickets = async () => {
|
||||
async function splitTickets() {
|
||||
try {
|
||||
showProgressDialog.value = true;
|
||||
for (const ticket of selectedTickets.value) {
|
||||
|
@ -310,7 +336,7 @@ const splitTickets = async () => {
|
|||
} finally {
|
||||
vnTableRef.value.reload();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const resetProgressData = () => {
|
||||
if (cancelProgress.value) cancelProgress.value = false;
|
||||
|
@ -326,6 +352,32 @@ const handleCloseProgressDialog = () => {
|
|||
|
||||
const handleCancelProgress = () => (cancelProgress.value = true);
|
||||
|
||||
const confirmAction = (action) => {
|
||||
openConfirmationModal(actions[action].title, false, actions[action].cb, null, {
|
||||
component: QTable,
|
||||
props: {
|
||||
columns: [
|
||||
{
|
||||
align: 'left',
|
||||
label: t('advanceTickets.destination'),
|
||||
name: 'id',
|
||||
field: (row) => row.id,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
label: t('advanceTickets.origin'),
|
||||
name: 'futureId',
|
||||
field: (row) => row.futureId,
|
||||
},
|
||||
],
|
||||
rows: selectedTickets.value,
|
||||
class: 'full-width',
|
||||
dense: true,
|
||||
flat: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => vnTableRef.value.tableRef?.$el,
|
||||
($el) => {
|
||||
|
@ -399,15 +451,7 @@ watch(
|
|||
color="primary"
|
||||
class="q-mr-sm"
|
||||
:disable="!selectedTickets.length"
|
||||
@click.stop="
|
||||
openConfirmationModal(
|
||||
t('advanceTickets.advanceTicketTitle'),
|
||||
t(`advanceTickets.advanceTitleSubtitle`, {
|
||||
selectedTickets: selectedTickets.length,
|
||||
}),
|
||||
moveTicketsAdvance,
|
||||
)
|
||||
"
|
||||
@click.stop="confirmAction('advance')"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('advanceTickets.advanceTickets') }}
|
||||
|
@ -417,15 +461,7 @@ watch(
|
|||
icon="alt_route"
|
||||
color="primary"
|
||||
:disable="!selectedTickets.length"
|
||||
@click.stop="
|
||||
openConfirmationModal(
|
||||
t('advanceTickets.advanceWithoutNegativeTitle'),
|
||||
t(`advanceTickets.advanceWithoutNegativeSubtitle`, {
|
||||
selectedTickets: selectedTickets.length,
|
||||
}),
|
||||
splitTickets,
|
||||
)
|
||||
"
|
||||
@click.stop="confirmAction('advanceWithoutNegative')"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('advanceTickets.advanceTicketsWithoutNegatives') }}
|
||||
|
@ -454,9 +490,9 @@ watch(
|
|||
}"
|
||||
v-model:selected="selectedTickets"
|
||||
:pagination="{ rowsPerPage: 0 }"
|
||||
:no-data-label="t('globals.noResults')"
|
||||
:no-data-label="$t('globals.noResults')"
|
||||
:right-search="false"
|
||||
:order="['futureTotalWithVat ASC']"
|
||||
:order="['futureTotalWithVat ASC']"
|
||||
auto-load
|
||||
:disable-option="{ card: true }"
|
||||
>
|
||||
|
@ -522,6 +558,9 @@ watch(
|
|||
{{ toCurrency(row.totalWithVat || 0) }}
|
||||
</QBadge>
|
||||
</template>
|
||||
<template #column-problems="{ row }">
|
||||
<TicketProblems :row="row" />
|
||||
</template>
|
||||
<template #column-futureId="{ row }">
|
||||
<QBtn flat class="link" dense>
|
||||
{{ row.futureId }}
|
||||
|
|
|
@ -124,6 +124,7 @@ onMounted(async () => await getItemPackingTypes());
|
|||
v-model="params.scopeDays"
|
||||
:label="t('Days onward')"
|
||||
filled
|
||||
:step="0"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
|
|
@ -56,6 +56,7 @@ advanceTickets:
|
|||
search: Search advance tickets
|
||||
searchInfo: Search advance tickets by ID or client ID
|
||||
clonedSales: Has turn lines
|
||||
problems: Problems
|
||||
futureTickets:
|
||||
problems: Problems
|
||||
shipped: Date
|
||||
|
|
|
@ -91,6 +91,7 @@ advanceTickets:
|
|||
search: Buscar por tickets adelantados
|
||||
searchInfo: Buscar tickets adelantados por el identificador o el identificador del cliente
|
||||
clonedSales: Tiene líneas de turno
|
||||
problems: Problemas
|
||||
futureTickets:
|
||||
problems: Problemas
|
||||
shipped: Fecha
|
||||
|
|
|
@ -141,6 +141,7 @@ const columns = computed(() => [
|
|||
label: 'id',
|
||||
field: 'id',
|
||||
name: 'id',
|
||||
align: 'center',
|
||||
showValue: true,
|
||||
sortable: true,
|
||||
},
|
||||
|
@ -164,7 +165,7 @@ const columns = computed(() => [
|
|||
label: t('globals.amount'),
|
||||
name: 'invoiceAmount',
|
||||
field: 'entries',
|
||||
align: 'right',
|
||||
align: 'left',
|
||||
showValue: true,
|
||||
sortable: true,
|
||||
format: (value) =>
|
||||
|
@ -189,7 +190,7 @@ const columns = computed(() => [
|
|||
label: t('globals.packages'),
|
||||
field: 'stickers',
|
||||
name: 'stickers',
|
||||
align: 'right',
|
||||
align: 'left',
|
||||
showValue: true,
|
||||
sortable: true,
|
||||
},
|
||||
|
@ -197,7 +198,7 @@ const columns = computed(() => [
|
|||
label: '%',
|
||||
field: '',
|
||||
name: 'percentage',
|
||||
align: 'right',
|
||||
align: 'center',
|
||||
showValue: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
@ -213,7 +214,7 @@ const columns = computed(() => [
|
|||
label: t('extraCommunity.physicKg'),
|
||||
field: 'loadedKg',
|
||||
name: 'loadedKg',
|
||||
align: 'right',
|
||||
align: 'left',
|
||||
showValue: true,
|
||||
sortable: true,
|
||||
},
|
||||
|
@ -221,7 +222,7 @@ const columns = computed(() => [
|
|||
label: 'KG Vol.',
|
||||
field: 'volumeKg',
|
||||
name: 'volumeKg',
|
||||
align: 'right',
|
||||
align: 'left',
|
||||
showValue: true,
|
||||
sortable: true,
|
||||
},
|
||||
|
@ -276,6 +277,7 @@ async function getData() {
|
|||
const onStoreDataChange = () => {
|
||||
const newData = JSON.parse(JSON.stringify(arrayData.store.data)) || [];
|
||||
rows.value = newData;
|
||||
// el objetivo de esto es guardar una copia de los valores iniciales de todas las rows para corroborar si la data cambio antes de guardar los cambios
|
||||
originalRowDataCopy.value = JSON.parse(JSON.stringify(newData));
|
||||
};
|
||||
|
||||
|
@ -298,17 +300,20 @@ const openReportPdf = () => {
|
|||
};
|
||||
|
||||
const saveFieldValue = async (val, field, index) => {
|
||||
// Evitar la solicitud de guardado si el valor no ha cambiado
|
||||
if (originalRowDataCopy.value[index][field] == val) return;
|
||||
|
||||
const id = rows.value[index].id;
|
||||
const params = { [field]: val };
|
||||
await axios.patch(`Travels/${id}`, params);
|
||||
// Actualizar la copia de los datos originales con el nuevo valor
|
||||
originalRowDataCopy.value[index][field] = val;
|
||||
|
||||
await arrayData.fetch({ append: false });
|
||||
};
|
||||
|
||||
const stopEventPropagation = (event, col) => {
|
||||
// Detener la propagación del evento de los siguientes elementos para evitar el click sobre la row que dispararía la función navigateToTravelId
|
||||
if (!['ref', 'id', 'cargoSupplierNickname', 'kg'].includes(col.name)) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
@ -330,12 +335,14 @@ onMounted(async () => {
|
|||
await getData();
|
||||
});
|
||||
|
||||
// Handler del evento @dragstart (inicio del drag) y guarda información inicial
|
||||
const handleDragStart = (event, rowIndex, entryIndex) => {
|
||||
draggedRowIndex.value = rowIndex;
|
||||
entryRowIndex.value = entryIndex;
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
};
|
||||
|
||||
// Handler del evento @dragenter (cuando haces drag sobre une elemento y lo arrastras sobre un posible target de drop) y actualiza el targetIndex
|
||||
const handleDragEnter = (_, targetIndex) => {
|
||||
targetRowIndex.value = targetIndex;
|
||||
};
|
||||
|
@ -349,8 +356,11 @@ const saveRowDrop = async (targetRowIndex) => {
|
|||
const moveRow = async (draggedRowIndex, targetRowIndex, entryIndex) => {
|
||||
try {
|
||||
if (draggedRowIndex === targetRowIndex) return;
|
||||
// Remover entry de la row original
|
||||
draggedEntry.value = rows.value[draggedRowIndex].entries.splice(entryIndex, 1)[0];
|
||||
//Si la row de destino por alguna razón no tiene la propiedad entry la creamos
|
||||
if (!rows.value[targetRowIndex].entries) rows.value[targetRowIndex].entries = [];
|
||||
// Añadir entry a la row de destino
|
||||
rows.value[targetRowIndex].entries.push(draggedEntry.value);
|
||||
|
||||
await saveRowDrop(targetRowIndex);
|
||||
|
@ -360,11 +370,13 @@ const moveRow = async (draggedRowIndex, targetRowIndex, entryIndex) => {
|
|||
}
|
||||
};
|
||||
|
||||
// Handler de cuando haces un drop tanto dentro como fuera de la tabla para limpiar acciones y data
|
||||
const handleDragEnd = () => {
|
||||
stopScroll();
|
||||
cleanDragAndDropData();
|
||||
};
|
||||
|
||||
// Handler del evento @drop (cuando soltas el elemento draggeado sobre un target)
|
||||
const handleDrop = () => {
|
||||
if (
|
||||
!draggedRowIndex.value &&
|
||||
|
@ -387,6 +399,7 @@ const cleanDragAndDropData = () => {
|
|||
const scrollInterval = ref(null);
|
||||
|
||||
const startScroll = (direction) => {
|
||||
// Iniciar el scroll en la dirección especificada
|
||||
if (!scrollInterval.value) {
|
||||
scrollInterval.value = requestAnimationFrame(() => scroll(direction));
|
||||
}
|
||||
|
@ -400,12 +413,14 @@ const stopScroll = () => {
|
|||
};
|
||||
|
||||
const scroll = (direction) => {
|
||||
// Controlar el desplazamiento en la dirección especificada
|
||||
const yOffset = direction === 'up' ? -2 : 2;
|
||||
window.scrollBy(0, yOffset);
|
||||
|
||||
const windowHeight = window.innerHeight;
|
||||
const documentHeight = document.body.offsetHeight;
|
||||
|
||||
// Verificar si se alcanzaron los límites de la ventana para detener el desplazamiento
|
||||
if (
|
||||
(direction === 'up' && window.scrollY > 0) ||
|
||||
(direction === 'down' && windowHeight + window.scrollY < documentHeight)
|
||||
|
@ -416,10 +431,13 @@ const scroll = (direction) => {
|
|||
}
|
||||
};
|
||||
|
||||
// Handler del scroll mientras se hace el drag de una row
|
||||
const handleDragScroll = (event) => {
|
||||
// Obtener la posición y dimensiones del cursor
|
||||
const y = event.clientY;
|
||||
const windowHeight = window.innerHeight;
|
||||
|
||||
// Verificar si el cursor está cerca del borde superior o inferior de la ventana
|
||||
const nearTop = y < 150;
|
||||
const nearBottom = y > windowHeight - 100;
|
||||
|
||||
|
@ -529,7 +547,7 @@ watch(route, () => {
|
|||
? `${props.row.percentageKg}%`
|
||||
: '-'
|
||||
"
|
||||
class="text-right q-py-xs q-px-sm"
|
||||
class="text-left q-py-xs q-px-sm"
|
||||
:color="getColor(props.row.percentageKg)"
|
||||
/>
|
||||
<span
|
||||
|
@ -548,6 +566,7 @@ watch(route, () => {
|
|||
]"
|
||||
v-text="col.value"
|
||||
/>
|
||||
<!-- Main Row Descriptors -->
|
||||
<TravelDescriptorProxy
|
||||
v-if="col.name === 'id'"
|
||||
:id="props.row.id"
|
||||
|
@ -578,7 +597,7 @@ watch(route, () => {
|
|||
index === props.row.entries.length - 1,
|
||||
}"
|
||||
>
|
||||
<QTd class="text-right">
|
||||
<QTd>
|
||||
<QBtn dense flat class="link">{{ entry.id }} </QBtn>
|
||||
<EntryDescriptorProxy :id="entry.id" />
|
||||
</QTd>
|
||||
|
@ -586,7 +605,7 @@ watch(route, () => {
|
|||
<QBtn flat class="link" dense>{{ entry.supplierName }}</QBtn>
|
||||
<SupplierDescriptorProxy :id="entry.supplierFk" />
|
||||
</QTd>
|
||||
<QTd class="text-center">
|
||||
<QTd>
|
||||
<QIcon
|
||||
v-if="entry.isCustomInspectionRequired"
|
||||
name="warning"
|
||||
|
@ -596,21 +615,21 @@ watch(route, () => {
|
|||
>
|
||||
</QIcon>
|
||||
</QTd>
|
||||
<QTd class="text-right">
|
||||
<QTd>
|
||||
<span>{{ toCurrency(entry.invoiceAmount) }}</span>
|
||||
</QTd>
|
||||
<QTd>
|
||||
<span>{{ entry.reference }}</span>
|
||||
</QTd>
|
||||
<QTd class="text-right">
|
||||
<QTd>
|
||||
<span>{{ entry.stickers }}</span>
|
||||
</QTd>
|
||||
<QTd />
|
||||
<QTd></QTd>
|
||||
<QTd class="text-right">
|
||||
<QTd>
|
||||
<span>{{ entry.loadedkg }}</span>
|
||||
</QTd>
|
||||
<QTd class="text-right">
|
||||
<QTd>
|
||||
<span>{{ entry.volumeKg }}</span>
|
||||
</QTd>
|
||||
<QTd />
|
||||
|
@ -645,6 +664,9 @@ watch(route, () => {
|
|||
:deep(.q-table) {
|
||||
border-collapse: collapse;
|
||||
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
tbody tr td {
|
||||
&:nth-child(1) {
|
||||
max-width: 65px;
|
||||
|
@ -653,10 +675,6 @@ watch(route, () => {
|
|||
padding: 0;
|
||||
}
|
||||
}
|
||||
thead > tr > th {
|
||||
padding: 3px;
|
||||
color: var(--vn-label-color);
|
||||
}
|
||||
}
|
||||
|
||||
.q-td :deep(input) {
|
||||
|
|
|
@ -44,12 +44,11 @@ describe('EntryList', () => {
|
|||
},
|
||||
);
|
||||
|
||||
// fix on task https://redmine.verdnatura.es/issues/8638
|
||||
/* checkBadgeDate(
|
||||
checkBadgeDate(
|
||||
'td[data-col-field="landed"] > div .bg-info',
|
||||
(badgeDate, compareDate) => {
|
||||
expect(badgeDate.getTime()).to.be.lessThan(compareDate.getTime());
|
||||
},
|
||||
); */
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue