Merge branch 'dev' into feature/TicketAdvanceFilter
This commit is contained in:
commit
e9ab0154fe
|
@ -55,10 +55,10 @@ const onResponseError = (error) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.isLoggedIn() && response?.status === 401) {
|
if (session.isLoggedIn() && response?.status === 401) {
|
||||||
session.destroy();
|
session.destroy(false);
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
const url = hash.slice(1);
|
const url = hash.slice(1);
|
||||||
Router.push({ path: url });
|
Router.push(`/login?redirect=${url}`);
|
||||||
} else if (!session.isLoggedIn()) {
|
} else if (!session.isLoggedIn()) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,22 +46,6 @@ const onDataSaved = async (formData, requestResponse) => {
|
||||||
@on-fetch="(data) => (taxAreasOptions = data)"
|
@on-fetch="(data) => (taxAreasOptions = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData
|
|
||||||
url="Tickets"
|
|
||||||
:filter="{
|
|
||||||
fields: ['id', 'nickname'],
|
|
||||||
where: { refFk: null },
|
|
||||||
order: 'shipped DESC',
|
|
||||||
}"
|
|
||||||
@on-fetch="(data) => (ticketsOptions = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
url="Clients"
|
|
||||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
|
||||||
@on-fetch="(data) => (clientsOptions = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FormModelPopup
|
<FormModelPopup
|
||||||
ref="formModelPopupRef"
|
ref="formModelPopupRef"
|
||||||
:title="t('Create manual invoice')"
|
:title="t('Create manual invoice')"
|
||||||
|
@ -84,6 +68,10 @@ const onDataSaved = async (formData, requestResponse) => {
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="data.ticketFk"
|
v-model="data.ticketFk"
|
||||||
@update:model-value="data.clientFk = null"
|
@update:model-value="data.clientFk = null"
|
||||||
|
url="Tickets"
|
||||||
|
:where="{ refFk: null }"
|
||||||
|
:fields="['id', 'nickname']"
|
||||||
|
:filter-options="{ order: 'shipped DESC' }"
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
|
@ -105,6 +93,9 @@ const onDataSaved = async (formData, requestResponse) => {
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="data.clientFk"
|
v-model="data.clientFk"
|
||||||
@update:model-value="data.ticketFk = null"
|
@update:model-value="data.ticketFk = null"
|
||||||
|
url="Clients"
|
||||||
|
:fields="['id', 'name']"
|
||||||
|
:filter-options="{ order: 'name ASC' }"
|
||||||
/>
|
/>
|
||||||
<VnInputDate :label="t('Max date')" v-model="data.maxShipped" />
|
<VnInputDate :label="t('Max date')" v-model="data.maxShipped" />
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
@ -116,7 +107,6 @@ const onDataSaved = async (formData, requestResponse) => {
|
||||||
option-label="description"
|
option-label="description"
|
||||||
option-value="code"
|
option-value="code"
|
||||||
v-model="data.serial"
|
v-model="data.serial"
|
||||||
:required="true"
|
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Area')"
|
:label="t('Area')"
|
||||||
|
@ -125,7 +115,6 @@ const onDataSaved = async (formData, requestResponse) => {
|
||||||
option-label="code"
|
option-label="code"
|
||||||
option-value="code"
|
option-value="code"
|
||||||
v-model="data.taxArea"
|
v-model="data.taxArea"
|
||||||
:required="true"
|
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
|
|
@ -10,7 +10,6 @@ import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||||
import SkeletonTable from 'components/ui/SkeletonTable.vue';
|
import SkeletonTable from 'components/ui/SkeletonTable.vue';
|
||||||
import { tMobile } from 'src/composables/tMobile';
|
import { tMobile } from 'src/composables/tMobile';
|
||||||
import VnSubToolbar from './ui/VnSubToolbar.vue';
|
|
||||||
|
|
||||||
const { push } = useRouter();
|
const { push } = useRouter();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
|
|
@ -8,7 +8,7 @@ import VnRow from 'components/ui/VnRow.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
import FormPopup from './FormPopup.vue';
|
import FormPopup from './FormPopup.vue';
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import useNotify from 'src/composables/useNotify.js';
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ const $props = defineProps({
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const { dialogRef } = useDialogPluginComponent();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -116,90 +116,92 @@ const makeInvoice = async () => {
|
||||||
@on-fetch="(data) => (invoiceCorrectionTypesOptions = data)"
|
@on-fetch="(data) => (invoiceCorrectionTypesOptions = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FormPopup
|
<QDialog ref="dialogRef">
|
||||||
|
<FormPopup
|
||||||
@on-submit="makeInvoice()"
|
@on-submit="makeInvoice()"
|
||||||
:title="t('Transfer invoice')"
|
:title="t('Transfer invoice')"
|
||||||
:custom-submit-button-label="t('Transfer client')"
|
:custom-submit-button-label="t('Transfer client')"
|
||||||
:default-cancel-button="false"
|
:default-cancel-button="false"
|
||||||
>
|
>
|
||||||
<template #form-inputs>
|
<template #form-inputs>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Client')"
|
:label="t('Client')"
|
||||||
:options="clientsOptions"
|
:options="clientsOptions"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="transferInvoiceParams.newClientFk"
|
v-model="transferInvoiceParams.newClientFk"
|
||||||
:required="true"
|
:required="true"
|
||||||
url="Clients"
|
url="Clients"
|
||||||
:fields="['id', 'name', 'hasToInvoiceByAddress']"
|
:fields="['id', 'name', 'hasToInvoiceByAddress']"
|
||||||
auto-load
|
auto-load
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem
|
<QItem
|
||||||
v-bind="scope.itemProps"
|
v-bind="scope.itemProps"
|
||||||
@click="selectedClient(scope.opt)"
|
@click="selectedClient(scope.opt)"
|
||||||
>
|
>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QItemLabel>
|
<QItemLabel>
|
||||||
#{{ scope.opt?.id }} - {{ scope.opt?.name }}
|
#{{ scope.opt?.id }} - {{ scope.opt?.name }}
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
</VnSelect>
|
</VnSelect>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Rectificative type')"
|
:label="t('Rectificative type')"
|
||||||
:options="rectificativeTypeOptions"
|
:options="rectificativeTypeOptions"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="description"
|
option-label="description"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="transferInvoiceParams.cplusRectificationTypeFk"
|
v-model="transferInvoiceParams.cplusRectificationTypeFk"
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Class')"
|
:label="t('Class')"
|
||||||
:options="siiTypeInvoiceOutsOptions"
|
:options="siiTypeInvoiceOutsOptions"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="description"
|
option-label="description"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="transferInvoiceParams.siiTypeInvoiceOutFk"
|
v-model="transferInvoiceParams.siiTypeInvoiceOutFk"
|
||||||
:required="true"
|
:required="true"
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QItemLabel>
|
<QItemLabel>
|
||||||
{{ scope.opt?.code }} -
|
{{ scope.opt?.code }} -
|
||||||
{{ scope.opt?.description }}
|
{{ scope.opt?.description }}
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
</VnSelect>
|
</VnSelect>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Type')"
|
:label="t('Type')"
|
||||||
:options="invoiceCorrectionTypesOptions"
|
:options="invoiceCorrectionTypesOptions"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="description"
|
option-label="description"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="transferInvoiceParams.invoiceCorrectionTypeFk"
|
v-model="transferInvoiceParams.invoiceCorrectionTypeFk"
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div>
|
<div>
|
||||||
<QCheckbox :label="t('Bill destination client')" v-model="checked" />
|
<QCheckbox :label="t('Bill destination client')" v-model="checked" />
|
||||||
<QIcon name="info" class="cursor-info q-ml-sm" size="sm">
|
<QIcon name="info" class="cursor-info q-ml-sm" size="sm">
|
||||||
<QTooltip>{{ t('transferInvoiceInfo') }}</QTooltip>
|
<QTooltip>{{ t('transferInvoiceInfo') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
</FormPopup>
|
</FormPopup>
|
||||||
|
</QDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -67,6 +67,10 @@ const $props = defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({ card: false, table: false }),
|
default: () => ({ card: false, table: false }),
|
||||||
},
|
},
|
||||||
|
table: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
|
@ -249,7 +253,7 @@ defineExpose({
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ rows }">
|
<template #body="{ rows }">
|
||||||
<QTable
|
<QTable
|
||||||
v-bind="$attrs['q-table']"
|
v-bind="table"
|
||||||
class="vnTable"
|
class="vnTable"
|
||||||
:columns="splittedColumns.columns"
|
:columns="splittedColumns.columns"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
|
|
|
@ -52,7 +52,7 @@ const toggleMarkAll = (val) => {
|
||||||
|
|
||||||
const getConfig = async (url, filter) => {
|
const getConfig = async (url, filter) => {
|
||||||
const response = await axios.get(url, {
|
const response = await axios.get(url, {
|
||||||
params: { filter: filter },
|
params: { filter: JSON.stringify(filter) },
|
||||||
});
|
});
|
||||||
return response.data && response.data.length > 0 ? response.data[0] : null;
|
return response.data && response.data.length > 0 ? response.data[0] : null;
|
||||||
};
|
};
|
||||||
|
@ -60,7 +60,7 @@ const getConfig = async (url, filter) => {
|
||||||
const fetchViewConfigData = async () => {
|
const fetchViewConfigData = async () => {
|
||||||
try {
|
try {
|
||||||
const userConfigFilter = {
|
const userConfigFilter = {
|
||||||
where: { tableCode: $props.tableCode, userFk: user.id },
|
where: { tableCode: $props.tableCode, userFk: user.value.id },
|
||||||
};
|
};
|
||||||
const userConfig = await getConfig('UserConfigViews', userConfigFilter);
|
const userConfig = await getConfig('UserConfigViews', userConfigFilter);
|
||||||
|
|
||||||
|
@ -74,8 +74,14 @@ const fetchViewConfigData = async () => {
|
||||||
const defaultConfig = await getConfig('DefaultViewConfigs', defaultConfigFilter);
|
const defaultConfig = await getConfig('DefaultViewConfigs', defaultConfigFilter);
|
||||||
|
|
||||||
if (defaultConfig) {
|
if (defaultConfig) {
|
||||||
|
// Si el backend devuelve una configuración por defecto la usamos
|
||||||
setUserConfigViewData(defaultConfig.columns);
|
setUserConfigViewData(defaultConfig.columns);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
// Si no hay configuración por defecto mostramos todas las columnas
|
||||||
|
const defaultColumns = {};
|
||||||
|
$props.allColumns.forEach((col) => (defaultColumns[col] = true));
|
||||||
|
setUserConfigViewData(defaultColumns);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.err('Error fetching config view data', err);
|
console.err('Error fetching config view data', err);
|
||||||
|
|
|
@ -165,9 +165,9 @@ const toModule = computed(() =>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('components.cardDescriptor.moreOptions') }}
|
{{ t('components.cardDescriptor.moreOptions') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
<QMenu>
|
<QMenu ref="menuRef">
|
||||||
<QList>
|
<QList>
|
||||||
<slot name="menu" :entity="entity" />
|
<slot name="menu" :entity="entity" :menu-ref="menuRef" />
|
||||||
</QList>
|
</QList>
|
||||||
</QMenu>
|
</QMenu>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import VnImg from 'src/components/ui/VnImg.vue';
|
||||||
import OrderCatalogItemDialog from 'pages/Order/Card/OrderCatalogItemDialog.vue';
|
import OrderCatalogItemDialog from 'pages/Order/Card/OrderCatalogItemDialog.vue';
|
||||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
|
|
||||||
import toCurrency from '../../../filters/toCurrency';
|
import { toCurrency } from 'filters/index';
|
||||||
|
|
||||||
const DEFAULT_PRICE_KG = 0;
|
const DEFAULT_PRICE_KG = 0;
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@ defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
isCatalog: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const dialog = ref(null);
|
const dialog = ref(null);
|
||||||
|
@ -28,7 +32,7 @@ const dialog = ref(null);
|
||||||
<QCard class="card shadow-6">
|
<QCard class="card shadow-6">
|
||||||
<div class="img-wrapper">
|
<div class="img-wrapper">
|
||||||
<VnImg :id="item.id" zoom-size="lg" class="image" />
|
<VnImg :id="item.id" zoom-size="lg" class="image" />
|
||||||
<div v-if="item.hex" class="item-color-container">
|
<div v-if="item.hex && isCatalog" class="item-color-container">
|
||||||
<div
|
<div
|
||||||
class="item-color"
|
class="item-color"
|
||||||
:style="{ backgroundColor: `#${item.hex}` }"
|
:style="{ backgroundColor: `#${item.hex}` }"
|
||||||
|
@ -50,11 +54,12 @@ const dialog = ref(null);
|
||||||
</template>
|
</template>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="price">
|
<div class="price">
|
||||||
<p>
|
<p v-if="isCatalog">
|
||||||
{{ item.available }} {{ t('to') }}
|
{{ item.available }} {{ t('to') }}
|
||||||
{{ toCurrency(item.price) }}
|
{{ toCurrency(item.price) }}
|
||||||
</p>
|
</p>
|
||||||
<QIcon name="add_circle" class="icon">
|
<slot name="price" />
|
||||||
|
<QIcon v-if="isCatalog" name="add_circle" class="icon">
|
||||||
<QTooltip>{{ t('globals.add') }}</QTooltip>
|
<QTooltip>{{ t('globals.add') }}</QTooltip>
|
||||||
<QPopupProxy ref="dialog">
|
<QPopupProxy ref="dialog">
|
||||||
<OrderCatalogItemDialog
|
<OrderCatalogItemDialog
|
|
@ -58,6 +58,7 @@ const $props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defineExpose({ search });
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'update:modelValue',
|
'update:modelValue',
|
||||||
'refresh',
|
'refresh',
|
||||||
|
@ -192,6 +193,14 @@ function formatValue(value) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<QBtn
|
||||||
|
class="q-mt-lg q-mr-xs q-mb-lg"
|
||||||
|
round
|
||||||
|
color="primary"
|
||||||
|
style="position: fixed; z-index: 1; right: 0; bottom: 0"
|
||||||
|
icon="search"
|
||||||
|
@click="search()"
|
||||||
|
></QBtn>
|
||||||
<QForm @submit="search" id="filterPanelForm">
|
<QForm @submit="search" id="filterPanelForm">
|
||||||
<QList dense>
|
<QList dense>
|
||||||
<QItem class="q-mt-xs">
|
<QItem class="q-mt-xs">
|
||||||
|
@ -265,23 +274,6 @@ function formatValue(value) {
|
||||||
<QList dense class="list q-gutter-y-sm q-mt-sm">
|
<QList dense class="list q-gutter-y-sm q-mt-sm">
|
||||||
<slot name="body" :params="userParams" :search-fn="search"></slot>
|
<slot name="body" :params="userParams" :search-fn="search"></slot>
|
||||||
</QList>
|
</QList>
|
||||||
<template v-if="$props.searchButton">
|
|
||||||
<QItem>
|
|
||||||
<QItemSection class="q-py-sm">
|
|
||||||
<QBtn
|
|
||||||
:label="t('Search')"
|
|
||||||
class="full-width"
|
|
||||||
color="primary"
|
|
||||||
dense
|
|
||||||
icon="search"
|
|
||||||
rounded
|
|
||||||
:type="disableSubmitEvent ? 'button' : 'submit'"
|
|
||||||
unelevated
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QSeparator />
|
|
||||||
</template>
|
|
||||||
</QForm>
|
</QForm>
|
||||||
<QInnerLoading
|
<QInnerLoading
|
||||||
:label="t('globals.pleaseWait')"
|
:label="t('globals.pleaseWait')"
|
||||||
|
|
|
@ -28,7 +28,7 @@ const $props = defineProps({
|
||||||
const show = ref(false);
|
const show = ref(false);
|
||||||
const token = useSession().getTokenMultimedia();
|
const token = useSession().getTokenMultimedia();
|
||||||
const timeStamp = ref(`timestamp=${Date.now()}`);
|
const timeStamp = ref(`timestamp=${Date.now()}`);
|
||||||
import noImage from '/public/no-user.png';
|
import noImage from '/no-user.png';
|
||||||
import { useRole } from 'src/composables/useRole';
|
import { useRole } from 'src/composables/useRole';
|
||||||
const url = computed(() => {
|
const url = computed(() => {
|
||||||
const isEmployee = useRole().isEmployee();
|
const isEmployee = useRole().isEmployee();
|
||||||
|
|
|
@ -58,31 +58,37 @@ export function useSession() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function destroy() {
|
async function destroy(destroyTokens = true) {
|
||||||
const tokens = {
|
const tokens = {
|
||||||
tokenMultimedia: 'Accounts/logout',
|
tokenMultimedia: 'Accounts/logout',
|
||||||
token: 'VnUsers/logout',
|
token: 'VnUsers/logout',
|
||||||
};
|
};
|
||||||
const storage = keepLogin() ? localStorage : sessionStorage;
|
const storage = keepLogin() ? localStorage : sessionStorage;
|
||||||
|
let destroyTokenPromises = [];
|
||||||
|
try {
|
||||||
|
if (destroyTokens) {
|
||||||
|
const { data: isValidToken } = await axios.get('VnUsers/validateToken');
|
||||||
|
if (isValidToken)
|
||||||
|
destroyTokenPromises = Object.entries(tokens).map(([key, url]) =>
|
||||||
|
destroyToken(url, storage, key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
localStorage.clear();
|
||||||
|
sessionStorage.clear();
|
||||||
|
await Promise.allSettled(destroyTokenPromises);
|
||||||
|
const { setUser } = useState();
|
||||||
|
|
||||||
for (const [key, url] of Object.entries(tokens)) {
|
setUser({
|
||||||
await destroyToken(url, storage, key);
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
nickname: '',
|
||||||
|
lang: '',
|
||||||
|
darkMode: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
stopRenewer();
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.clear();
|
|
||||||
sessionStorage.clear();
|
|
||||||
|
|
||||||
const { setUser } = useState();
|
|
||||||
|
|
||||||
setUser({
|
|
||||||
id: 0,
|
|
||||||
name: '',
|
|
||||||
nickname: '',
|
|
||||||
lang: '',
|
|
||||||
darkMode: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
stopRenewer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function login(data) {
|
async function login(data) {
|
||||||
|
|
|
@ -550,10 +550,14 @@ ticket:
|
||||||
observation: Notes
|
observation: Notes
|
||||||
ticketAdvance: Advance tickets
|
ticketAdvance: Advance tickets
|
||||||
futureTickets: Future tickets
|
futureTickets: Future tickets
|
||||||
|
expedition: Expedition
|
||||||
purchaseRequest: Purchase request
|
purchaseRequest: Purchase request
|
||||||
weeklyTickets: Weekly tickets
|
weeklyTickets: Weekly tickets
|
||||||
services: Service
|
services: Service
|
||||||
tracking: Tracking
|
tracking: Tracking
|
||||||
|
components: Components
|
||||||
|
pictures: Pictures
|
||||||
|
packages: Packages
|
||||||
list:
|
list:
|
||||||
nickname: Nickname
|
nickname: Nickname
|
||||||
state: State
|
state: State
|
||||||
|
|
|
@ -239,6 +239,13 @@ globals:
|
||||||
mailForwarding: Reenvío de correo
|
mailForwarding: Reenvío de correo
|
||||||
mailAlias: Alias de correo
|
mailAlias: Alias de correo
|
||||||
privileges: Privilegios
|
privileges: Privilegios
|
||||||
|
observation: Notas
|
||||||
|
expedition: Expedición
|
||||||
|
services: Servicios
|
||||||
|
tracking: Estados
|
||||||
|
components: Componentes
|
||||||
|
pictures: Fotos
|
||||||
|
packages: Bultos
|
||||||
created: Fecha creación
|
created: Fecha creación
|
||||||
worker: Trabajador
|
worker: Trabajador
|
||||||
now: Ahora
|
now: Ahora
|
||||||
|
@ -548,10 +555,14 @@ ticket:
|
||||||
observation: Notas
|
observation: Notas
|
||||||
ticketAdvance: Adelantar tickets
|
ticketAdvance: Adelantar tickets
|
||||||
futureTickets: Tickets a futuro
|
futureTickets: Tickets a futuro
|
||||||
|
expedition: Expedición
|
||||||
purchaseRequest: Petición de compra
|
purchaseRequest: Petición de compra
|
||||||
weeklyTickets: Tickets programados
|
weeklyTickets: Tickets programados
|
||||||
services: Servicios
|
services: Servicios
|
||||||
tracking: Estados
|
tracking: Estados
|
||||||
|
components: Componentes
|
||||||
|
pictures: Fotos
|
||||||
|
packages: Bultos
|
||||||
list:
|
list:
|
||||||
nickname: Alias
|
nickname: Alias
|
||||||
state: Estado
|
state: Estado
|
||||||
|
|
|
@ -408,7 +408,6 @@ function handleLocation(data, location) {
|
||||||
default-mode="table"
|
default-mode="table"
|
||||||
redirect="customer"
|
redirect="customer"
|
||||||
auto-load
|
auto-load
|
||||||
:disable-option="{ card: true }"
|
|
||||||
>
|
>
|
||||||
<template #more-create-dialog="{ data }">
|
<template #more-create-dialog="{ data }">
|
||||||
<VnLocation
|
<VnLocation
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, computed, onUpdated } from 'vue';
|
import { onMounted, ref, computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, computed, reactive, onUnmounted } from 'vue';
|
import { onMounted, onUnmounted } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, computed } from 'vue';
|
import { onMounted, ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import EntryFilter from './EntryFilter.vue';
|
import EntryFilter from './EntryFilter.vue';
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
@ -12,8 +10,6 @@ import { toDate } from 'src/filters';
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
|
||||||
const entityId = computed(() => route.params.id);
|
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
|
|
||||||
const entryFilter = {
|
const entryFilter = {
|
||||||
|
|
|
@ -63,8 +63,8 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
|
||||||
@on-fetch="setData"
|
@on-fetch="setData"
|
||||||
data-key="invoiceOutData"
|
data-key="invoiceOutData"
|
||||||
>
|
>
|
||||||
<template #menu="{ entity }">
|
<template #menu="{ entity, menuRef }">
|
||||||
<InvoiceOutDescriptorMenu :invoice-out-data="entity" />
|
<InvoiceOutDescriptorMenu :invoice-out-data="entity" :menu-ref="menuRef" />
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<VnLv :label="t('invoiceOut.card.issued')" :value="toDate(entity.issued)" />
|
<VnLv :label="t('invoiceOut.card.issued')" :value="toDate(entity.issued)" />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref, onBeforeMount } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
@ -11,13 +11,20 @@ import useNotify from 'src/composables/useNotify';
|
||||||
import { useSession } from 'src/composables/useSession';
|
import { useSession } from 'src/composables/useSession';
|
||||||
import { usePrintService } from 'composables/usePrintService';
|
import { usePrintService } from 'composables/usePrintService';
|
||||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
import { getUrl } from 'src/composables/getUrl';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
|
onBeforeMount(async () => (salixUrl.value = await getUrl('')));
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
invoiceOutData: {
|
invoiceOutData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
|
menuRef: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { notify } = useNotify();
|
const { notify } = useNotify();
|
||||||
|
@ -28,8 +35,7 @@ const { t } = useI18n();
|
||||||
const { openReport, sendEmail } = usePrintService();
|
const { openReport, sendEmail } = usePrintService();
|
||||||
const { openConfirmationModal } = useVnConfirm();
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
const salixUrl = ref();
|
||||||
const transferInvoiceDialogRef = ref();
|
|
||||||
const invoiceFormType = ref('pdf');
|
const invoiceFormType = ref('pdf');
|
||||||
const defaultEmailAddress = ref($props.invoiceOutData.client?.email);
|
const defaultEmailAddress = ref($props.invoiceOutData.client?.email);
|
||||||
|
|
||||||
|
@ -115,6 +121,7 @@ const refundInvoice = async (withWarehouse) => {
|
||||||
try {
|
try {
|
||||||
const params = { ref: $props.invoiceOutData.ref, withWarehouse: withWarehouse };
|
const params = { ref: $props.invoiceOutData.ref, withWarehouse: withWarehouse };
|
||||||
const { data } = await axios.post('InvoiceOuts/refund', params);
|
const { data } = await axios.post('InvoiceOuts/refund', params);
|
||||||
|
location.href = window.origin + `/#/ticket/${data[0].id}/sale`;
|
||||||
notify(
|
notify(
|
||||||
t('refundInvoiceSuccessMessage', {
|
t('refundInvoiceSuccessMessage', {
|
||||||
refundTicket: data[0].id,
|
refundTicket: data[0].id,
|
||||||
|
@ -125,11 +132,22 @@ const refundInvoice = async (withWarehouse) => {
|
||||||
console.error('Error generating invoice out pdf', err);
|
console.error('Error generating invoice out pdf', err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showTransferInvoiceForm = async () => {
|
||||||
|
quasar.dialog({
|
||||||
|
component: TransferInvoiceForm,
|
||||||
|
componentProps: {
|
||||||
|
invoiceOutData: $props.invoiceOutData,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QItem v-ripple clickable @click="transferInvoiceDialogRef.show()">
|
<QItem v-ripple clickable>
|
||||||
<QItemSection>{{ t('Transfer invoice to...') }}</QItemSection>
|
<QItemSection @click="showTransferInvoiceForm()">{{
|
||||||
|
t('Transfer invoice to...')
|
||||||
|
}}</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem v-ripple clickable>
|
<QItem v-ripple clickable>
|
||||||
<QItemSection>{{ t('Show invoice...') }}</QItemSection>
|
<QItemSection>{{ t('Show invoice...') }}</QItemSection>
|
||||||
|
@ -222,10 +240,6 @@ const refundInvoice = async (withWarehouse) => {
|
||||||
{{ t('Create a single ticket with all the content of the current invoice') }}
|
{{ t('Create a single ticket with all the content of the current invoice') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
||||||
<QDialog ref="transferInvoiceDialogRef">
|
|
||||||
<TransferInvoiceForm :invoice-out-data="invoiceOutData" />
|
|
||||||
</QDialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { onMounted, ref, computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { toCurrency, toDate } from 'src/filters';
|
import { toCurrency, toDate, toPercentage } from 'src/filters';
|
||||||
import CardSummary from 'components/ui/CardSummary.vue';
|
import CardSummary from 'components/ui/CardSummary.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import { getUrl } from 'src/composables/getUrl';
|
import { getUrl } from 'src/composables/getUrl';
|
||||||
|
@ -57,12 +57,14 @@ const taxColumns = ref([
|
||||||
name: 'quantity',
|
name: 'quantity',
|
||||||
label: 'invoiceOut.summary.rate',
|
label: 'invoiceOut.summary.rate',
|
||||||
field: (row) => row.rate,
|
field: (row) => row.rate,
|
||||||
|
format: (value) => toPercentage(value / 100),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'invoiceOuted',
|
name: 'invoiceOuted',
|
||||||
label: 'invoiceOut.summary.fee',
|
label: 'invoiceOut.summary.fee',
|
||||||
field: (row) => row.vat,
|
field: (row) => row.vat,
|
||||||
|
format: (value) => toCurrency(value),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -113,7 +115,7 @@ const ticketsColumns = ref([
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ entity: { invoiceOut } }">
|
<template #body="{ entity: { invoiceOut } }">
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<VnTitle :text="t('invoiceOut.pageTitles.basicData')" />
|
<VnTitle :text="t('globals.pageTitles.basicData')" />
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('invoiceOut.summary.issued')"
|
:label="t('invoiceOut.summary.issued')"
|
||||||
:value="toDate(invoiceOut.issued)"
|
:value="toDate(invoiceOut.issued)"
|
||||||
|
@ -164,7 +166,7 @@ const ticketsColumns = ref([
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell-item="{ value }">
|
<template #body-cell-item="{ value }">
|
||||||
<QTd>
|
<QTd>
|
||||||
<QBtn flat color="primary">
|
<QBtn flat class="link">
|
||||||
{{ value }}
|
{{ value }}
|
||||||
<TicketDescriptorProxy :id="value" />
|
<TicketDescriptorProxy :id="value" />
|
||||||
</QBtn>
|
</QBtn>
|
||||||
|
@ -172,7 +174,7 @@ const ticketsColumns = ref([
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell-quantity="{ value, row }">
|
<template #body-cell-quantity="{ value, row }">
|
||||||
<QTd>
|
<QTd>
|
||||||
<QBtn class="no-uppercase" flat color="primary" dense>
|
<QBtn class="no-uppercase link" flat dense>
|
||||||
{{ value }}
|
{{ value }}
|
||||||
<CustomerDescriptorProxy :id="row.id" />
|
<CustomerDescriptorProxy :id="row.id" />
|
||||||
</QBtn>
|
</QBtn>
|
||||||
|
|
|
@ -41,7 +41,7 @@ function setWorkers(data) {
|
||||||
<span>{{ formatFn(tag.value) }}</span>
|
<span>{{ formatFn(tag.value) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ params, searchFn }">
|
<template #body="{ params }">
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<VnInput
|
<VnInput
|
||||||
|
@ -93,7 +93,6 @@ function setWorkers(data) {
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
:label="t('Has PDF')"
|
:label="t('Has PDF')"
|
||||||
@update:model-value="searchFn()"
|
|
||||||
toggle-indeterminate
|
toggle-indeterminate
|
||||||
v-model="params.hasPdf"
|
v-model="params.hasPdf"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -30,7 +30,7 @@ const selectedCustomerId = ref(null);
|
||||||
const tableColumnComponents = {
|
const tableColumnComponents = {
|
||||||
clientId: {
|
clientId: {
|
||||||
component: QBtn,
|
component: QBtn,
|
||||||
props: { flat: true, color: 'blue' },
|
props: { flat: true, class: 'link' },
|
||||||
event: (prop) => selectCustomerId(prop.value),
|
event: (prop) => selectCustomerId(prop.value),
|
||||||
},
|
},
|
||||||
clientName: {
|
clientName: {
|
||||||
|
@ -52,7 +52,12 @@ const tableColumnComponents = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{ label: 'Id', field: 'clientId', name: 'clientId', align: 'left' },
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'clientId',
|
||||||
|
label: 'Id',
|
||||||
|
field: 'clientId',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.globalInvoices.table.client'),
|
label: t('invoiceOut.globalInvoices.table.client'),
|
||||||
field: 'clientName',
|
field: 'clientName',
|
||||||
|
|
|
@ -48,7 +48,7 @@ const getStatus = computed({
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await invoiceOutGlobalStore.init();
|
await invoiceOutGlobalStore.init();
|
||||||
formData.value = { ...formInitialData.value };
|
formData.value = formInitialData.value.invoiceDate;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,96 +1,177 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onUnmounted, ref } from 'vue';
|
import { onMounted, onUnmounted, ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
|
||||||
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
|
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
|
||||||
import CardList from 'src/components/ui/CardList.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
|
|
||||||
import CreateManualInvoiceForm from 'src/components/CreateManualInvoiceForm.vue';
|
|
||||||
|
|
||||||
import InvoiceOutFilter from './InvoiceOutFilter.vue';
|
|
||||||
import { toDate, toCurrency } from 'src/filters/index';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import { useSession } from 'src/composables/useSession';
|
import { usePrintService } from 'composables/usePrintService';
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
|
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
|
||||||
|
import { toCurrency, toDate } from 'src/filters/index';
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { QBtn } from 'quasar';
|
||||||
|
import { watchEffect } from 'vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const router = useRouter();
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const session = useSession();
|
|
||||||
const tokenMultimedia = session.getTokenMultimedia();
|
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
|
const tableRef = ref();
|
||||||
|
const invoiceOutSerialsOptions = ref([]);
|
||||||
|
const ticketsOptions = ref([]);
|
||||||
|
const customerOptions = ref([]);
|
||||||
|
const selectedRows = ref([]);
|
||||||
|
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
|
||||||
|
const MODEL = 'InvoiceOuts';
|
||||||
|
const { openReport } = usePrintService();
|
||||||
|
|
||||||
const manualInvoiceDialogRef = ref(null);
|
const columns = computed(() => [
|
||||||
const selectedCards = ref(new Map());
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'id',
|
||||||
|
label: t('invoiceOutList.tableVisibleColumns.id'),
|
||||||
|
chip: {
|
||||||
|
condition: () => true,
|
||||||
|
},
|
||||||
|
isId: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'ref',
|
||||||
|
label: t('invoiceOutList.tableVisibleColumns.ref'),
|
||||||
|
isTitle: true,
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: MODEL,
|
||||||
|
optionLabel: 'ref',
|
||||||
|
optionValue: 'id',
|
||||||
|
},
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'Issued',
|
||||||
|
label: t('invoiceOutList.tableVisibleColumns.issued'),
|
||||||
|
component: 'date',
|
||||||
|
format: (row) => toDate(row.issued),
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'clientSocialName',
|
||||||
|
label: t('invoiceOutModule.customer'),
|
||||||
|
cardVisible: true,
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Clients',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
},
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'companyCode',
|
||||||
|
label: t('invoiceOutModule.company'),
|
||||||
|
cardVisible: true,
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Companies',
|
||||||
|
optionLabel: 'code',
|
||||||
|
optionValue: 'id',
|
||||||
|
},
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'amount',
|
||||||
|
label: t('invoiceOutModule.amount'),
|
||||||
|
cardVisible: true,
|
||||||
|
format: (row) => toCurrency(row.amount),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'created',
|
||||||
|
label: t('invoiceOutList.tableVisibleColumns.created'),
|
||||||
|
component: 'date',
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
format: (row) => toDate(row.created),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'dued',
|
||||||
|
label: t('invoiceOutList.tableVisibleColumns.dueDate'),
|
||||||
|
component: 'date',
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
format: (row) => toDate(row.dued),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
name: 'tableActions',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
title: t('InvoiceOutSummary'),
|
||||||
|
icon: 'preview',
|
||||||
|
action: (row) => viewSummary(row.id, InvoiceOutSummary),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('DownloadPdf'),
|
||||||
|
icon: 'vn:ticket',
|
||||||
|
isPrimary: true,
|
||||||
|
action: (row) => openPdf(row.id),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
onMounted(() => (stateStore.rightDrawer = true));
|
onMounted(() => (stateStore.rightDrawer = true));
|
||||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
|
||||||
function navigate(id) {
|
function openPdf(id) {
|
||||||
router.push({ path: `/invoice-out/${id}` });
|
try {
|
||||||
|
openReport(`${MODEL}/${id}/download`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error opening PDF', err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleIndividualCard = (cardData) => {
|
function downloadPdf() {
|
||||||
if (selectedCards.value.has(cardData.id)) {
|
|
||||||
selectedCards.value.delete(cardData.id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedCards.value.set(cardData.id, cardData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleAllCards = (cardsData) => {
|
|
||||||
const allSelected = selectedCards.value.size === cardsData.length;
|
|
||||||
|
|
||||||
if (!allSelected) {
|
|
||||||
// Si no todas las tarjetas están seleccionadas, selecciónalas todas
|
|
||||||
cardsData.forEach((data) => {
|
|
||||||
if (!selectedCards.value.has(data.id)) {
|
|
||||||
selectedCards.value.set(data.id, data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Si todas las tarjetas están seleccionadas, deselecciónalas todas
|
|
||||||
selectedCards.value.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const openPdf = () => {
|
|
||||||
try {
|
try {
|
||||||
if (selectedCards.value.size === 0) return;
|
if (selectedRows.value.size === 0) return;
|
||||||
const selectedCardsArray = Array.from(selectedCards.value.values());
|
const selectedCardsArray = Array.from(selectedRows.value.values());
|
||||||
|
|
||||||
if (selectedCards.value.size === 1) {
|
if (selectedRows.value.size === 1) {
|
||||||
const [invoiceOut] = selectedCardsArray;
|
const [invoiceOut] = selectedCardsArray;
|
||||||
const url = `api/InvoiceOuts/${invoiceOut.id}/download?access_token=${tokenMultimedia}`;
|
openPdf(invoiceOut.id);
|
||||||
window.open(url, '_blank');
|
|
||||||
} else {
|
} else {
|
||||||
const invoiceOutIdsArray = selectedCardsArray.map(
|
const invoiceOutIdsArray = selectedCardsArray.map(
|
||||||
(invoiceOut) => invoiceOut.id
|
(invoiceOut) => invoiceOut.id
|
||||||
);
|
);
|
||||||
const invoiceOutIds = invoiceOutIdsArray.join(',');
|
const invoiceOutIds = invoiceOutIdsArray.join(',');
|
||||||
|
|
||||||
const params = new URLSearchParams({
|
const params = {
|
||||||
access_token: tokenMultimedia,
|
|
||||||
ids: invoiceOutIds,
|
ids: invoiceOutIds,
|
||||||
});
|
};
|
||||||
|
|
||||||
const url = `api/InvoiceOuts/downloadZip?${params}`;
|
openReport(`${MODEL}/downloadZip`, params);
|
||||||
window.open(url, '_blank');
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error opening PDF');
|
console.error('Error opening PDF');
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const openCreateInvoiceModal = () => {
|
watchEffect(selectedRows);
|
||||||
manualInvoiceDialogRef.value.show();
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -99,115 +180,84 @@ const openCreateInvoiceModal = () => {
|
||||||
:label="t('searchInvoice')"
|
:label="t('searchInvoice')"
|
||||||
data-key="InvoiceOutList"
|
data-key="InvoiceOutList"
|
||||||
/>
|
/>
|
||||||
<RightMenu>
|
<VnSubToolbar>
|
||||||
<template #right-panel>
|
<template #st-actions>
|
||||||
<InvoiceOutFilter data-key="InvoiceOutList" />
|
<QBtn
|
||||||
|
color="primary"
|
||||||
|
icon-right="cloud_download"
|
||||||
|
@click="downloadPdf()"
|
||||||
|
:disable="!hasSelectedCards"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('globals.downloadPdf') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
</template>
|
</template>
|
||||||
</RightMenu>
|
</VnSubToolbar>
|
||||||
<QPage>
|
<VnTable
|
||||||
<VnPaginate
|
ref="tableRef"
|
||||||
auto-load
|
data-key="invoiceOut"
|
||||||
data-key="InvoiceOutList"
|
:url="`${MODEL}/filter`"
|
||||||
:order="['issued DESC', 'id DESC']"
|
:create="{
|
||||||
url="InvoiceOuts/filter"
|
urlCreate: 'InvoiceOuts/createManualInvoice',
|
||||||
>
|
title: t('Create Manual Invoice'),
|
||||||
<template #body="{ rows }">
|
onDataSaved: ({ id }) => tableRef.redirect(id),
|
||||||
<VnSubToolbar class="justify-end">
|
formInitialData: {
|
||||||
<template #st-actions>
|
active: true,
|
||||||
<QBtn
|
},
|
||||||
@click="openPdf()"
|
}"
|
||||||
class="q-mr-md"
|
v-model:selected="selectedRows"
|
||||||
color="primary"
|
order="id DESC"
|
||||||
icon="cloud_download"
|
:columns="columns"
|
||||||
:disable="selectedCards.size === 0"
|
default-mode="table"
|
||||||
>
|
redirect="invoice-out"
|
||||||
<QTooltip>{{ t('globals.downloadPdf') }}</QTooltip>
|
auto-load
|
||||||
</QBtn>
|
:table="{
|
||||||
<QCheckbox
|
'row-key': 'id',
|
||||||
left-label
|
selection: 'multiple',
|
||||||
:label="t('globals.markAll')"
|
}"
|
||||||
@click="toggleAllCards(rows)"
|
>
|
||||||
:model-value="selectedCards.size === rows.length"
|
<template #more-create-dialog="{ data }">
|
||||||
class="q-mr-md"
|
<VnSelect
|
||||||
/>
|
url="Tickets"
|
||||||
</template>
|
v-model="data.ticketFk"
|
||||||
</VnSubToolbar>
|
:label="t('invoiceOutList.tableVisibleColumns.ticket')"
|
||||||
<div class="flex flex-center q-pa-md">
|
:options="ticketsOptions"
|
||||||
<div class="vn-card-list">
|
option-label="nickname"
|
||||||
<CardList
|
option-value="id"
|
||||||
:element="row"
|
/>
|
||||||
:id="row.id"
|
<VnSelect
|
||||||
:show-checkbox="true"
|
url="Clients"
|
||||||
:is-selected="selectedCards.has(row.id)"
|
v-model="data.clientFk"
|
||||||
:key="row.id"
|
:label="t('invoiceOutModule.customer')"
|
||||||
:title="row.ref"
|
:options="customerOptions"
|
||||||
@click="navigate(row.id)"
|
option-label="name"
|
||||||
@toggle-card-check="toggleIndividualCard(row)"
|
option-value="id"
|
||||||
v-for="row of rows"
|
/>
|
||||||
>
|
<VnInputDate
|
||||||
<template #list-items>
|
:label="t('invoiceOutList.tableVisibleColumns.dueDate')"
|
||||||
<VnLv
|
v-model="data.maxShipped"
|
||||||
:label="t('invoiceOut.list.issued')"
|
/>
|
||||||
:value="toDate(row.issued)"
|
<VnSelect
|
||||||
/>
|
url="InvoiceOutSerials"
|
||||||
<VnLv
|
v-model="data.invoiceOutSerial"
|
||||||
:label="t('invoiceOut.list.amount')"
|
:label="t('invoiceOutList.tableVisibleColumns.invoiceOutSerial')"
|
||||||
:value="toCurrency(row.amount)"
|
:options="invoiceOutSerialsOptions"
|
||||||
/>
|
option-label="description"
|
||||||
<VnLv :label="t('invoiceOut.list.client')">
|
option-value="code"
|
||||||
<template #value>
|
/>
|
||||||
<span class="link" @click.stop>
|
<VnSelect
|
||||||
{{ row?.clientSocialName }}
|
url="TaxAreas"
|
||||||
<CustomerDescriptorProxy
|
v-model="data.area"
|
||||||
:id="row?.clientFk"
|
:label="t('invoiceOutList.tableVisibleColumns.taxArea')"
|
||||||
/>
|
:options="taxAreasOptions"
|
||||||
</span>
|
option-label="code"
|
||||||
</template>
|
option-value="code"
|
||||||
</VnLv>
|
/>
|
||||||
<VnLv
|
<QInput
|
||||||
:label="t('invoiceOut.list.shortCreated')"
|
v-model="data.reference"
|
||||||
:title-label="t('invoiceOut.list.created')"
|
:label="t('invoiceOutList.tableVisibleColumns.ref')"
|
||||||
:value="toDate(row.created)"
|
/>
|
||||||
/>
|
</template>
|
||||||
<VnLv
|
</VnTable>
|
||||||
:label="t('invoiceOut.list.company')"
|
|
||||||
:value="row.companyCode"
|
|
||||||
/>
|
|
||||||
<VnLv
|
|
||||||
:label="t('invoiceOut.list.shortDued')"
|
|
||||||
:title-label="t('invoiceOut.list.dued')"
|
|
||||||
:value="toDate(row.dued)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template #actions>
|
|
||||||
<QBtn
|
|
||||||
:label="t('components.smartCard.openSummary')"
|
|
||||||
@click.stop="viewSummary(row.id, InvoiceOutSummary)"
|
|
||||||
color="primary"
|
|
||||||
style="margin-top: 15px"
|
|
||||||
type="submit"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</CardList>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</VnPaginate>
|
|
||||||
<QPageSticky :offset="[20, 20]">
|
|
||||||
<QBtn fab icon="add" color="primary" @click="openCreateInvoiceModal()" />
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('createInvoice') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QPageSticky>
|
|
||||||
|
|
||||||
<QDialog
|
|
||||||
ref="manualInvoiceDialogRef"
|
|
||||||
transition-show="scale"
|
|
||||||
transition-hide="scale"
|
|
||||||
>
|
|
||||||
<CreateManualInvoiceForm />
|
|
||||||
</QDialog>
|
|
||||||
</QPage>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -1,200 +1,177 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onBeforeMount } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
|
||||||
import InvoiceOutNegativeFilter from './InvoiceOutNegativeBasesFilter.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
|
||||||
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
|
||||||
import { toCurrency } from 'src/filters';
|
import { toCurrency } from 'src/filters';
|
||||||
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js';
|
import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
|
||||||
|
|
||||||
const invoiceOutGlobalStore = useInvoiceOutGlobalStore();
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const tableRef = ref();
|
||||||
const arrayData = useArrayData('InvoiceOutNegative', {
|
const invoiceOutGlobalStore = useInvoiceOutGlobalStore();
|
||||||
url: 'InvoiceOuts/negativeBases',
|
const userParams = {
|
||||||
limit: 0,
|
from: Date.vnFirstDayOfMonth().toISOString(),
|
||||||
userParams: {
|
to: Date.vnLastDayOfMonth().toISOString(),
|
||||||
from: Date.vnFirstDayOfMonth().toISOString(),
|
};
|
||||||
to: Date.vnLastDayOfMonth().toISOString(),
|
useArrayData('InvoiceOutNegative', { userParams });
|
||||||
},
|
|
||||||
exprBuilder: (param, value) => {
|
|
||||||
switch (param) {
|
|
||||||
case 'from':
|
|
||||||
case 'to':
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
return { [param]: value };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
await arrayData.fetch({ append: false });
|
|
||||||
stateStore.rightDrawer = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.company'),
|
align: 'left',
|
||||||
field: 'company',
|
|
||||||
name: 'company',
|
name: 'company',
|
||||||
align: 'left',
|
label: t('invoiceOutModule.company'),
|
||||||
|
component: 'select',
|
||||||
|
cardVisible: true,
|
||||||
|
attrs: {
|
||||||
|
url: 'Companies',
|
||||||
|
optionLabel: 'code',
|
||||||
|
optionValue: 'id',
|
||||||
|
},
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.country'),
|
align: 'left',
|
||||||
field: 'country',
|
|
||||||
name: 'country',
|
name: 'country',
|
||||||
align: 'left',
|
label: t('negativeBases.country'),
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Countries',
|
||||||
|
optionLabel: 'name',
|
||||||
|
optionValue: 'id',
|
||||||
|
},
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.clientId'),
|
align: 'left',
|
||||||
field: 'clientId',
|
|
||||||
name: 'clientId',
|
name: 'clientId',
|
||||||
align: 'left',
|
label: t('negativeBases.clientId'),
|
||||||
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.client'),
|
|
||||||
field: 'clientSocialName',
|
|
||||||
name: 'client',
|
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
name: 'clientSocialName',
|
||||||
|
label: t('invoiceOutModule.customer'),
|
||||||
|
component: 'select',
|
||||||
|
isTitle: true,
|
||||||
|
cardVisible: true,
|
||||||
|
attrs: {
|
||||||
|
url: 'Clients',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
},
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.amount'),
|
align: 'left',
|
||||||
field: 'amount',
|
|
||||||
name: 'amount',
|
name: 'amount',
|
||||||
align: 'left',
|
label: t('invoiceOutModule.amount'),
|
||||||
format: (value) => toCurrency(value),
|
format: (row) => toCurrency(row.amount),
|
||||||
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.base'),
|
|
||||||
field: 'taxableBase',
|
|
||||||
name: 'base',
|
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
name: 'taxableBase',
|
||||||
|
label: t('negativeBases.base'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.ticketId'),
|
|
||||||
field: 'ticketFk',
|
|
||||||
name: 'ticketId',
|
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
name: 'ticketFk',
|
||||||
|
label: t('negativeBases.ticketId'),
|
||||||
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.active'),
|
|
||||||
field: 'isActive',
|
|
||||||
name: 'active',
|
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
name: 'isActive',
|
||||||
|
label: t('negativeBases.active'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.hasToInvoice'),
|
align: 'left',
|
||||||
field: 'hasToInvoice',
|
|
||||||
name: 'hasToInvoice',
|
name: 'hasToInvoice',
|
||||||
align: 'left',
|
label: t('negativeBases.hasToInvoice'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.verifiedData'),
|
|
||||||
field: 'isTaxDataChecked',
|
|
||||||
name: 'verifiedData',
|
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
name: 'hasVerifiedData',
|
||||||
|
label: t('negativeBases.verifiedData'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('invoiceOut.negativeBases.comercial'),
|
|
||||||
field: 'workerName',
|
|
||||||
name: 'worker',
|
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
|
||||||
|
name: 'workerName',
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
where: { role: 'salesPerson' },
|
||||||
|
},
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
format: (row, dashIfEmpty) => dashIfEmpty(row.workerName),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const downloadCSV = async () => {
|
const downloadCSV = async () => {
|
||||||
const params = {}; // filter.value;
|
|
||||||
const filterParams = {
|
const filterParams = {
|
||||||
limit: 20,
|
limit: 20,
|
||||||
where: {
|
where: {
|
||||||
and: [],
|
and: [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
for (const param in params) {
|
|
||||||
if (params[param]) filterParams.where.and.push({ [param]: params[param] });
|
for (const [key, value] of Object.entries(userParams)) {
|
||||||
|
if (value) {
|
||||||
|
filterParams.where.and.push({ [key]: value });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await invoiceOutGlobalStore.getNegativeBasesCsv(
|
await invoiceOutGlobalStore.getNegativeBasesCsv(
|
||||||
arrayData.value.store.userParams.from,
|
userParams.from,
|
||||||
arrayData.value.store.userParams.to,
|
userParams.to,
|
||||||
params
|
filterParams
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnSubToolbar>
|
<VnSubToolbar>
|
||||||
<template #st-actions>
|
<template #st-actions>
|
||||||
<QBtn color="primary" icon-right="download" no-caps @click="downloadCSV()">
|
<QBtn color="primary" icon-right="download" @click="downloadCSV()">
|
||||||
<QTooltip>{{ t('Download as CSV') }}</QTooltip>
|
<QTooltip>{{ t('Download as CSV') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</template>
|
</template>
|
||||||
</VnSubToolbar>
|
</VnSubToolbar>
|
||||||
<RightMenu>
|
<VnTable
|
||||||
<template #right-panel>
|
ref="tableRef"
|
||||||
<InvoiceOutNegativeFilter data-key="InvoiceOutNegative" />
|
data-key="negativeFilter"
|
||||||
</template>
|
url="InvoiceOuts/negativeBases"
|
||||||
</RightMenu>
|
:user-params="userParams"
|
||||||
<QPage class="column items-center q-pa-md">
|
:expr-builder="
|
||||||
<QTable
|
(param, value) => {
|
||||||
:columns="columns"
|
switch (param) {
|
||||||
:rows="arrayData.store.data"
|
case 'from':
|
||||||
row-key="clientId"
|
case 'to':
|
||||||
class="full-width q-mt-md"
|
return;
|
||||||
>
|
default:
|
||||||
<template #body-cell-clientId="{ row }">
|
return { [param]: value };
|
||||||
<QTd>
|
}
|
||||||
<QBtn flat dense class="link"> {{ row.clientId }}</QBtn>
|
}
|
||||||
<CustomerDescriptorProxy :id="row.clientId" />
|
"
|
||||||
</QTd>
|
:limit="0"
|
||||||
</template>
|
:columns="columns"
|
||||||
<template #body-cell-ticketId="{ row }">
|
default-mode="table"
|
||||||
<QTd>
|
auto-load
|
||||||
<QBtn flat dense class="link"> {{ row.ticketFk }}</QBtn>
|
:is-editable="false"
|
||||||
<TicketDescriptorProxy :id="row.ticketFk" />
|
:use-model="true"
|
||||||
</QTd>
|
>
|
||||||
</template>
|
</VnTable>
|
||||||
<template #body-cell-worker="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<QBtn class="no-uppercase link" flat dense>{{ row.workerName }}</QBtn>
|
|
||||||
<WorkerDescriptorProxy :id="row.comercialId" />
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #body-cell-active="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<QCheckbox :model-value="!!row.isActive" disable />
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #body-cell-hasToInvoice="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<QCheckbox :model-value="!!row.hasToInvoice" disable />
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #body-cell-verifiedData="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<QCheckbox :model-value="!!row.isTaxDataChecked" disable />
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
</QPage>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.col-content {
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
.no-uppercase {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Download as CSV: Descargar como CSV
|
Download as CSV: Descargar como CSV
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
invoiceOutModule:
|
||||||
|
customer: Client
|
||||||
|
amount: Amount
|
||||||
|
company: Company
|
||||||
|
invoiceOutList:
|
||||||
|
tableVisibleColumns:
|
||||||
|
id: ID
|
||||||
|
ref: Reference
|
||||||
|
issued: Issued
|
||||||
|
created: Created
|
||||||
|
dueDate: Max date
|
||||||
|
invoiceOutSerial: Serial
|
||||||
|
ticket: Ticket
|
||||||
|
taxArea: Tax area
|
||||||
|
DownloadPdf: Download PDF
|
||||||
|
InvoiceOutSummary: Summary
|
||||||
|
negativeBases:
|
||||||
|
country: Country
|
||||||
|
clientId: Client ID
|
||||||
|
base: Base
|
||||||
|
ticketId: Ticket
|
||||||
|
active: Active
|
||||||
|
hasToInvoice: Has to invoice
|
||||||
|
verifiedData: Verified data
|
||||||
|
commercial: Commercial
|
|
@ -1,2 +1,31 @@
|
||||||
Search invoice: Buscar factura emitida
|
Search invoice: Buscar factura emitida
|
||||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
You can search by invoice reference: Puedes buscar por referencia de la factura
|
||||||
|
invoiceOutModule:
|
||||||
|
customer: Cliente
|
||||||
|
amount: Importe
|
||||||
|
company: Empresa
|
||||||
|
invoiceOutList:
|
||||||
|
tableVisibleColumns:
|
||||||
|
id: ID
|
||||||
|
ref: Referencia
|
||||||
|
issued: Fecha emisión
|
||||||
|
customer: Cliente
|
||||||
|
company: Empresa
|
||||||
|
amount: Importe
|
||||||
|
created: F. creación
|
||||||
|
dueDate: F. máxima
|
||||||
|
invoiceOutSerial: Serial
|
||||||
|
ticket: Ticket
|
||||||
|
taxArea: Area
|
||||||
|
DownloadPdf: Descargar PDF
|
||||||
|
InvoiceOutSummary: Resumen
|
||||||
|
negativeBases:
|
||||||
|
country: País
|
||||||
|
clientId: ID del cliente
|
||||||
|
client: Cliente
|
||||||
|
base: Base
|
||||||
|
ticketId: Ticket
|
||||||
|
active: Activo
|
||||||
|
hasToInvoice: Debe facturar
|
||||||
|
verifiedData: Datos verificados
|
||||||
|
commercial: Comercial
|
|
@ -4,7 +4,7 @@ import { useRoute } from 'vue-router';
|
||||||
import { onMounted, onUnmounted, ref } from 'vue';
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||||
import OrderCatalogItem from 'pages/Order/Card/OrderCatalogItem.vue';
|
import CatalogItem from 'components/ui/CatalogItem.vue';
|
||||||
import OrderCatalogFilter from 'pages/Order/Card/OrderCatalogFilter.vue';
|
import OrderCatalogFilter from 'pages/Order/Card/OrderCatalogFilter.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -77,7 +77,12 @@ function extractValueTags(items) {
|
||||||
<div v-if="rows && !rows?.length" class="no-result">
|
<div v-if="rows && !rows?.length" class="no-result">
|
||||||
{{ t('globals.noResults') }}
|
{{ t('globals.noResults') }}
|
||||||
</div>
|
</div>
|
||||||
<OrderCatalogItem v-for="row in rows" :key="row.id" :item="row" />
|
<CatalogItem
|
||||||
|
v-for="row in rows"
|
||||||
|
:key="row.id"
|
||||||
|
:item="row"
|
||||||
|
is-catalog
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VnPaginate>
|
</VnPaginate>
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<script setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
ticket: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
withRoute: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
selectedExpeditions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const router = useRouter();
|
||||||
|
const { notify } = useNotify();
|
||||||
|
|
||||||
|
const newTicketFormData = reactive({});
|
||||||
|
|
||||||
|
const createTicket = async () => {
|
||||||
|
try {
|
||||||
|
const expeditionIds = $props.selectedExpeditions.map(
|
||||||
|
(expedition) => expedition.id
|
||||||
|
);
|
||||||
|
const params = {
|
||||||
|
clientId: $props.ticket.clientFk,
|
||||||
|
landed: newTicketFormData.landed,
|
||||||
|
warehouseId: $props.ticket.warehouseFk,
|
||||||
|
addressId: $props.ticket.addressFk,
|
||||||
|
agencyModeId: $props.ticket.agencyModeFk,
|
||||||
|
routeId: newTicketFormData.routeFk,
|
||||||
|
expeditionIds: expeditionIds,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data } = await axios.post('Expeditions/moveExpeditions', params);
|
||||||
|
notify(t('globals.dataSaved'), 'positive');
|
||||||
|
router.push({ name: 'TicketSummary', params: { id: data.id } });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormModelPopup
|
||||||
|
model="expeditionNewTicket"
|
||||||
|
:form-initial-data="newTicketFormData"
|
||||||
|
:save-fn="createTicket"
|
||||||
|
>
|
||||||
|
<template #form-inputs="{ data }">
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInputDate :label="t('expedition.landed')" v-model="data.landed" />
|
||||||
|
</VnRow>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInput
|
||||||
|
v-if="withRoute"
|
||||||
|
:label="t('expedition.routeId')"
|
||||||
|
v-model="data.routeFk"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModelPopup>
|
||||||
|
</template>
|
|
@ -0,0 +1,354 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
|
import FetchedTags from 'components/ui/FetchedTags.vue';
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
|
||||||
|
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
|
import { toCurrency } from 'filters/index';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const salesRef = ref(null);
|
||||||
|
const arrayData = useArrayData('ticketData');
|
||||||
|
const { store } = arrayData;
|
||||||
|
|
||||||
|
const ticketData = computed(() => store.data);
|
||||||
|
const components = ref([]);
|
||||||
|
const componentsList = ref([]);
|
||||||
|
const theoricalCost = ref(0);
|
||||||
|
const ticketVolume = ref(null);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => ticketData.value,
|
||||||
|
async () => {
|
||||||
|
await nextTick();
|
||||||
|
salesRef.value.fetch();
|
||||||
|
getComponentsSum();
|
||||||
|
getTheoricalCost();
|
||||||
|
if (ticketData.value?.zone && ticketData.value?.zone?.isVolumetric)
|
||||||
|
getTicketVolume();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const salesFilter = computed(() => ({
|
||||||
|
order: 'concept ASC',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'item',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relation: 'components',
|
||||||
|
scope: {
|
||||||
|
fields: ['componentFk', 'value'],
|
||||||
|
include: {
|
||||||
|
relation: 'component',
|
||||||
|
scope: {
|
||||||
|
fields: ['typeFk', 'name'],
|
||||||
|
include: {
|
||||||
|
relation: 'componentType',
|
||||||
|
scope: {
|
||||||
|
fields: ['type', 'isBase', 'name'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('components.item'),
|
||||||
|
name: 'item',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.description'),
|
||||||
|
name: 'description',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.quantity'),
|
||||||
|
name: 'quantity',
|
||||||
|
field: 'quantity',
|
||||||
|
align: 'left',
|
||||||
|
format: (val) => dashIfEmpty(val),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.serie'),
|
||||||
|
name: 'serie',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.components'),
|
||||||
|
name: 'components',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.import'),
|
||||||
|
name: 'import',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.total'),
|
||||||
|
name: 'total',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const getBase = computed(() => {
|
||||||
|
let sum = 0;
|
||||||
|
for (let sale of components.value) {
|
||||||
|
for (let saleComponent of sale.components) {
|
||||||
|
if (saleComponent.component.componentType.isBase) {
|
||||||
|
sum += sale.quantity * saleComponent.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTotal = computed(() => {
|
||||||
|
let total = 0;
|
||||||
|
for (let sale of components.value) {
|
||||||
|
for (let saleComponent of sale.components) {
|
||||||
|
total += sale.quantity * saleComponent.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getComponentsSum = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(`Tickets/${route.params.id}/getComponentsSum`);
|
||||||
|
componentsList.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTheoricalCost = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(`Tickets/${route.params.id}/freightCost`);
|
||||||
|
theoricalCost.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTicketVolume = async () => {
|
||||||
|
try {
|
||||||
|
if (!ticketData.value) return;
|
||||||
|
const { data } = await axios.get(`Tickets/${ticketData.value.id}/getVolume`);
|
||||||
|
ticketVolume.value = data[0].volume;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
stateStore.rightDrawer = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
ref="salesRef"
|
||||||
|
url="Sales"
|
||||||
|
:filter="salesFilter"
|
||||||
|
@on-fetch="(data) => (components = data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.total') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label"
|
||||||
|
>{{ t('components.baseToCommission') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(getBase) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label"
|
||||||
|
>{{ t('components.totalWithoutVat') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(getTotal) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.components') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection
|
||||||
|
v-for="(component, index) in componentsList"
|
||||||
|
:key="index"
|
||||||
|
horizontal
|
||||||
|
>
|
||||||
|
<span v-if="component.name" class="q-mr-xs color-vn-label">
|
||||||
|
{{ component.name }}:
|
||||||
|
</span>
|
||||||
|
<span v-if="component.value">{{
|
||||||
|
toCurrency(component.value, 'EUR', 3)
|
||||||
|
}}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.zoneBreakdown') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.price') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(ticketData?.zonePrice, 'EUR', 2) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.bonus') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(ticketData?.zoneBonus, 'EUR', 2) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.zone') }}:
|
||||||
|
</span>
|
||||||
|
<span class="link">
|
||||||
|
{{ dashIfEmpty(ticketData?.zone?.name) }}
|
||||||
|
<ZoneDescriptorProxy :id="ticketData?.zone?.id" />
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection v-if="ticketData?.zone?.isVolumetric" horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.volume') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ ticketVolume }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.packages') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ dashIfEmpty(ticketData?.packages) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.theoricalCost') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.totalPrice') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(theoricalCost, 'EUR', 2) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
|
<QTable
|
||||||
|
:rows="components"
|
||||||
|
:columns="columns"
|
||||||
|
row-key="id"
|
||||||
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
:no-data-label="t('globals.noResults')"
|
||||||
|
>
|
||||||
|
<template #body-cell-item="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<QBtn flat color="primary">
|
||||||
|
<span class="link">{{ row.itemFk }}</span>
|
||||||
|
<ItemDescriptorProxy :id="row.itemFk" />
|
||||||
|
</QBtn>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-description="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column">
|
||||||
|
<span>{{ row.item.name }}</span>
|
||||||
|
<span class="color-vn-label">{{ row.item.subName }}</span>
|
||||||
|
<FetchedTags :item="row.item" :max-length="6" />
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-serie="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ saleComponent.component?.componentType?.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-components="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ saleComponent.component?.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-import="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column text-right">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ toCurrency(saleComponent.value, 'EUR', 3) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-total="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column text-right">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ toCurrency(saleComponent.value * row.quantity, 'EUR', 3) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</template>
|
|
@ -66,6 +66,23 @@ const filter = {
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
relation: 'zone',
|
||||||
|
scope: {
|
||||||
|
fields: [
|
||||||
|
'agencyModeFk',
|
||||||
|
'bonus',
|
||||||
|
'hour',
|
||||||
|
'id',
|
||||||
|
'isVolumetric',
|
||||||
|
'itemMaxSize',
|
||||||
|
'm3Max',
|
||||||
|
'name',
|
||||||
|
'price',
|
||||||
|
'travelingDays',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,474 @@
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, computed, onUnmounted, reactive, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
|
import TicketEditManaProxy from './TicketEditMana.vue';
|
||||||
|
import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
|
||||||
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
|
import ExpeditionNewTicket from './ExpeditionNewTicket.vue';
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { toCurrency, toPercentage } from 'src/filters';
|
||||||
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
|
const editPriceProxyRef = ref(null);
|
||||||
|
const newTicketDialogRef = ref(null);
|
||||||
|
const logsTableDialogRef = ref(null);
|
||||||
|
|
||||||
|
const expeditionsLogsData = ref([]);
|
||||||
|
const selectedExpeditions = ref([]);
|
||||||
|
const allColumnNames = ref([]);
|
||||||
|
const visibleColumns = ref([]);
|
||||||
|
const newTicketWithRoute = ref(false);
|
||||||
|
const itemsOptions = ref([]);
|
||||||
|
|
||||||
|
const exprBuilder = (param, value) => {
|
||||||
|
switch (param) {
|
||||||
|
case 'expeditionFk':
|
||||||
|
return { id: value };
|
||||||
|
case 'packageItemName':
|
||||||
|
return { packagingItemFk: value };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const expeditionsFilter = computed(() => ({
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
order: ['created DESC'],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const expeditionsArrayData = useArrayData('ticketExpeditions', {
|
||||||
|
url: 'Expeditions/filter',
|
||||||
|
filter: expeditionsFilter.value,
|
||||||
|
exprBuilder: exprBuilder,
|
||||||
|
});
|
||||||
|
const expeditionsStore = expeditionsArrayData.store;
|
||||||
|
const ticketExpeditions = computed(() => expeditionsStore.data);
|
||||||
|
|
||||||
|
const ticketArrayData = useArrayData('ticketData');
|
||||||
|
const ticketStore = ticketArrayData.store;
|
||||||
|
const ticketData = computed(() => ticketStore.data);
|
||||||
|
|
||||||
|
const refetchExpeditions = async () => {
|
||||||
|
await expeditionsArrayData.applyFilter({
|
||||||
|
params: { filter: JSON.stringify(expeditionsFilter.value) },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
async () => await refetchExpeditions(),
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const params = reactive({});
|
||||||
|
|
||||||
|
const applyColumnFilter = async (col) => {
|
||||||
|
try {
|
||||||
|
const paramKey = col.columnFilter?.filterParamKey || col.field;
|
||||||
|
params[paramKey] = col.columnFilter.filterValue;
|
||||||
|
await expeditionsArrayData.addFilter({ params });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error applying column filter', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInputEvents = (col) => {
|
||||||
|
return col.columnFilter.type === 'select'
|
||||||
|
? { 'update:modelValue': () => applyColumnFilter(col) }
|
||||||
|
: {
|
||||||
|
'keyup.enter': () => applyColumnFilter(col),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('expedition.id'),
|
||||||
|
name: 'id',
|
||||||
|
field: 'id',
|
||||||
|
align: 'left',
|
||||||
|
sortable: true,
|
||||||
|
columnFilter: {
|
||||||
|
component: VnInput,
|
||||||
|
type: 'text',
|
||||||
|
filterParamKey: 'expeditionFk',
|
||||||
|
filterValue: null,
|
||||||
|
event: getInputEvents,
|
||||||
|
attrs: {
|
||||||
|
dense: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.item'),
|
||||||
|
name: 'item',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: {
|
||||||
|
component: VnInput,
|
||||||
|
type: 'text',
|
||||||
|
filterParamKey: 'packageItemName',
|
||||||
|
filterValue: null,
|
||||||
|
event: getInputEvents,
|
||||||
|
attrs: {
|
||||||
|
dense: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.name'),
|
||||||
|
name: 'name',
|
||||||
|
field: 'packageItemName',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: {
|
||||||
|
component: VnSelect,
|
||||||
|
type: 'select',
|
||||||
|
filterValue: null,
|
||||||
|
event: getInputEvents,
|
||||||
|
attrs: {
|
||||||
|
options: itemsOptions.value,
|
||||||
|
'option-value': 'id',
|
||||||
|
'option-label': 'name',
|
||||||
|
dense: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.packageType'),
|
||||||
|
name: 'packageType',
|
||||||
|
field: 'freightItemName',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: {
|
||||||
|
component: VnInput,
|
||||||
|
type: 'text',
|
||||||
|
// filterParamKey: 'expeditionFk',
|
||||||
|
filterValue: null,
|
||||||
|
event: getInputEvents,
|
||||||
|
attrs: {
|
||||||
|
dense: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.counter'),
|
||||||
|
name: 'counter',
|
||||||
|
field: 'counter',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.externalId'),
|
||||||
|
name: 'externalId',
|
||||||
|
field: 'externalId',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.created'),
|
||||||
|
name: 'created',
|
||||||
|
field: 'created',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: null,
|
||||||
|
format: (value) => toDateTimeFormat(value),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.state'),
|
||||||
|
name: 'state',
|
||||||
|
field: 'state',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
name: 'history',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: null,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const logTableColumns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('expedition.state'),
|
||||||
|
name: 'state',
|
||||||
|
field: 'state',
|
||||||
|
align: 'left',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.name'),
|
||||||
|
name: 'name',
|
||||||
|
align: 'name',
|
||||||
|
columnFilter: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('expedition.created'),
|
||||||
|
name: 'created',
|
||||||
|
field: 'created',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: null,
|
||||||
|
format: (value) => toDateTimeFormat(value),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const showNewTicketDialog = (withRoute = false) => {
|
||||||
|
newTicketWithRoute.value = withRoute;
|
||||||
|
newTicketDialogRef.value.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteExpedition = async () => {
|
||||||
|
try {
|
||||||
|
const expeditionIds = selectedExpeditions.value.map(
|
||||||
|
(expedition) => expedition.id
|
||||||
|
);
|
||||||
|
const params = { expeditionIds };
|
||||||
|
await axios.post('Expeditions/deleteExpeditions', params);
|
||||||
|
await refetchExpeditions();
|
||||||
|
selectedExpeditions.value = [];
|
||||||
|
notify(t('expedition.expeditionRemoved'), 'positive');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showLog = async (expedition) => {
|
||||||
|
await getExpeditionState(expedition);
|
||||||
|
logsTableDialogRef.value.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getExpeditionState = async (expedition) => {
|
||||||
|
try {
|
||||||
|
const filter = {
|
||||||
|
where: { expeditionFk: expedition.id },
|
||||||
|
order: ['created DESC'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data } = await axios.get(`ExpeditionStates/filter`, {
|
||||||
|
params: { filter: JSON.stringify(filter) },
|
||||||
|
});
|
||||||
|
expeditionsLogsData.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
stateStore.rightDrawer = true;
|
||||||
|
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
|
||||||
|
allColumnNames.value = filteredColumns.map((col) => col.name);
|
||||||
|
// await expeditionsArrayData.fetch({ append: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
url="Items"
|
||||||
|
auto-load
|
||||||
|
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||||
|
@on-fetch="(data) => (itemsOptions = data)"
|
||||||
|
/>
|
||||||
|
<VnSubToolbar>
|
||||||
|
<template #st-data>
|
||||||
|
<TableVisibleColumns
|
||||||
|
:all-columns="allColumnNames"
|
||||||
|
table-code="expeditionIndex"
|
||||||
|
labels-traductions-path="expedition"
|
||||||
|
@on-config-saved="visibleColumns = [...$event, 'history']"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #st-actions>
|
||||||
|
<QBtnGroup push class="q-gutter-x-sm" flat>
|
||||||
|
<QBtnDropdown
|
||||||
|
ref="btnDropdownRef"
|
||||||
|
color="primary"
|
||||||
|
:label="t('expedition.move')"
|
||||||
|
:disable="!selectedExpeditions.length"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<QTooltip>{{ t('Select lines to see the options') }}</QTooltip>
|
||||||
|
</template>
|
||||||
|
<QList>
|
||||||
|
<QItem
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
v-ripple
|
||||||
|
@click="showNewTicketDialog(false)"
|
||||||
|
>
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>{{
|
||||||
|
t('expedition.newTicketWithoutRoute')
|
||||||
|
}}</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
v-ripple
|
||||||
|
@click="showNewTicketDialog(true)"
|
||||||
|
>
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>{{
|
||||||
|
t('expedition.newTicketWithRoute')
|
||||||
|
}}</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</QList>
|
||||||
|
</QBtnDropdown>
|
||||||
|
<QBtn
|
||||||
|
:disable="!selectedExpeditions.length"
|
||||||
|
icon="delete"
|
||||||
|
color="primary"
|
||||||
|
@click="
|
||||||
|
openConfirmationModal(
|
||||||
|
'',
|
||||||
|
t('expedition.removeExpeditionSubtitle'),
|
||||||
|
deleteExpedition
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</QBtnGroup>
|
||||||
|
</template>
|
||||||
|
</VnSubToolbar>
|
||||||
|
|
||||||
|
<QTable
|
||||||
|
:rows="ticketExpeditions"
|
||||||
|
:columns="columns"
|
||||||
|
row-key="id"
|
||||||
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
selection="multiple"
|
||||||
|
v-model:selected="selectedExpeditions"
|
||||||
|
:visible-columns="visibleColumns"
|
||||||
|
:no-data-label="t('globals.noResults')"
|
||||||
|
>
|
||||||
|
<template #top-row="{ cols }">
|
||||||
|
<QTr>
|
||||||
|
<QTd />
|
||||||
|
<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-item="{ row }">
|
||||||
|
<QTd auto-width @click.stop>
|
||||||
|
<QBtn flat color="primary">{{ row.packagingItemFk }}</QBtn>
|
||||||
|
<ItemDescriptorProxy :id="row.packagingItemFk" />
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-available="{ row }">
|
||||||
|
<QTd @click.stop>
|
||||||
|
<QBadge :color="row.available < 0 ? 'alert' : 'transparent'" dense>
|
||||||
|
{{ row.available }}
|
||||||
|
</QBadge>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body-cell-price="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<template v-if="isTicketEditable && row.id">
|
||||||
|
<QBtn flat color="primary" dense @click="onOpenEditPricePopover(row)">
|
||||||
|
{{ toCurrency(row.price) }}
|
||||||
|
</QBtn>
|
||||||
|
<TicketEditManaProxy
|
||||||
|
ref="editPriceProxyRef"
|
||||||
|
:mana="mana"
|
||||||
|
:new-price="getNewPrice"
|
||||||
|
@save="updatePrice(row)"
|
||||||
|
>
|
||||||
|
<VnInput
|
||||||
|
v-model.number="edit.price"
|
||||||
|
:label="t('ticketSale.price')"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
</TicketEditManaProxy>
|
||||||
|
</template>
|
||||||
|
<span v-else>{{ toCurrency(row.price) }}</span>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-discount="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<template v-if="!isLocked && row.id">
|
||||||
|
<QBtn
|
||||||
|
flat
|
||||||
|
color="primary"
|
||||||
|
dense
|
||||||
|
@click="onOpenEditDiscountPopover(row)"
|
||||||
|
>
|
||||||
|
{{ toPercentage(row.discount / 100) }}
|
||||||
|
</QBtn>
|
||||||
|
<TicketEditManaProxy
|
||||||
|
:mana="mana"
|
||||||
|
:new-price="getNewPrice"
|
||||||
|
@save="changeDiscount(row)"
|
||||||
|
>
|
||||||
|
<VnInput
|
||||||
|
v-model.number="edit.discount"
|
||||||
|
:label="t('ticketSale.discount')"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
</TicketEditManaProxy>
|
||||||
|
</template>
|
||||||
|
<span v-else>{{ toPercentage(row.discount / 100) }}</span>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-history="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<QBtn
|
||||||
|
@click.stop="showLog(row)"
|
||||||
|
color="primary"
|
||||||
|
icon="history"
|
||||||
|
size="md"
|
||||||
|
flat
|
||||||
|
>
|
||||||
|
<QTooltip class="text-no-wrap">
|
||||||
|
{{ t('expedition.historyAction') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
<QDialog ref="newTicketDialogRef" transition-show="scale" transition-hide="scale">
|
||||||
|
<ExpeditionNewTicket
|
||||||
|
:ticket="ticketData"
|
||||||
|
:with-route="newTicketWithRoute"
|
||||||
|
:selected-expeditions="selectedExpeditions"
|
||||||
|
/>
|
||||||
|
</QDialog>
|
||||||
|
<QDialog ref="logsTableDialogRef" transition-show="scale" transition-hide="scale">
|
||||||
|
<QTable
|
||||||
|
ref="tableRef"
|
||||||
|
data-key="TicketExpeditionLog"
|
||||||
|
:rows="expeditionsLogsData"
|
||||||
|
:columns="logTableColumns"
|
||||||
|
class="q-pa-sm"
|
||||||
|
>
|
||||||
|
<template #body-cell-name="{ row }">
|
||||||
|
<QTd auto-width>
|
||||||
|
<QBtn flat dense color="primary">{{ row.name }}</QBtn>
|
||||||
|
<WorkerDescriptorProxy :id="row.workerFk" />
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</QDialog>
|
||||||
|
</template>
|
|
@ -0,0 +1,132 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, computed, reactive } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import CrudModel from 'components/CrudModel.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const ticketPackagingsCrudRef = ref(null);
|
||||||
|
const listPackagingsOptions = ref([]);
|
||||||
|
const arrayData = useArrayData('TicketPackagings');
|
||||||
|
const { store } = arrayData;
|
||||||
|
|
||||||
|
const crudModelFilter = reactive({
|
||||||
|
fields: ['id', 'ticketFk', 'packagingFk', 'quantity', 'created'],
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
const crudModelRequiredData = computed(() => ({
|
||||||
|
packagingFk: null,
|
||||||
|
quantity: 0,
|
||||||
|
created: Date.vnNew(),
|
||||||
|
ticketFk: route.params.id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const handleInputQuantityClear = (row) => {
|
||||||
|
if (row.quantity === null || row.quantity === undefined) row.quantity = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
async () => {
|
||||||
|
crudModelFilter.where.ticketFk = route.params.id;
|
||||||
|
store.filter = crudModelFilter;
|
||||||
|
await ticketPackagingsCrudRef.value.reload();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
@on-fetch="(data) => (listPackagingsOptions = data)"
|
||||||
|
auto-load
|
||||||
|
:filter="{ fields: ['packagingFk', 'name'], order: 'name ASC', limit: 30 }"
|
||||||
|
url="Packagings/listPackaging"
|
||||||
|
/>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<CrudModel
|
||||||
|
ref="ticketPackagingsCrudRef"
|
||||||
|
data-key="TicketPackagings"
|
||||||
|
url="TicketPackagings"
|
||||||
|
model="TicketPackagings"
|
||||||
|
:filter="crudModelFilter"
|
||||||
|
:data-required="crudModelRequiredData"
|
||||||
|
:default-remove="false"
|
||||||
|
auto-load
|
||||||
|
style="max-width: 800px"
|
||||||
|
>
|
||||||
|
<template #body="{ rows, validate }">
|
||||||
|
<QCard class="q-px-lg q-py-md">
|
||||||
|
<div
|
||||||
|
v-for="(row, index) in rows"
|
||||||
|
:key="index"
|
||||||
|
class="q-mb-md row items-center q-gutter-x-md"
|
||||||
|
>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('package.package')"
|
||||||
|
:options="listPackagingsOptions"
|
||||||
|
hide-selected
|
||||||
|
option-label="name"
|
||||||
|
option-value="packagingFk"
|
||||||
|
v-model="row.packagingFk"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{ scope.opt?.name }}
|
||||||
|
</QItemLabel>
|
||||||
|
<QItemLabel caption>
|
||||||
|
#{{ scope.opt?.itemFk }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
|
<VnInput
|
||||||
|
:label="t('package.quantity')"
|
||||||
|
v-model.number="row.quantity"
|
||||||
|
class="col"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
:required="true"
|
||||||
|
@update:model-value="handleInputQuantityClear(row)"
|
||||||
|
:rules="validate('TicketPackaging.quantity')"
|
||||||
|
/>
|
||||||
|
<VnInputDate :label="t('package.added')" v-model="row.created" />
|
||||||
|
<QIcon
|
||||||
|
name="delete"
|
||||||
|
size="sm"
|
||||||
|
class="cursor-pointer"
|
||||||
|
color="primary"
|
||||||
|
@click="ticketPackagingsCrudRef.remove([row])"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('package.removePackage') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
<QIcon
|
||||||
|
name="add_circle"
|
||||||
|
class="fill-icon-on-hover q-ml-md"
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
@click="ticketPackagingsCrudRef.insert()"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('package.addPackage') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
</CrudModel>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1,60 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import CatalogItem from 'components/ui/CatalogItem.vue';
|
||||||
|
|
||||||
|
import { toCurrency } from 'filters/index';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const salesFilter = {
|
||||||
|
include: {
|
||||||
|
relation: 'item',
|
||||||
|
scope: {
|
||||||
|
field: ['name', 'image'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
};
|
||||||
|
const sales = ref([]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
ref="salesRef"
|
||||||
|
url="sales"
|
||||||
|
:filter="salesFilter"
|
||||||
|
@on-fetch="(data) => (sales = data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<div class="pictures-list">
|
||||||
|
<CatalogItem v-for="(sale, index) in sales" :key="index" :item="sale.item">
|
||||||
|
<template #price>
|
||||||
|
<div class="q-mt-md full-width row justify-between items-center">
|
||||||
|
<span class="text-h6">{{ sale.quantity }}</span>
|
||||||
|
<span>{{ t('by') }}</span>
|
||||||
|
<span class="text-h6">{{ toCurrency(sale?.price) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CatalogItem>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.pictures-list {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
by: por
|
||||||
|
</i18n>
|
|
@ -774,6 +774,5 @@ es:
|
||||||
Continue anyway?: ¿Continuar de todas formas?
|
Continue anyway?: ¿Continuar de todas formas?
|
||||||
You are going to delete lines of the ticket: Vas a eliminar lineas del ticket
|
You are going to delete lines of the ticket: Vas a eliminar lineas del ticket
|
||||||
Add item: Añadir artículo
|
Add item: Añadir artículo
|
||||||
Select lines to see the options: Selecciona líneas para ver las opciones
|
|
||||||
Transfer lines: Transferir líneas
|
Transfer lines: Transferir líneas
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -77,7 +77,6 @@ const getDefaultTaxClass = async () => {
|
||||||
params: { filter: JSON.stringify(filter) },
|
params: { filter: JSON.stringify(filter) },
|
||||||
});
|
});
|
||||||
defaultTaxClass.value = data;
|
defaultTaxClass.value = data;
|
||||||
console.log('defaultTaxClass', defaultTaxClass.value);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import FetchData from 'components/FetchData.vue';
|
||||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
import toDateString from 'filters/toDateString';
|
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||||
import { toDate, toDateString, toCurrency } from 'src/filters/index';
|
|
||||||
import TicketSummary from './Card/TicketSummary.vue';
|
import TicketSummary from './Card/TicketSummary.vue';
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||||
import TicketFilter from './TicketFilter.vue';
|
import TicketFilter from './TicketFilter.vue';
|
||||||
|
|
|
@ -93,6 +93,25 @@ futureTickets:
|
||||||
moveTicketSuccess: Tickets moved successfully!
|
moveTicketSuccess: Tickets moved successfully!
|
||||||
searchInfo: Search future tickets by date
|
searchInfo: Search future tickets by date
|
||||||
futureTicket: Future tickets
|
futureTicket: Future tickets
|
||||||
|
expedition:
|
||||||
|
id: Expedition
|
||||||
|
item: Item
|
||||||
|
name: Name
|
||||||
|
packageType: Package type
|
||||||
|
counter: Counter
|
||||||
|
externalId: externalId
|
||||||
|
created: Created
|
||||||
|
state: State
|
||||||
|
historyAction: Status log
|
||||||
|
newTicketWithRoute: New ticket with route
|
||||||
|
newTicketWithoutRoute: New ticket without route
|
||||||
|
landed: Landed
|
||||||
|
routeId: Route id
|
||||||
|
deleteExpedition: Delete expedition
|
||||||
|
expeditionRemoved: Expedition removed
|
||||||
|
removeExpeditionSubtitle: Are you sure you want to delete this expedition?
|
||||||
|
worker: Worker
|
||||||
|
move: Move
|
||||||
basicData:
|
basicData:
|
||||||
next: Next
|
next: Next
|
||||||
back: Back
|
back: Back
|
||||||
|
@ -159,8 +178,32 @@ service:
|
||||||
addService: Add service
|
addService: Add service
|
||||||
quantityInfo: To create services with negative amounts mark the service on the source ticket and press the pay button.
|
quantityInfo: To create services with negative amounts mark the service on the source ticket and press the pay button.
|
||||||
createRefundSuccess: 'The following refund ticket have been created: { ticketId }'
|
createRefundSuccess: 'The following refund ticket have been created: { ticketId }'
|
||||||
|
components:
|
||||||
|
item: Item
|
||||||
|
description: Description
|
||||||
|
quantity: Quantity
|
||||||
|
serie: Serie
|
||||||
|
components: Components
|
||||||
|
import: Import
|
||||||
|
total: Total
|
||||||
|
baseToCommission: Base to commission
|
||||||
|
totalWithoutVat: Total without VAT
|
||||||
|
zoneBreakdown: Zone breakdown
|
||||||
|
price: Price
|
||||||
|
bonus: Bonus
|
||||||
|
zone: Zone
|
||||||
|
volume: Volume
|
||||||
|
theoricalCost: Theorical cost
|
||||||
|
totalPrice: Total price
|
||||||
|
packages: Packages
|
||||||
tracking:
|
tracking:
|
||||||
state: State
|
state: State
|
||||||
worker: Worker
|
worker: Worker
|
||||||
created: Created
|
created: Created
|
||||||
addState: Add state
|
addState: Add state
|
||||||
|
package:
|
||||||
|
package: Package
|
||||||
|
quantity: Quantity
|
||||||
|
added: Added
|
||||||
|
addPackage: Add package
|
||||||
|
removePackage: Remove package
|
||||||
|
|
|
@ -164,5 +164,49 @@ ticketSale:
|
||||||
shipped: F. Envío
|
shipped: F. Envío
|
||||||
agency: Agencia
|
agency: Agencia
|
||||||
address: Consignatario
|
address: Consignatario
|
||||||
|
components:
|
||||||
|
item: Artículo
|
||||||
|
description: Descripción
|
||||||
|
quantity: Cantidad
|
||||||
|
serie: Serie
|
||||||
|
components: Componentes
|
||||||
|
import: Importe
|
||||||
|
total: Total
|
||||||
|
baseToCommission: Base comisionable
|
||||||
|
totalWithoutVat: Total sin IVA
|
||||||
|
zoneBreakdown: Desglose zona
|
||||||
|
price: Precio
|
||||||
|
bonus: Bonificación
|
||||||
|
zone: Zona
|
||||||
|
volume: Volúmen
|
||||||
|
theoricalCost: Porte teórico
|
||||||
|
totalPrice: Precio total
|
||||||
|
packages: Bultos
|
||||||
|
expedition:
|
||||||
|
id: Expedición
|
||||||
|
item: Artículo
|
||||||
|
name: Nombre
|
||||||
|
packageType: Package type
|
||||||
|
counter: Contador
|
||||||
|
externalId: externalId
|
||||||
|
created: Fecha creación
|
||||||
|
state: Estado
|
||||||
|
historyAction: Historial de estados
|
||||||
|
newTicketWithRoute: Nuevo ticket con ruta
|
||||||
|
newTicketWithoutRoute: Nuevo ticket sin ruta
|
||||||
|
landed: F. entrega
|
||||||
|
routeId: Id ruta
|
||||||
|
deleteExpedition: Eliminar expedición
|
||||||
|
expeditionRemoved: Expedición eliminada
|
||||||
|
removeExpeditionSubtitle: ¿Está seguro de eliminar esta expedición?
|
||||||
|
worker: Trabajador
|
||||||
|
move: Mover
|
||||||
|
package:
|
||||||
|
package: Embalaje
|
||||||
|
quantity: Cantidad
|
||||||
|
added: Añadido
|
||||||
|
addPackage: Añadir embalaje
|
||||||
|
removePackage: Quitar embalaje
|
||||||
Search ticket: Buscar tickets
|
Search ticket: Buscar tickets
|
||||||
You can search by ticket id or alias: Puedes buscar por id o alias del ticket
|
You can search by ticket id or alias: Puedes buscar por id o alias del ticket
|
||||||
|
Select lines to see the options: Selecciona líneas para ver las opciones
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onUpdated } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default {
|
||||||
name: 'InvoiceOutGlobal',
|
name: 'InvoiceOutGlobal',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'globalInvoicing',
|
title: 'globalInvoicing',
|
||||||
icon: 'contact_support',
|
icon: 'Date_Range',
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/InvoiceOut/InvoiceOutGlobal.vue'),
|
component: () => import('src/pages/InvoiceOut/InvoiceOutGlobal.vue'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,15 +14,19 @@ export default {
|
||||||
main: ['TicketList', 'TicketAdvance', 'TicketWeekly', 'TicketFuture'],
|
main: ['TicketList', 'TicketAdvance', 'TicketWeekly', 'TicketFuture'],
|
||||||
card: [
|
card: [
|
||||||
'TicketBasicData',
|
'TicketBasicData',
|
||||||
'TicketBoxing',
|
'TicketPurchaseRequest',
|
||||||
'TicketSms',
|
|
||||||
'TicketSale',
|
'TicketSale',
|
||||||
'TicketLog',
|
'TicketLog',
|
||||||
'TicketPurchaseRequest',
|
'TicketExpedition',
|
||||||
'TicketService',
|
'TicketService',
|
||||||
'TicketTracking',
|
|
||||||
'TicketVolume',
|
'TicketVolume',
|
||||||
'TicketNotes',
|
'TicketNotes',
|
||||||
|
'TicketTracking',
|
||||||
|
'TicketBoxing',
|
||||||
|
'TicketSms',
|
||||||
|
'TicketPicture',
|
||||||
|
'TicketComponents',
|
||||||
|
'TicketPackage',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
@ -70,8 +74,8 @@ export default {
|
||||||
component: () => import('src/pages/Ticket/TicketFuture.vue'),
|
component: () => import('src/pages/Ticket/TicketFuture.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'advance',
|
|
||||||
name: 'TicketAdvance',
|
name: 'TicketAdvance',
|
||||||
|
path: 'advance',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'ticketAdvance',
|
title: 'ticketAdvance',
|
||||||
icon: 'keyboard_double_arrow_left',
|
icon: 'keyboard_double_arrow_left',
|
||||||
|
@ -142,12 +146,76 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Ticket/Card/TicketLog.vue'),
|
component: () => import('src/pages/Ticket/Card/TicketLog.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'observation',
|
||||||
|
name: 'TicketNotes',
|
||||||
|
meta: {
|
||||||
|
title: 'notes',
|
||||||
|
icon: 'vn:notes',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketNotes.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'picture',
|
||||||
|
name: 'TicketPicture',
|
||||||
|
meta: {
|
||||||
|
title: 'pictures',
|
||||||
|
icon: 'vn:photo',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketPicture.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'volume',
|
||||||
|
name: 'TicketVolume',
|
||||||
|
meta: {
|
||||||
|
title: 'volume',
|
||||||
|
icon: 'vn:volume',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketVolume.vue'),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: 'expedition',
|
||||||
|
name: 'TicketExpedition',
|
||||||
|
meta: {
|
||||||
|
title: 'expedition',
|
||||||
|
icon: 'vn:package',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketExpedition.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'service',
|
||||||
|
name: 'TicketService',
|
||||||
|
meta: {
|
||||||
|
title: 'services',
|
||||||
|
icon: 'vn:services',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketService.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'package',
|
||||||
|
name: 'TicketPackage',
|
||||||
|
meta: {
|
||||||
|
title: 'packages',
|
||||||
|
icon: 'vn:bucket',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketPackage.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'components',
|
||||||
|
name: 'TicketComponents',
|
||||||
|
meta: {
|
||||||
|
title: 'components',
|
||||||
|
icon: 'vn:components',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketComponents.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'boxing',
|
path: 'boxing',
|
||||||
name: 'TicketBoxing',
|
name: 'TicketBoxing',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'boxing',
|
title: 'boxing',
|
||||||
icon: 'vn:package',
|
icon: 'science',
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Ticket/Card/TicketBoxing.vue'),
|
component: () => import('src/pages/Ticket/Card/TicketBoxing.vue'),
|
||||||
},
|
},
|
||||||
|
@ -160,34 +228,6 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Ticket/Card/TicketSms.vue'),
|
component: () => import('src/pages/Ticket/Card/TicketSms.vue'),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
path: 'service',
|
|
||||||
name: 'TicketService',
|
|
||||||
meta: {
|
|
||||||
title: 'services',
|
|
||||||
icon: 'vn:services',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Ticket/Card/TicketService.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'volume',
|
|
||||||
name: 'TicketVolume',
|
|
||||||
meta: {
|
|
||||||
title: 'volume',
|
|
||||||
icon: 'vn:volume',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Ticket/Card/TicketVolume.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'observation',
|
|
||||||
name: 'TicketNotes',
|
|
||||||
meta: {
|
|
||||||
title: 'notes',
|
|
||||||
icon: 'vn:notes',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Ticket/Card/TicketNotes.vue'),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -237,7 +237,7 @@ export const useInvoiceOutGlobalStore = defineStore({
|
||||||
async getNegativeBasesCsv() {
|
async getNegativeBasesCsv() {
|
||||||
try {
|
try {
|
||||||
const arrayData = useArrayData('InvoiceOutNegative');
|
const arrayData = useArrayData('InvoiceOutNegative');
|
||||||
const params = arrayData.store.currentFilter;
|
const params = arrayData.store.userParams;
|
||||||
|
|
||||||
const { data } = await axios.get('InvoiceOuts/negativeBasesCsv', {
|
const { data } = await axios.get('InvoiceOuts/negativeBasesCsv', {
|
||||||
params,
|
params,
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
// describe('WagonTypeCreate', () => {
|
describe('EntryMy when is supplier', () => {
|
||||||
// beforeEach(() => {
|
beforeEach(() => {
|
||||||
// cy.viewport(1920, 1080);
|
cy.viewport(1920, 1080);
|
||||||
// cy.login('customer');
|
cy.login('supplier');
|
||||||
// cy.visit(`/#/entry/my`, {
|
cy.visit(`/#/entry/my`, {
|
||||||
// onBeforeLoad(win) {
|
onBeforeLoad(win) {
|
||||||
// cy.stub(win, 'open');
|
cy.stub(win, 'open');
|
||||||
// },
|
},
|
||||||
// });
|
});
|
||||||
// cy.waitForElement('.q-page', 6000);
|
cy.waitForElement('.q-page', 6000);
|
||||||
// });
|
});
|
||||||
|
|
||||||
// it('should create edit and remove new dms', () => {
|
it('should open buyLabel when is supplier', () => {
|
||||||
// cy.get(
|
cy.get(
|
||||||
// '[to="/null/2"] > .q-card > .column > .q-btn > .q-btn__content > .q-icon'
|
'[to="/null/2"] > .q-card > .column > .q-btn > .q-btn__content > .q-icon'
|
||||||
// ).click();
|
).click();
|
||||||
// cy.get('.q-card__actions > .q-btn').click();
|
cy.get('.q-card__actions > .q-btn').click();
|
||||||
// cy.window().its('open').should('be.called');
|
cy.window().its('open').should('be.called');
|
||||||
// });
|
});
|
||||||
// });
|
});
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/// <reference types="cypress" />
|
||||||
|
describe('Logout', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.login('developer');
|
||||||
|
cy.visit(`/#/dashboard`);
|
||||||
|
cy.waitForElement('.q-page', 6000);
|
||||||
|
});
|
||||||
|
describe('by user', () => {
|
||||||
|
it('should logout', () => {
|
||||||
|
cy.get(
|
||||||
|
'#user > .q-btn__content > .q-avatar > .q-avatar__content > .q-img > .q-img__container > .q-img__image'
|
||||||
|
).click();
|
||||||
|
cy.get('.block').click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('not user', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.intercept('GET', '**/VnUsers/acl', {
|
||||||
|
statusCode: 401,
|
||||||
|
body: {
|
||||||
|
error: {
|
||||||
|
statusCode: 401,
|
||||||
|
name: 'Error',
|
||||||
|
message: 'Authorization Required',
|
||||||
|
code: 'AUTHORIZATION_REQUIRED',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
statusMessage: 'AUTHORIZATION_REQUIRED',
|
||||||
|
}).as('someRoute');
|
||||||
|
});
|
||||||
|
it('when token not exists', () => {
|
||||||
|
cy.reload();
|
||||||
|
cy.get('.q-notification__message').should(
|
||||||
|
'have.text',
|
||||||
|
'Authorization Required'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -55,6 +55,7 @@ describe('session', () => {
|
||||||
expect(user.value).toEqual(previousUser);
|
expect(user.value).toEqual(previousUser);
|
||||||
|
|
||||||
vi.spyOn(axios, 'post').mockResolvedValue({ data: true });
|
vi.spyOn(axios, 'post').mockResolvedValue({ data: true });
|
||||||
|
vi.spyOn(axios, 'get').mockResolvedValue({ data: true });
|
||||||
await session.destroy();
|
await session.destroy();
|
||||||
|
|
||||||
user = state.getUser();
|
user = state.getUser();
|
||||||
|
|
Loading…
Reference in New Issue