forked from verdnatura/salix-front
WIP
This commit is contained in:
parent
ad950f33c6
commit
053059997a
|
@ -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>
|
|
@ -1,16 +1,17 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, computed, onUnmounted, watch } from 'vue';
|
import { onMounted, ref, computed, onUnmounted, reactive } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FetchedTags from 'components/ui/FetchedTags.vue';
|
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
||||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
import TicketEditManaProxy from './TicketEditMana.vue';
|
import TicketEditManaProxy from './TicketEditMana.vue';
|
||||||
import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
|
import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.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 { useStateStore } from 'stores/useStateStore';
|
||||||
import { toCurrency, toPercentage } from 'src/filters';
|
import { toCurrency, toPercentage } from 'src/filters';
|
||||||
|
@ -21,25 +22,64 @@ import { toDateTimeFormat } from 'src/filters/date';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { notify } = useNotify();
|
const { notify } = useNotify();
|
||||||
const { openConfirmationModal } = useVnConfirm();
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
const editPriceProxyRef = ref(null);
|
const editPriceProxyRef = ref(null);
|
||||||
|
const newTicketDialogRef = ref(null);
|
||||||
|
const expeditionsFetchDataRef = ref(null);
|
||||||
|
const logsTableDialogRef = ref(null);
|
||||||
|
|
||||||
const expeditions = ref([]);
|
const expeditionsLogsData = ref([]);
|
||||||
const selectedExpeditions = ref([]);
|
const selectedExpeditions = ref([]);
|
||||||
const allColumnNames = ref([]);
|
const allColumnNames = ref([]);
|
||||||
|
const visibleColumns = ref([]);
|
||||||
|
const newTicketWithRoute = ref(false);
|
||||||
|
const itemsOptions = ref([]);
|
||||||
|
|
||||||
// const arrayData = useArrayData('ticketData');
|
const exprBuilder = (param, value) => {
|
||||||
// const { store } = arrayData;
|
switch (param) {
|
||||||
|
case 'expeditionFk':
|
||||||
|
return { id: value };
|
||||||
|
case 'packageItemName':
|
||||||
|
return { packagingItemFk: value };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const arrayData = useArrayData('ticketExpeditions', {
|
||||||
|
url: 'Expeditions/filter',
|
||||||
|
filter: { where: { ticketFk: route.params.id }, order: ['created DESC'] },
|
||||||
|
exprBuilder: exprBuilder,
|
||||||
|
});
|
||||||
|
const { store } = arrayData;
|
||||||
|
const ticketExpeditions = computed(() => store.data);
|
||||||
|
|
||||||
// watch(
|
// watch(
|
||||||
// () => route.params.id,
|
// () => route.params.id,
|
||||||
// async () => await getSales()
|
// async () => await getSales()
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
const params = reactive({});
|
||||||
|
|
||||||
|
const applyColumnFilter = async (col) => {
|
||||||
|
try {
|
||||||
|
const paramKey = col.columnFilter?.filterParamKey || col.field;
|
||||||
|
params[paramKey] = col.columnFilter.filterValue;
|
||||||
|
await arrayData.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(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
label: t('expedition.id'),
|
label: t('expedition.id'),
|
||||||
|
@ -47,35 +87,65 @@ const columns = computed(() => [
|
||||||
field: 'id',
|
field: 'id',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
// columnFilter: {
|
columnFilter: {
|
||||||
// component: VnInput,
|
component: VnInput,
|
||||||
// type: 'text',
|
type: 'text',
|
||||||
// filterValue: null,
|
filterParamKey: 'expeditionFk',
|
||||||
// event: getInputEvents,
|
filterValue: null,
|
||||||
// attrs: {
|
event: getInputEvents,
|
||||||
// dense: true,
|
attrs: {
|
||||||
// },
|
dense: true,
|
||||||
// },
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('expedition.item'),
|
label: t('expedition.item'),
|
||||||
name: 'item',
|
name: 'item',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
columnFilter: null,
|
columnFilter: {
|
||||||
|
component: VnInput,
|
||||||
|
type: 'text',
|
||||||
|
filterParamKey: 'packageItemName',
|
||||||
|
filterValue: null,
|
||||||
|
event: getInputEvents,
|
||||||
|
attrs: {
|
||||||
|
dense: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('expedition.name'),
|
label: t('expedition.name'),
|
||||||
name: 'name',
|
name: 'name',
|
||||||
field: 'packageItemName',
|
field: 'packageItemName',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
columnFilter: null,
|
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'),
|
label: t('expedition.packageType'),
|
||||||
name: 'packageType',
|
name: 'packageType',
|
||||||
field: 'freightItemName',
|
field: 'freightItemName',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
columnFilter: null,
|
columnFilter: {
|
||||||
|
component: VnInput,
|
||||||
|
type: 'text',
|
||||||
|
// filterParamKey: 'expeditionFk',
|
||||||
|
filterValue: null,
|
||||||
|
event: getInputEvents,
|
||||||
|
attrs: {
|
||||||
|
dense: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('expedition.counter'),
|
label: t('expedition.counter'),
|
||||||
|
@ -114,13 +184,76 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const showLog = (expedition) => {};
|
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);
|
||||||
|
expeditionsFetchDataRef.value.fetch();
|
||||||
|
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 () => {
|
onMounted(async () => {
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
|
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
|
||||||
allColumnNames.value = filteredColumns.map((col) => col.name);
|
allColumnNames.value = filteredColumns.map((col) => col.name);
|
||||||
console.log('allColumnNames', allColumnNames.value);
|
await arrayData.fetch({ append: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
@ -128,12 +261,11 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Expeditions/filter"
|
url="Items"
|
||||||
auto-load
|
auto-load
|
||||||
:filter="{ where: { ticketFk: route.params.id }, order: ['created DESC'] }"
|
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||||
@on-fetch="(data) => (expeditions = data)"
|
@on-fetch="(data) => (itemsOptions = data)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VnSubToolbar>
|
<VnSubToolbar>
|
||||||
<template #st-data>
|
<template #st-data>
|
||||||
<TableVisibleColumns
|
<TableVisibleColumns
|
||||||
|
@ -143,10 +275,62 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
@on-config-saved="visibleColumns = [...$event, 'history']"
|
@on-config-saved="visibleColumns = [...$event, 'history']"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
<template #st-actions>
|
||||||
|
<QBtnGroup push class="q-gutter-x-sm" flat>
|
||||||
|
<QBtnDropdown
|
||||||
|
ref="btnDropdownRef"
|
||||||
|
color="primary"
|
||||||
|
:label="t('ticketSale.more')"
|
||||||
|
: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>
|
</VnSubToolbar>
|
||||||
|
|
||||||
<QTable
|
<QTable
|
||||||
:rows="expeditions"
|
:rows="ticketExpeditions"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:pagination="{ rowsPerPage: 0 }"
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
|
@ -156,6 +340,21 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
:visible-columns="visibleColumns"
|
:visible-columns="visibleColumns"
|
||||||
:no-data-label="t('globals.noResults')"
|
: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 }">
|
<template #body-cell-item="{ row }">
|
||||||
<QTd auto-width @click.stop>
|
<QTd auto-width @click.stop>
|
||||||
<QBtn flat color="primary">{{ row.packagingItemFk }}</QBtn>
|
<QBtn flat color="primary">{{ row.packagingItemFk }}</QBtn>
|
||||||
|
@ -234,11 +433,28 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
</QTable>
|
</QTable>
|
||||||
|
<QDialog ref="newTicketDialogRef" transition-show="scale" transition-hide="scale">
|
||||||
<!-- <QPageSticky :offset="[20, 20]">
|
<ExpeditionNewTicket
|
||||||
<QBtn @click="newOrderFromTicket()" color="primary" fab icon="add" />
|
:ticket="ticketExpeditions"
|
||||||
<QTooltip class="text-no-wrap">
|
:with-route="newTicketWithRoute"
|
||||||
{{ t('Add item to basket') }}
|
:selected-expeditions="selectedExpeditions"
|
||||||
</QTooltip>
|
/>
|
||||||
</QPageSticky> -->
|
</QDialog>
|
||||||
|
<QDialog ref="logsTableDialogRef" transition-show="scale" transition-hide="scale">
|
||||||
|
<QTable
|
||||||
|
ref="tableRef"
|
||||||
|
data-key="TicketExpeditionLog"
|
||||||
|
:rows="expeditionsLogsData"
|
||||||
|
:filter="logTableFilter"
|
||||||
|
: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>
|
</template>
|
||||||
|
|
|
@ -90,3 +90,11 @@ expedition:
|
||||||
created: Created
|
created: Created
|
||||||
state: State
|
state: State
|
||||||
historyAction: Status log
|
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
|
||||||
|
|
|
@ -89,6 +89,14 @@ expedition:
|
||||||
created: Fecha creación
|
created: Fecha creación
|
||||||
state: Estado
|
state: Estado
|
||||||
historyAction: Historial de estados
|
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
|
||||||
card:
|
card:
|
||||||
search: Buscar tickets
|
search: Buscar tickets
|
||||||
searchInfo: Buscar tickets por identificador o alias
|
searchInfo: Buscar tickets por identificador o alias
|
||||||
|
|
Loading…
Reference in New Issue