forked from verdnatura/salix-front
Merge branch 'feature/TicketExpedition' of https://gitea.verdnatura.es/hyervoni/salix-front-mindshore into feature/TicketExpedition
This commit is contained in:
commit
fef3dfa605
|
@ -187,15 +187,10 @@ function existSummary(routes) {
|
||||||
color: lighten($primary, 20%);
|
color: lighten($primary, 20%);
|
||||||
}
|
}
|
||||||
.q-checkbox {
|
.q-checkbox {
|
||||||
display: flex;
|
|
||||||
margin-bottom: 9px;
|
|
||||||
& .q-checkbox__label {
|
& .q-checkbox__label {
|
||||||
margin-left: 31px;
|
|
||||||
color: var(--vn-text-color);
|
color: var(--vn-text-color);
|
||||||
}
|
}
|
||||||
& .q-checkbox__inner {
|
& .q-checkbox__inner {
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
color: var(--vn-label-color);
|
color: var(--vn-label-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { dashIfEmpty } from 'src/filters';
|
import { dashIfEmpty } from 'src/filters';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useClipboard } from 'src/composables/useClipboard';
|
import { useClipboard } from 'src/composables/useClipboard';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
label: { type: String, default: null },
|
label: { type: String, default: null },
|
||||||
|
@ -24,52 +25,67 @@ function copyValueText() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const val = computed(() => $props.value);
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
|
||||||
.label,
|
|
||||||
.value {
|
|
||||||
white-space: pre-line;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<template>
|
<template>
|
||||||
<div class="vn-label-value">
|
<div class="vn-label-value">
|
||||||
<div v-if="$props.label || $slots.label" class="label">
|
<QCheckbox
|
||||||
<slot name="label">
|
v-if="typeof value === 'boolean'"
|
||||||
<span>{{ $props.label }}</span>
|
v-model="val"
|
||||||
</slot>
|
:label="label"
|
||||||
</div>
|
disable
|
||||||
<div class="value">
|
dense
|
||||||
<slot name="value">
|
/>
|
||||||
<span :title="$props.value">
|
<template v-else>
|
||||||
{{ $props.dash ? dashIfEmpty($props.value) : $props.value }}
|
<div v-if="label || $slots.label" class="label">
|
||||||
</span>
|
<slot name="label">
|
||||||
</slot>
|
<span>{{ label }}</span>
|
||||||
</div>
|
</slot>
|
||||||
<div class="info" v-if="$props.info">
|
</div>
|
||||||
<QIcon name="info" class="cursor-pointer" size="xs" color="grey">
|
<div class="value">
|
||||||
<QTooltip class="bg-dark text-white shadow-4" :offset="[10, 10]">
|
<slot name="value">
|
||||||
{{ $props.info }}
|
<span :title="value">
|
||||||
</QTooltip>
|
{{ dash ? dashIfEmpty(value) : value }}
|
||||||
</QIcon>
|
</span>
|
||||||
</div>
|
</slot>
|
||||||
<div class="copy" v-if="$props.copy && $props.value" @click="copyValueText()">
|
</div>
|
||||||
<QIcon name="Content_Copy" color="primary">
|
<div class="info" v-if="info">
|
||||||
<QTooltip>{{ t('globals.copyClipboard') }}</QTooltip>
|
<QIcon name="info" class="cursor-pointer" size="xs" color="grey">
|
||||||
</QIcon>
|
<QTooltip class="bg-dark text-white shadow-4" :offset="[10, 10]">
|
||||||
</div>
|
{{ info }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
<div class="copy" v-if="copy && value" @click="copyValueText()">
|
||||||
|
<QIcon name="Content_Copy" color="primary">
|
||||||
|
<QTooltip>{{ t('globals.copyClipboard') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.vn-label-value:hover .copy {
|
.vn-label-value {
|
||||||
visibility: visible;
|
&:hover .copy {
|
||||||
cursor: pointer;
|
visibility: visible;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label,
|
||||||
|
.value {
|
||||||
|
white-space: pre-line;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.copy {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.copy {
|
|
||||||
visibility: hidden;
|
:deep(.q-checkbox.disabled) {
|
||||||
}
|
opacity: 1 !important;
|
||||||
.info {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -444,11 +444,15 @@ ticket:
|
||||||
sms: Sms
|
sms: Sms
|
||||||
notes: Notes
|
notes: Notes
|
||||||
sale: Sale
|
sale: Sale
|
||||||
|
volume: Volume
|
||||||
|
observation: Notes
|
||||||
ticketAdvance: Advance tickets
|
ticketAdvance: Advance tickets
|
||||||
futureTickets: Future tickets
|
futureTickets: Future tickets
|
||||||
expedition: Expedition
|
expedition: Expedition
|
||||||
purchaseRequest: Purchase request
|
purchaseRequest: Purchase request
|
||||||
weeklyTickets: Weekly tickets
|
weeklyTickets: Weekly tickets
|
||||||
|
services: Service
|
||||||
|
tracking: Tracking
|
||||||
list:
|
list:
|
||||||
nickname: Nickname
|
nickname: Nickname
|
||||||
state: State
|
state: State
|
||||||
|
|
|
@ -443,11 +443,15 @@ ticket:
|
||||||
sms: Sms
|
sms: Sms
|
||||||
notes: Notas
|
notes: Notas
|
||||||
sale: Lineas del pedido
|
sale: Lineas del pedido
|
||||||
|
volume: Volumen
|
||||||
|
observation: Notas
|
||||||
ticketAdvance: Adelantar tickets
|
ticketAdvance: Adelantar tickets
|
||||||
futureTickets: Tickets a futuro
|
futureTickets: Tickets a futuro
|
||||||
expedition: Expedición
|
expedition: Expedición
|
||||||
purchaseRequest: Petición de compra
|
purchaseRequest: Petición de compra
|
||||||
weeklyTickets: Tickets programados
|
weeklyTickets: Tickets programados
|
||||||
|
services: Servicios
|
||||||
|
tracking: Estados
|
||||||
list:
|
list:
|
||||||
nickname: Alias
|
nickname: Alias
|
||||||
state: Estado
|
state: Estado
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<script setup>
|
||||||
|
import { reactive, ref, onMounted, nextTick } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const emit = defineEmits(['onDataSaved']);
|
||||||
|
|
||||||
|
const nameInputRef = ref(null);
|
||||||
|
const serviceFormData = reactive({});
|
||||||
|
|
||||||
|
const onDataSaved = (formData, requestResponse) => {
|
||||||
|
emit('onDataSaved', formData, requestResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await nextTick();
|
||||||
|
nameInputRef.value.focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormModelPopup
|
||||||
|
url-create="TicketServiceTypes"
|
||||||
|
model="TicketServiceType"
|
||||||
|
:title="t('New service type')"
|
||||||
|
:form-initial-data="serviceFormData"
|
||||||
|
@on-data-saved="onDataSaved"
|
||||||
|
>
|
||||||
|
<template #form-inputs="{ data }">
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInput
|
||||||
|
ref="nameInputRef"
|
||||||
|
:label="t('service.description')"
|
||||||
|
v-model="data.name"
|
||||||
|
:required="true"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModelPopup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
New service type: Nuevo tipo de servicio
|
||||||
|
</i18n>
|
|
@ -0,0 +1,86 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
|
||||||
|
const emit = defineEmits(['onRequestCreated']);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const state = useState();
|
||||||
|
const user = state.getUser();
|
||||||
|
const stateFetchDataRef = ref(null);
|
||||||
|
|
||||||
|
const statesOptions = ref([]);
|
||||||
|
const workersOptions = ref([]);
|
||||||
|
|
||||||
|
const onStateFkChange = (formData) => (formData.userFk = user.value.id);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
ref="stateFetchDataRef"
|
||||||
|
url="States"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="(data) => (statesOptions = data)"
|
||||||
|
/>
|
||||||
|
<FetchData
|
||||||
|
url="Workers/search"
|
||||||
|
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="(data) => (workersOptions = data)"
|
||||||
|
/>
|
||||||
|
<FormModelPopup
|
||||||
|
:title="t('Create tracking')"
|
||||||
|
url-create="Tickets/state"
|
||||||
|
model="CreateTicketTracking"
|
||||||
|
:form-initial-data="{ ticketFk: route.params.id }"
|
||||||
|
@on-data-saved="() => emit('onRequestCreated')"
|
||||||
|
>
|
||||||
|
<template #form-inputs="{ data }">
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnSelect
|
||||||
|
v-model="data.stateFk"
|
||||||
|
:label="t('tracking.state')"
|
||||||
|
:options="statesOptions"
|
||||||
|
@update:model-value="onStateFkChange(data)"
|
||||||
|
hide-selected
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
/>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('tracking.worker')"
|
||||||
|
v-model="data.userFk"
|
||||||
|
:options="workersOptions"
|
||||||
|
hide-selected
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
>
|
||||||
|
<template #option="{ opt, itemProps }">
|
||||||
|
<QItem v-bind="itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{ opt.name }}
|
||||||
|
</QItemLabel>
|
||||||
|
<QItemLabel caption>
|
||||||
|
{{ opt.nickname }}, {{ opt.code }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template></VnSelect
|
||||||
|
>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModelPopup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Create tracking: Crear estado
|
||||||
|
</i18n>
|
|
@ -71,7 +71,7 @@ const filter = {
|
||||||
|
|
||||||
const data = ref(useCardDescription());
|
const data = ref(useCardDescription());
|
||||||
const setData = (entity) =>
|
const setData = (entity) =>
|
||||||
(data.value = useCardDescription(entity.client.name, entity.id));
|
(data.value = useCardDescription(entity.client?.name, entity.id));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -92,7 +92,7 @@ const setData = (entity) =>
|
||||||
<template #value>
|
<template #value>
|
||||||
<span class="link">
|
<span class="link">
|
||||||
{{ entity.clientFk }}
|
{{ entity.clientFk }}
|
||||||
<CustomerDescriptorProxy :id="entity.client.id" />
|
<CustomerDescriptorProxy :id="entity.client?.id" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
|
@ -109,8 +109,8 @@ const setData = (entity) =>
|
||||||
<VnLv :label="t('ticket.summary.salesPerson')">
|
<VnLv :label="t('ticket.summary.salesPerson')">
|
||||||
<template #value>
|
<template #value>
|
||||||
<VnUserLink
|
<VnUserLink
|
||||||
:name="entity.client.salesPersonUser?.name"
|
:name="entity.client?.salesPersonUser?.name"
|
||||||
:worker-id="entity.client.salesPersonFk"
|
:worker-id="entity.client?.salesPersonFk"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
<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 VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const ticketNotesCrudRef = ref(null);
|
||||||
|
const observationTypes = ref([]);
|
||||||
|
const arrayData = useArrayData('TicketNotes');
|
||||||
|
const { store } = arrayData;
|
||||||
|
|
||||||
|
const crudModelFilter = reactive({
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
fields: ['id', 'ticketFk', 'observationTypeFk', 'description'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const crudModelRequiredData = computed(() => ({ ticketFk: route.params.id }));
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
async () => {
|
||||||
|
crudModelFilter.where.ticketFk = route.params.id;
|
||||||
|
store.filter = crudModelFilter;
|
||||||
|
await ticketNotesCrudRef.value.reload();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
@on-fetch="(data) => (observationTypes = data)"
|
||||||
|
auto-load
|
||||||
|
url="ObservationTypes"
|
||||||
|
/>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<CrudModel
|
||||||
|
ref="ticketNotesCrudRef"
|
||||||
|
data-key="TicketNotes"
|
||||||
|
url="TicketObservations"
|
||||||
|
model="TicketNotes"
|
||||||
|
:filter="crudModelFilter"
|
||||||
|
:data-required="crudModelRequiredData"
|
||||||
|
:default-remove="false"
|
||||||
|
auto-load
|
||||||
|
style="max-width: 800px"
|
||||||
|
>
|
||||||
|
<template #body="{ rows }">
|
||||||
|
<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('ticketNotes.observationType')"
|
||||||
|
:options="observationTypes"
|
||||||
|
hide-selected
|
||||||
|
option-label="description"
|
||||||
|
option-value="id"
|
||||||
|
v-model="row.observationTypeFk"
|
||||||
|
:disable="!!row.id"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
:label="t('ticketNotes.description')"
|
||||||
|
v-model="row.description"
|
||||||
|
class="col"
|
||||||
|
/>
|
||||||
|
<QIcon
|
||||||
|
name="delete"
|
||||||
|
size="sm"
|
||||||
|
class="cursor-pointer"
|
||||||
|
color="primary"
|
||||||
|
@click="ticketNotesCrudRef.remove([row])"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('ticketNotes.removeNote') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
<VnRow v-if="observationTypes.length > rows.length">
|
||||||
|
<QIcon
|
||||||
|
name="add_circle"
|
||||||
|
class="fill-icon-on-hover q-ml-md"
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
@click="ticketNotesCrudRef.insert()"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('ticketNotes.addNote') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</VnRow>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
</CrudModel>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1,190 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, computed, onMounted } from 'vue';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import CrudModel from 'components/CrudModel.vue';
|
||||||
|
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import TicketCreateServiceType from './TicketCreateServiceType.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const ticketServiceTypeFetchRef = ref(null);
|
||||||
|
const ticketServiceCrudRef = ref(null);
|
||||||
|
const ticketServiceOptions = ref([]);
|
||||||
|
const arrayData = useArrayData('TicketNotes');
|
||||||
|
const { store } = arrayData;
|
||||||
|
const { notify } = useNotify();
|
||||||
|
|
||||||
|
const selected = ref([]);
|
||||||
|
const defaultTaxClass = ref(null);
|
||||||
|
|
||||||
|
const crudModelFilter = computed(() => ({
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const crudModelRequiredData = computed(() => ({
|
||||||
|
ticketFk: route.params.id,
|
||||||
|
taxClassFk: defaultTaxClass.value?.id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
async () => {
|
||||||
|
store.filter = crudModelFilter.value;
|
||||||
|
await ticketServiceCrudRef.value.reload();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(async () => await getDefaultTaxClass());
|
||||||
|
|
||||||
|
const createRefund = async () => {
|
||||||
|
try {
|
||||||
|
if (!selected.value.length) return;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
servicesIds: selected.value.map((s) => +s.ticketFk),
|
||||||
|
withWarehouse: false,
|
||||||
|
negative: true,
|
||||||
|
};
|
||||||
|
const { data } = await axios.post('Sales/clone', params);
|
||||||
|
const [refundTicket] = data;
|
||||||
|
notify(
|
||||||
|
t('service.createRefundSuccess', {
|
||||||
|
ticketId: refundTicket.id,
|
||||||
|
}),
|
||||||
|
'positive'
|
||||||
|
);
|
||||||
|
router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDefaultTaxClass = async () => {
|
||||||
|
try {
|
||||||
|
let filter = {
|
||||||
|
where: { code: 'G' },
|
||||||
|
};
|
||||||
|
const { data } = await axios.get('TaxClasses/findOne', {
|
||||||
|
params: { filter: JSON.stringify(filter) },
|
||||||
|
});
|
||||||
|
defaultTaxClass.value = data;
|
||||||
|
console.log('defaultTaxClass', defaultTaxClass.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
label: t('service.description'),
|
||||||
|
field: (row) => row.ticketServiceTypeFk,
|
||||||
|
sortable: true,
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'quantity',
|
||||||
|
label: t('service.quantity'),
|
||||||
|
field: (row) => row.quantity,
|
||||||
|
sortable: true,
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'price',
|
||||||
|
label: t('service.price'),
|
||||||
|
field: (row) => row.price,
|
||||||
|
sortable: true,
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
ref="ticketServiceTypeFetchRef"
|
||||||
|
@on-fetch="(data) => (ticketServiceOptions = data)"
|
||||||
|
auto-load
|
||||||
|
url="TicketServiceTypes"
|
||||||
|
/>
|
||||||
|
<CrudModel
|
||||||
|
ref="ticketServiceCrudRef"
|
||||||
|
data-key="TicketService"
|
||||||
|
url="TicketServices"
|
||||||
|
model="TicketService"
|
||||||
|
:filter="crudModelFilter"
|
||||||
|
:data-required="crudModelRequiredData"
|
||||||
|
auto-load
|
||||||
|
v-model:selected="selected"
|
||||||
|
>
|
||||||
|
<template #moreBeforeActions>
|
||||||
|
<QBtn
|
||||||
|
color="primary"
|
||||||
|
:label="t('service.pay')"
|
||||||
|
:disabled="!selected.length"
|
||||||
|
@click.stop="createRefund()"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #body="{ rows }">
|
||||||
|
<QTable
|
||||||
|
:columns="columns"
|
||||||
|
:rows="rows"
|
||||||
|
row-key="$index"
|
||||||
|
selection="multiple"
|
||||||
|
v-model:selected="selected"
|
||||||
|
table-header-class="text-left"
|
||||||
|
>
|
||||||
|
<template #body-cell-description="{ row, col }">
|
||||||
|
<QTd auto-width>
|
||||||
|
<VnSelectDialog
|
||||||
|
:label="col.label"
|
||||||
|
v-model="row.ticketServiceTypeFk"
|
||||||
|
:options="ticketServiceOptions"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
hide-selected
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<TicketCreateServiceType
|
||||||
|
@on-data-saved="ticketServiceTypeFetchRef.fetch()"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</VnSelectDialog>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-quantity="{ row, col }">
|
||||||
|
<QTd auto-width>
|
||||||
|
<VnInput
|
||||||
|
:label="col.label"
|
||||||
|
v-model.number="row.quantity"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
:info="t('service.quantityInfo')"
|
||||||
|
/>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-price="{ row, col }">
|
||||||
|
<QTd auto-width>
|
||||||
|
<VnInput
|
||||||
|
:label="col.label"
|
||||||
|
v-model.number="row.price"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</template>
|
||||||
|
</CrudModel>
|
||||||
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||||
|
<QBtn fab color="primary" icon="add" @click="ticketServiceCrudRef.insert()" />
|
||||||
|
</QPageSticky>
|
||||||
|
</template>
|
|
@ -0,0 +1,121 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, watch, reactive } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import TicketCreateTracking from './TicketCreateTracking.vue';
|
||||||
|
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||||
|
|
||||||
|
import { toDateTimeFormat } from 'src/filters/date.js';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const createTrackingDialogRef = ref(null);
|
||||||
|
const paginateRef = ref(null);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
async (val) => {
|
||||||
|
paginateFilter.where.ticketFk = val;
|
||||||
|
paginateRef.value.fetch();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const paginateFilter = reactive({
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'user',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
include: {
|
||||||
|
relation: 'worker',
|
||||||
|
scope: {
|
||||||
|
fields: ['id'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relation: 'state',
|
||||||
|
scope: {
|
||||||
|
fields: ['name'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
order: ['created DESC'],
|
||||||
|
where: {
|
||||||
|
ticketFk: route.params.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('tracking.state'),
|
||||||
|
name: 'state',
|
||||||
|
field: 'state',
|
||||||
|
align: 'left',
|
||||||
|
format: (val) => val.name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('tracking.worker'),
|
||||||
|
name: 'worker',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('tracking.created'),
|
||||||
|
name: 'created',
|
||||||
|
field: 'created',
|
||||||
|
align: 'left',
|
||||||
|
format: (val) => toDateTimeFormat(val),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const openCreateModal = () => createTrackingDialogRef.value.show();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QPage class="column items-center q-pa-md">
|
||||||
|
<VnPaginate
|
||||||
|
ref="paginateRef"
|
||||||
|
data-key="TicketTracking"
|
||||||
|
:filter="paginateFilter"
|
||||||
|
url="TicketTrackings"
|
||||||
|
auto-load
|
||||||
|
>
|
||||||
|
<template #body="{ rows }">
|
||||||
|
<QTable
|
||||||
|
:rows="rows"
|
||||||
|
:columns="columns"
|
||||||
|
row-key="id"
|
||||||
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
:no-data-label="t('globals.noResults')"
|
||||||
|
>
|
||||||
|
<template #body-cell-worker="{ row }">
|
||||||
|
<QTd @click.stop>
|
||||||
|
<QBtn flat color="primary">
|
||||||
|
{{ row.user?.name }}
|
||||||
|
<WorkerDescriptorProxy :id="row.user?.worker?.id" />
|
||||||
|
</QBtn>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</template>
|
||||||
|
</VnPaginate>
|
||||||
|
<QDialog
|
||||||
|
ref="createTrackingDialogRef"
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
>
|
||||||
|
<TicketCreateTracking @on-request-created="paginateRef.fetch()" />
|
||||||
|
</QDialog>
|
||||||
|
<QPageSticky :offset="[20, 20]">
|
||||||
|
<QBtn @click="openCreateModal()" color="primary" fab icon="add" />
|
||||||
|
<QTooltip class="text-no-wrap">
|
||||||
|
{{ t('tracking.addState') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QPageSticky>
|
||||||
|
</QPage>
|
||||||
|
</template>
|
|
@ -0,0 +1,153 @@
|
||||||
|
<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 { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const salesRef = ref(null);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
async () => {
|
||||||
|
await nextTick();
|
||||||
|
salesRef.value?.fetch();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const salesFilter = computed(() => ({
|
||||||
|
include: { relation: 'item' },
|
||||||
|
order: 'concept',
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
limit: 20,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sales = ref([]);
|
||||||
|
const packingTypeVolume = ref([]);
|
||||||
|
const rows = computed(() => sales.value);
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('volume.item'),
|
||||||
|
name: 'item',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('volume.description'),
|
||||||
|
name: 'description',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('volume.packingType'),
|
||||||
|
name: 'quantity',
|
||||||
|
field: (row) => row.item.itemPackingTypeFk,
|
||||||
|
align: 'left',
|
||||||
|
format: (val) => dashIfEmpty(val),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('volume.quantity'),
|
||||||
|
name: 'quantity',
|
||||||
|
field: 'quantity',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('volume.volumeQuantity'),
|
||||||
|
name: 'quantity',
|
||||||
|
field: (row) => row.saleVolume?.volume,
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const applyVolumes = async (salesData) => {
|
||||||
|
try {
|
||||||
|
if (!salesData.length) return;
|
||||||
|
|
||||||
|
sales.value = salesData;
|
||||||
|
const ticket = sales.value[0].ticketFk;
|
||||||
|
const { data } = await axios.get(`Tickets/${ticket}/getVolume`);
|
||||||
|
const volumes = new Map(data.saleVolume.map((volume) => [volume.saleFk, volume]));
|
||||||
|
|
||||||
|
sales.value.forEach((sale) => {
|
||||||
|
sale.saleVolume = volumes.get(sale.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
packingTypeVolume.value = data.packingTypeVolume;
|
||||||
|
} 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) => applyVolumes(data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<RightMenu v-if="packingTypeVolume.length">
|
||||||
|
<template #right-panel>
|
||||||
|
<QCard
|
||||||
|
v-for="(packingType, index) in packingTypeVolume"
|
||||||
|
:key="index"
|
||||||
|
class="q-pa-md q-mb-md q-ma-md color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection class="column items-center" horizontal>
|
||||||
|
<span>
|
||||||
|
{{ t('volume.type') }}:
|
||||||
|
{{ dashIfEmpty(packingType.description) }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection class="column items-center" horizontal>
|
||||||
|
<span> {{ t('volume.volume') }}: {{ packingType.volume }} </span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
|
<QTable
|
||||||
|
:rows="rows"
|
||||||
|
:columns="columns"
|
||||||
|
row-key="id"
|
||||||
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
:no-data-label="t('globals.noResults')"
|
||||||
|
>
|
||||||
|
<template #body-cell-item="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<QBtn flat color="primary">
|
||||||
|
{{ row.itemFk }}
|
||||||
|
<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>
|
||||||
|
</QTable>
|
||||||
|
</template>
|
|
@ -1,3 +1,19 @@
|
||||||
|
card:
|
||||||
|
search: Search tickets
|
||||||
|
searchInfo: You can search by ticket id or alias
|
||||||
|
volume:
|
||||||
|
item: Item
|
||||||
|
description: Description
|
||||||
|
packingType: Packing Type
|
||||||
|
quantity: Quantity
|
||||||
|
volumeQuantity: m³ per quantity
|
||||||
|
type: Type
|
||||||
|
volume: Volume
|
||||||
|
ticketNotes:
|
||||||
|
observationType: Observation type
|
||||||
|
description: Description
|
||||||
|
removeNote: Remove note
|
||||||
|
addNote: Add note
|
||||||
ticketSale:
|
ticketSale:
|
||||||
id: Id
|
id: Id
|
||||||
visible: Visible
|
visible: Visible
|
||||||
|
@ -132,9 +148,6 @@ basicData:
|
||||||
negativesConfirmMessage: Negatives are going to be generated, are you sure you want to advance all the lines?
|
negativesConfirmMessage: Negatives are going to be generated, are you sure you want to advance all the lines?
|
||||||
chooseAnOption: Choose an option
|
chooseAnOption: Choose an option
|
||||||
unroutedTicket: The ticket has been unrouted
|
unroutedTicket: The ticket has been unrouted
|
||||||
card:
|
|
||||||
search: Search tickets
|
|
||||||
searchInfo: You can search by ticket id or alias
|
|
||||||
purchaseRequest:
|
purchaseRequest:
|
||||||
id: Id
|
id: Id
|
||||||
description: Description
|
description: Description
|
||||||
|
@ -155,3 +168,18 @@ weeklyTickets:
|
||||||
salesperson: Salesperson
|
salesperson: Salesperson
|
||||||
search: Search weekly tickets
|
search: Search weekly tickets
|
||||||
searchInfo: Search weekly tickets by id or client id
|
searchInfo: Search weekly tickets by id or client id
|
||||||
|
service:
|
||||||
|
pay: Pay
|
||||||
|
description: Description
|
||||||
|
quantity: Quantity
|
||||||
|
price: Price
|
||||||
|
removeService: Remove service
|
||||||
|
newService: New service type
|
||||||
|
addService: Add service
|
||||||
|
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 }'
|
||||||
|
tracking:
|
||||||
|
state: State
|
||||||
|
worker: Worker
|
||||||
|
created: Created
|
||||||
|
addState: Add state
|
||||||
|
|
|
@ -1,6 +1,34 @@
|
||||||
|
service:
|
||||||
|
pay: Abonar
|
||||||
|
description: Descripción
|
||||||
|
quantity: Cantidad
|
||||||
|
price: Precio
|
||||||
|
removeService: Quitar servicio
|
||||||
|
newService: Nuevo tipo de servicio
|
||||||
|
addService: Añadir servicio
|
||||||
|
quantityInfo: Para crear sevicios con cantidades negativas marcar servicio en el ticket origen y apretar el boton abonar.
|
||||||
|
createRefundSuccess: 'Se ha creado siguiente ticket de abono: { ticketId }'
|
||||||
|
tracking:
|
||||||
|
state: Estado
|
||||||
|
worker: Trabajador
|
||||||
|
created: Fecha creación
|
||||||
|
addState: Añadir estado
|
||||||
card:
|
card:
|
||||||
search: Buscar tickets
|
search: Buscar tickets
|
||||||
searchInfo: Buscar tickets por identificador o alias
|
searchInfo: Buscar tickets por identificador o alias
|
||||||
|
volume:
|
||||||
|
item: Artículo
|
||||||
|
description: Descripción
|
||||||
|
packingType: Encajado
|
||||||
|
quantity: Cantidad
|
||||||
|
volumeQuantity: m³ por cantidad
|
||||||
|
type: Tipo
|
||||||
|
volume: Volumen
|
||||||
|
ticketNotes:
|
||||||
|
observationType: Tipo de observación
|
||||||
|
description: Descripción
|
||||||
|
removeNote: Quitar nota
|
||||||
|
addNote: Añadir nota
|
||||||
purchaseRequest:
|
purchaseRequest:
|
||||||
Id: Id
|
Id: Id
|
||||||
description: Descripción
|
description: Descripción
|
||||||
|
@ -112,8 +140,6 @@ futureTickets:
|
||||||
moveTicketSuccess: Tickets movidos correctamente
|
moveTicketSuccess: Tickets movidos correctamente
|
||||||
searchInfo: Buscar tickets por fecha
|
searchInfo: Buscar tickets por fecha
|
||||||
futureTicket: Tickets a futuro
|
futureTicket: Tickets a futuro
|
||||||
Search ticket: Buscar tickets
|
|
||||||
You can search by ticket id or alias: Puedes buscar por id o alias del ticket
|
|
||||||
ticketSale:
|
ticketSale:
|
||||||
id: Id
|
id: Id
|
||||||
visible: Visible
|
visible: Visible
|
||||||
|
@ -157,3 +183,5 @@ expedition:
|
||||||
removeExpeditionSubtitle: ¿Está seguro de eliminar esta expedición?
|
removeExpeditionSubtitle: ¿Está seguro de eliminar esta expedición?
|
||||||
worker: Trabajador
|
worker: Trabajador
|
||||||
move: Mover
|
move: Mover
|
||||||
|
Search ticket: Buscar tickets
|
||||||
|
You can search by ticket id or alias: Puedes buscar por id o alias del ticket
|
||||||
|
|
|
@ -14,12 +14,16 @@ export default {
|
||||||
main: ['TicketList', 'TicketAdvance', 'TicketWeekly', 'TicketFuture'],
|
main: ['TicketList', 'TicketAdvance', 'TicketWeekly', 'TicketFuture'],
|
||||||
card: [
|
card: [
|
||||||
'TicketBasicData',
|
'TicketBasicData',
|
||||||
'TicketBoxing',
|
'TicketPurchaseRequest',
|
||||||
'TicketSms',
|
|
||||||
'TicketSale',
|
'TicketSale',
|
||||||
'TicketLog',
|
'TicketLog',
|
||||||
'TicketExpedition',
|
'TicketExpedition',
|
||||||
'TicketPurchaseRequest',
|
'TicketService',
|
||||||
|
'TicketVolume',
|
||||||
|
'TicketNotes',
|
||||||
|
'TicketTracking',
|
||||||
|
'TicketBoxing',
|
||||||
|
'TicketSms',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
@ -30,8 +34,8 @@ export default {
|
||||||
redirect: { name: 'TicketList' },
|
redirect: { name: 'TicketList' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'TicketList',
|
|
||||||
path: 'list',
|
path: 'list',
|
||||||
|
name: 'TicketList',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'list',
|
title: 'list',
|
||||||
icon: 'view_list',
|
icon: 'view_list',
|
||||||
|
@ -39,8 +43,8 @@ export default {
|
||||||
component: () => import('src/pages/Ticket/TicketList.vue'),
|
component: () => import('src/pages/Ticket/TicketList.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'TicketCreate',
|
|
||||||
path: 'create',
|
path: 'create',
|
||||||
|
name: 'TicketCreate',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'createTicket',
|
title: 'createTicket',
|
||||||
icon: 'vn:ticketAdd',
|
icon: 'vn:ticketAdd',
|
||||||
|
@ -58,8 +62,17 @@ export default {
|
||||||
component: () => import('src/pages/Ticket/TicketAdvance.vue'),
|
component: () => import('src/pages/Ticket/TicketAdvance.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'TicketWeekly',
|
name: 'TicketAdvance',
|
||||||
|
path: 'advance',
|
||||||
|
meta: {
|
||||||
|
title: 'ticketAdvance',
|
||||||
|
icon: 'keyboard_double_arrow_left',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/TicketAdvance.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
path: 'weekly',
|
path: 'weekly',
|
||||||
|
name: 'TicketWeekly',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'weeklyTickets',
|
title: 'weeklyTickets',
|
||||||
icon: 'access_time',
|
icon: 'access_time',
|
||||||
|
@ -67,14 +80,23 @@ export default {
|
||||||
component: () => import('src/pages/Ticket/TicketWeekly.vue'),
|
component: () => import('src/pages/Ticket/TicketWeekly.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'TicketFuture',
|
|
||||||
path: 'future',
|
path: 'future',
|
||||||
|
name: 'TicketFuture',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'futureTickets',
|
title: 'futureTickets',
|
||||||
icon: 'keyboard_double_arrow_right',
|
icon: 'keyboard_double_arrow_right',
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Ticket/TicketFuture.vue'),
|
component: () => import('src/pages/Ticket/TicketFuture.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'advance',
|
||||||
|
name: 'TicketAdvance',
|
||||||
|
meta: {
|
||||||
|
title: 'ticketAdvance',
|
||||||
|
icon: 'keyboard_double_arrow_left',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/TicketAdvance.vue'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -84,8 +106,8 @@ export default {
|
||||||
redirect: { name: 'TicketSummary' },
|
redirect: { name: 'TicketSummary' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'TicketSummary',
|
|
||||||
path: 'summary',
|
path: 'summary',
|
||||||
|
name: 'TicketSummary',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'summary',
|
title: 'summary',
|
||||||
icon: 'launch',
|
icon: 'launch',
|
||||||
|
@ -93,8 +115,8 @@ export default {
|
||||||
component: () => import('src/pages/Ticket/Card/TicketSummary.vue'),
|
component: () => import('src/pages/Ticket/Card/TicketSummary.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'TicketBasicData',
|
|
||||||
path: 'basic-data',
|
path: 'basic-data',
|
||||||
|
name: 'TicketBasicData',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'basicData',
|
title: 'basicData',
|
||||||
icon: 'vn:settings',
|
icon: 'vn:settings',
|
||||||
|
@ -103,8 +125,8 @@ export default {
|
||||||
import('src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue'),
|
import('src/pages/Ticket/Card/BasicData/TicketBasicDataView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'TicketSale',
|
|
||||||
path: 'sale',
|
path: 'sale',
|
||||||
|
name: 'TicketSale',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'sale',
|
title: 'sale',
|
||||||
icon: 'vn:lines',
|
icon: 'vn:lines',
|
||||||
|
@ -122,23 +144,13 @@ export default {
|
||||||
import('src/pages/Ticket/Card/TicketPurchaseRequest.vue'),
|
import('src/pages/Ticket/Card/TicketPurchaseRequest.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'log',
|
path: 'tracking',
|
||||||
name: 'TicketLog',
|
name: 'TicketTracking',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'log',
|
title: 'tracking',
|
||||||
icon: 'history',
|
icon: 'vn:eye',
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Ticket/Card/TicketLog.vue'),
|
component: () => import('src/pages/Ticket/Card/TicketTracking.vue'),
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'request',
|
|
||||||
name: 'TicketPurchaseRequest',
|
|
||||||
meta: {
|
|
||||||
title: 'purchaseRequest',
|
|
||||||
icon: 'vn:buyrequest',
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import('src/pages/Ticket/Card/TicketPurchaseRequest.vue'),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'log',
|
path: 'log',
|
||||||
|
@ -149,6 +161,24 @@ 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: 'volume',
|
||||||
|
name: 'TicketVolume',
|
||||||
|
meta: {
|
||||||
|
title: 'volume',
|
||||||
|
icon: 'vn:volume',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketVolume.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'expedition',
|
path: 'expedition',
|
||||||
name: 'TicketExpedition',
|
name: 'TicketExpedition',
|
||||||
|
@ -158,7 +188,15 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Ticket/Card/TicketExpedition.vue'),
|
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: 'boxing',
|
path: 'boxing',
|
||||||
name: 'TicketBoxing',
|
name: 'TicketBoxing',
|
||||||
|
|
|
@ -2,13 +2,10 @@ describe('AgencyWorkCenter', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport(1920, 1080);
|
cy.viewport(1920, 1080);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.visit(`/#/agency`);
|
cy.visit(`/#/agency/11/workCenter`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('assign workCenter', () => {
|
it('assign workCenter', () => {
|
||||||
cy.visit(`/#/agency`);
|
|
||||||
cy.get(':nth-child(1) > :nth-child(1) > .card-list-body > .list-items').click();
|
|
||||||
cy.get('[href="#/agency/11/workCenter"] > .q-item__section--main').click();
|
|
||||||
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
||||||
cy.get(
|
cy.get(
|
||||||
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
|
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
|
||||||
|
@ -17,8 +14,6 @@ describe('AgencyWorkCenter', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('delete workCenter', () => {
|
it('delete workCenter', () => {
|
||||||
cy.get(':nth-child(1) > :nth-child(1) > .card-list-body > .list-items').click();
|
|
||||||
cy.get('[href="#/agency/11/workCenter"] > .q-item__section--main').click();
|
|
||||||
cy.get('.q-item__section--side > .q-btn > .q-btn__content > .q-icon').click();
|
cy.get('.q-item__section--side > .q-btn > .q-btn__content > .q-icon').click();
|
||||||
cy.get('.q-notification__message').should(
|
cy.get('.q-notification__message').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
|
@ -27,9 +22,6 @@ describe('AgencyWorkCenter', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('error on duplicate workCenter', () => {
|
it('error on duplicate workCenter', () => {
|
||||||
cy.visit(`/#/agency`);
|
|
||||||
cy.get(':nth-child(1) > :nth-child(1) > .card-list-body > .list-items').click();
|
|
||||||
cy.get('[href="#/agency/11/workCenter"] > .q-item__section--main').click();
|
|
||||||
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
||||||
cy.get(
|
cy.get(
|
||||||
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
|
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container'
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
describe('InvoiceInDescriptor', () => {
|
describe('InvoiceInDescriptor', () => {
|
||||||
const dialogBtns = '.q-card__actions button';
|
const dialogBtns = '.q-card__actions button';
|
||||||
const firstDescritorOpt = '.q-menu > .q-list > :nth-child(1) > .q-item__section';
|
const firstDescritorOpt = '.q-menu > .q-list > :nth-child(1) > .q-item__section';
|
||||||
const isBookedField =
|
const isBookedField = '.q-card:nth-child(3) .vn-label-value:nth-child(5) .q-checkbox';
|
||||||
'.q-card:nth-child(3) .vn-label-value:nth-child(5) > .value > span';
|
|
||||||
|
|
||||||
it('should booking and unbooking the invoice properly', () => {
|
it('should booking and unbooking the invoice properly', () => {
|
||||||
cy.viewport(1280, 720);
|
cy.viewport(1280, 720);
|
||||||
|
@ -12,10 +11,10 @@ describe('InvoiceInDescriptor', () => {
|
||||||
cy.openActionsDescriptor();
|
cy.openActionsDescriptor();
|
||||||
cy.get(firstDescritorOpt).click();
|
cy.get(firstDescritorOpt).click();
|
||||||
cy.get(dialogBtns).eq(1).click();
|
cy.get(dialogBtns).eq(1).click();
|
||||||
cy.get(isBookedField).should('have.attr', 'title', 'true');
|
cy.get(isBookedField).should('have.attr', 'aria-checked', 'true');
|
||||||
|
|
||||||
cy.get(firstDescritorOpt).click();
|
cy.get(firstDescritorOpt).click();
|
||||||
cy.get(dialogBtns).eq(1).click();
|
cy.get(dialogBtns).eq(1).click();
|
||||||
cy.get(isBookedField).should('have.attr', 'title', 'false');
|
cy.get(isBookedField).should('have.attr', 'aria-checked', 'false');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,13 +3,10 @@ describe('VnSearchBar', () => {
|
||||||
const employeeId = ' #1';
|
const employeeId = ' #1';
|
||||||
const salesPersonId = ' #18';
|
const salesPersonId = ' #18';
|
||||||
const idGap = '.q-item > .q-item__label';
|
const idGap = '.q-item > .q-item__label';
|
||||||
const cardList = '.vn-card-list';
|
const vnTableRow = '.q-virtual-scroll__content';
|
||||||
|
|
||||||
let url;
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.visit('#/customer/list');
|
cy.visit('#/customer/list');
|
||||||
cy.url().then((currentUrl) => (url = currentUrl));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect to customer summary page', () => {
|
it('should redirect to customer summary page', () => {
|
||||||
|
@ -19,12 +16,12 @@ describe('VnSearchBar', () => {
|
||||||
|
|
||||||
it('should stay on the list page if there are several results or none', () => {
|
it('should stay on the list page if there are several results or none', () => {
|
||||||
cy.writeSearchbar('salesA{enter}');
|
cy.writeSearchbar('salesA{enter}');
|
||||||
checkCardListAndUrl(2);
|
checkTableLength(2);
|
||||||
|
|
||||||
cy.clearSearchbar();
|
cy.clearSearchbar();
|
||||||
|
|
||||||
cy.writeSearchbar('0{enter}');
|
cy.writeSearchbar('0{enter}');
|
||||||
checkCardListAndUrl(0);
|
checkTableLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchAndCheck = (searchTerm, expectedText) => {
|
const searchAndCheck = (searchTerm, expectedText) => {
|
||||||
|
@ -33,10 +30,7 @@ describe('VnSearchBar', () => {
|
||||||
cy.get(idGap).should('have.text', expectedText);
|
cy.get(idGap).should('have.text', expectedText);
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkCardListAndUrl = (expectedLength) => {
|
const checkTableLength = (expectedLength) => {
|
||||||
cy.get(cardList).then(($cardList) => {
|
cy.get(vnTableRow).find('tr').should('have.length', expectedLength);
|
||||||
expect($cardList.find('.q-card').length).to.equal(expectedLength);
|
|
||||||
cy.url().then((currentUrl) => expect(currentUrl).to.contain(url));
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue