7167-testToMaster_2414 #266
|
@ -0,0 +1,153 @@
|
||||||
|
<script setup>
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const MESSAGE_MAX_LENGTH = 160;
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const props = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
destination: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
destinationFk: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits([...useDialogPluginComponent.emits, 'sent']);
|
||||||
|
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||||
|
|
||||||
|
const smsRules = [
|
||||||
|
(val) => (val && val.length > 0) || t("The message can't be empty"),
|
||||||
|
(val) =>
|
||||||
|
(val && new Blob([val]).size <= MESSAGE_MAX_LENGTH) ||
|
||||||
|
t("The message it's too long"),
|
||||||
|
];
|
||||||
|
|
||||||
|
const message = ref('');
|
||||||
|
|
||||||
|
const charactersRemaining = computed(
|
||||||
|
() => MESSAGE_MAX_LENGTH - new Blob([message.value]).size
|
||||||
|
);
|
||||||
|
|
||||||
|
const charactersChipColor = computed(() => {
|
||||||
|
if (charactersRemaining.value < 0) {
|
||||||
|
return 'negative';
|
||||||
|
}
|
||||||
|
if (charactersRemaining.value <= 25) {
|
||||||
|
return 'warning';
|
||||||
|
}
|
||||||
|
return 'primary';
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
if (!props.destination) {
|
||||||
|
throw new Error(`The destination can't be empty`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.value) {
|
||||||
|
throw new Error(`The message can't be empty`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charactersRemaining.value < 0) {
|
||||||
|
throw new Error(`The message it's too long`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post(props.url, {
|
||||||
|
destination: props.destination,
|
||||||
|
destinationFk: props.destinationFk,
|
||||||
|
message: message.value,
|
||||||
|
...props.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data) {
|
||||||
|
emit('sent', response.data);
|
||||||
|
}
|
||||||
|
emit('ok', response.data);
|
||||||
|
emit('hide', response.data);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QDialog ref="dialogRef" @hide="onDialogHide">
|
||||||
|
<QCard class="full-width dialog">
|
||||||
|
<QCardSection class="row">
|
||||||
|
<span v-if="title" class="text-h6">{{ title }}</span>
|
||||||
|
<QSpace />
|
||||||
|
<QBtn icon="close" flat round dense v-close-popup />
|
||||||
|
</QCardSection>
|
||||||
|
<QForm @submit="onSubmit">
|
||||||
|
<QCardSection>
|
||||||
|
<VnInput
|
||||||
|
v-model="message"
|
||||||
|
type="textarea"
|
||||||
|
:rules="smsRules"
|
||||||
|
:label="t('Message')"
|
||||||
|
:placeholder="t('Message')"
|
||||||
|
:rows="5"
|
||||||
|
required
|
||||||
|
clearable
|
||||||
|
no-error-icon
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info">
|
||||||
|
<QTooltip>
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
'Special characters like accents counts as a multiple'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template>
|
||||||
|
</VnInput>
|
||||||
|
<p class="q-mb-none q-mt-md">
|
||||||
|
{{ t('Characters remaining') }}:
|
||||||
|
<QChip :color="charactersChipColor">
|
||||||
|
{{ charactersRemaining }}
|
||||||
|
</QChip>
|
||||||
|
</p>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardActions align="right">
|
||||||
|
<QBtn type="button" flat v-close-popup class="text-primary">
|
||||||
|
{{ t('globals.cancel') }}
|
||||||
|
</QBtn>
|
||||||
|
<QBtn type="submit" color="primary">{{ t('Send') }}</QBtn>
|
||||||
|
</QCardActions>
|
||||||
|
</QForm>
|
||||||
|
</QCard>
|
||||||
|
</QDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.dialog {
|
||||||
|
max-width: 450px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Message: Mensaje
|
||||||
|
Send: Enviar
|
||||||
|
Characters remaining: Carácteres restantes
|
||||||
|
Special characters like accents counts as a multiple: Carácteres especiales como los acentos cuentan como varios
|
||||||
|
The destination can't be empty: El destinatario no puede estar vacio
|
||||||
|
The message can't be empty: El mensaje no puede estar vacio
|
||||||
|
The message it's too long: El mensaje es demasiado largo
|
||||||
|
</i18n>
|
|
@ -1,11 +1,11 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useDialogPluginComponent, useQuasar } from 'quasar';
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { computed, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
|
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
import TicketDescriptorProxy from "pages/Ticket/Card/TicketDescriptorProxy.vue";
|
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -19,7 +19,7 @@ const emit = defineEmits([...useDialogPluginComponent.emits]);
|
||||||
|
|
||||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = ref([
|
||||||
{
|
{
|
||||||
name: 'ticket',
|
name: 'ticket',
|
||||||
label: t('Ticket'),
|
label: t('Ticket'),
|
||||||
|
|
|
@ -7,15 +7,17 @@ import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { QIcon, useQuasar } from 'quasar';
|
import { QIcon, useQuasar } from 'quasar';
|
||||||
import { useSession } from 'composables/useSession';
|
|
||||||
import RouteListTicketsDialog from 'pages/Route/Card/RouteListTicketsDialog.vue';
|
import RouteListTicketsDialog from 'pages/Route/Card/RouteListTicketsDialog.vue';
|
||||||
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
|
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
|
||||||
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
|
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import { openBuscaman } from 'src/utils/buscaman';
|
||||||
|
import SendSmsDialog from 'components/common/SendSmsDialog.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const session = useSession();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const selectedRows = ref([]);
|
const selectedRows = ref([]);
|
||||||
|
@ -102,6 +104,8 @@ const columns = computed(() => [
|
||||||
const refreshKey = ref(0);
|
const refreshKey = ref(0);
|
||||||
const confirmationDialog = ref(false);
|
const confirmationDialog = ref(false);
|
||||||
const startingDate = ref(null);
|
const startingDate = ref(null);
|
||||||
|
const routeEntity = ref(null);
|
||||||
|
const ticketList = ref([]);
|
||||||
|
|
||||||
const cloneRoutes = () => {
|
const cloneRoutes = () => {
|
||||||
axios.post('Routes/clone', {
|
axios.post('Routes/clone', {
|
||||||
|
@ -112,31 +116,54 @@ const cloneRoutes = () => {
|
||||||
startingDate.value = null;
|
startingDate.value = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const showRouteReport = () => {
|
const deletePriorities = async () => {
|
||||||
const ids = selectedRows.value.map((row) => row?.id);
|
try {
|
||||||
const idString = ids.join(',');
|
await Promise.all(
|
||||||
let url;
|
selectedRows.value.map((ticket) =>
|
||||||
|
axios.patch(`Tickets/${ticket?.id}/`, { priority: null })
|
||||||
if (selectedRows.value.length <= 1) {
|
)
|
||||||
url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getToken()}`;
|
);
|
||||||
} else {
|
} finally {
|
||||||
const params = new URLSearchParams({
|
refreshKey.value++;
|
||||||
access_token: session.getToken(),
|
|
||||||
id: idString,
|
|
||||||
});
|
|
||||||
url = `api/Routes/downloadZip?${params.toString()}`;
|
|
||||||
}
|
}
|
||||||
window.open(url, '_blank');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const markAsServed = () => {
|
const setOrderedPriority = async () => {
|
||||||
selectedRows.value.forEach((row) => {
|
try {
|
||||||
if (row?.id) {
|
await Promise.all(
|
||||||
axios.patch(`Routes/${row?.id}`, { isOk: true });
|
ticketList.value.map((ticket, index) =>
|
||||||
}
|
axios.patch(`Tickets/${ticket?.id}/`, { priority: index + 1 })
|
||||||
});
|
)
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
refreshKey.value++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortRoutes = async () => {
|
||||||
|
await axios.get(`Routes/${route.params?.id}/guessPriority/`);
|
||||||
refreshKey.value++;
|
refreshKey.value++;
|
||||||
startingDate.value = null;
|
};
|
||||||
|
|
||||||
|
const updatePriority = async (ticket, priority = null) => {
|
||||||
|
return axios.patch(`Tickets/${ticket?.id}/`, {
|
||||||
|
priority: priority || ticket?.priority,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setHighestPriority = async (ticket, ticketList) => {
|
||||||
|
const highestPriority = Math.max(...ticketList.map((item) => item.priority)) + 1;
|
||||||
|
if (highestPriority - 1 !== ticket.priority) {
|
||||||
|
const response = await updatePriority(ticket, highestPriority);
|
||||||
|
ticket.priority = response.data.priority;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToBuscaman = async (ticket = null) => {
|
||||||
|
await openBuscaman(
|
||||||
|
routeEntity.value?.vehicleFk,
|
||||||
|
ticket ? [ticket] : selectedRows.value
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openTicketsDialog = () => {
|
const openTicketsDialog = () => {
|
||||||
|
@ -149,9 +176,57 @@ const openTicketsDialog = () => {
|
||||||
})
|
})
|
||||||
.onOk(() => refreshKey.value++);
|
.onOk(() => refreshKey.value++);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const removeTicket = async (ticket) => {
|
||||||
|
await axios.patch(`Tickets/${ticket?.id}/`, { routeFk: null });
|
||||||
|
await axios.post(`Routes/${route?.params?.id}/updateVolume`);
|
||||||
|
refreshKey.value++;
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmRemove = (ticket) => {
|
||||||
|
quasar
|
||||||
|
.dialog({
|
||||||
|
component: VnConfirm,
|
||||||
|
componentProps: {
|
||||||
|
title: t('confirmDeletion'),
|
||||||
|
message: t('confirmDeletionMessage'),
|
||||||
|
promise: () => removeTicket(ticket),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.onOk(() => refreshKey.value++);
|
||||||
|
};
|
||||||
|
|
||||||
|
const openSmsDialog = async () => {
|
||||||
|
const clientsId = [];
|
||||||
|
const clientsPhone = [];
|
||||||
|
|
||||||
|
for (let ticket of selectedRows.value) {
|
||||||
|
clientsId.push(ticket?.clientFk);
|
||||||
|
const { data: client } = await axios.get(`Clients/${ticket?.clientFk}`);
|
||||||
|
clientsPhone.push(client.phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
quasar.dialog({
|
||||||
|
component: SendSmsDialog,
|
||||||
|
componentProps: {
|
||||||
|
title: t('Send SMS to the selected tickets'),
|
||||||
|
url: 'Routes/sendSms',
|
||||||
|
destinationFk: clientsId.toString(),
|
||||||
|
destination: clientsPhone.toString(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<FetchData
|
||||||
|
@on-fetch="(data) => (routeEntity = data)"
|
||||||
|
auto-load
|
||||||
|
:url="`Routes/${route.params?.id}`"
|
||||||
|
:filter="{
|
||||||
|
fields: ['vehicleFk'],
|
||||||
|
}"
|
||||||
|
/>
|
||||||
<QDialog v-model="confirmationDialog">
|
<QDialog v-model="confirmationDialog">
|
||||||
<QCard style="min-width: 350px">
|
<QCard style="min-width: 350px">
|
||||||
<QCardSection>
|
<QCardSection>
|
||||||
|
@ -176,32 +251,47 @@ const openTicketsDialog = () => {
|
||||||
<QPage class="column items-center">
|
<QPage class="column items-center">
|
||||||
<QToolbar class="bg-vn-dark justify-end">
|
<QToolbar class="bg-vn-dark justify-end">
|
||||||
<div id="st-actions" class="q-pa-sm">
|
<div id="st-actions" class="q-pa-sm">
|
||||||
<QBtn
|
<QBtn icon="vn:wand" color="primary" class="q-mr-sm" @click="sortRoutes">
|
||||||
icon="vn:clone"
|
<QTooltip>{{ t('Sort routes') }}</QTooltip>
|
||||||
color="primary"
|
|
||||||
class="q-mr-sm"
|
|
||||||
:disable="!selectedRows?.length"
|
|
||||||
@click="confirmationDialog = true"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('Clone Selected Routes') }}</QTooltip>
|
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QBtn
|
<QBtn
|
||||||
icon="cloud_download"
|
icon="vn:buscaman"
|
||||||
color="primary"
|
color="primary"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
:disable="!selectedRows?.length"
|
:disable="!selectedRows?.length"
|
||||||
@click="showRouteReport"
|
@click="goToBuscaman()"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('Download selected routes as PDF') }}</QTooltip>
|
<QTooltip>{{ t('Open buscaman') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QBtn
|
<QBtn
|
||||||
icon="check"
|
icon="filter_alt"
|
||||||
color="primary"
|
color="primary"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
:disable="!selectedRows?.length"
|
:disable="!selectedRows?.length"
|
||||||
@click="markAsServed"
|
@click="deletePriorities"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('Mark as served') }}</QTooltip>
|
<QTooltip>{{ t('Delete priority') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn
|
||||||
|
icon="format_list_numbered"
|
||||||
|
color="primary"
|
||||||
|
class="q-mr-sm"
|
||||||
|
@click="setOrderedPriority"
|
||||||
|
>
|
||||||
|
<QTooltip
|
||||||
|
>{{
|
||||||
|
t('Renumber all tickets in the order you see on the screen')
|
||||||
|
}}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn
|
||||||
|
icon="sms"
|
||||||
|
color="primary"
|
||||||
|
class="q-mr-sm"
|
||||||
|
:disable="!selectedRows?.length"
|
||||||
|
@click="openSmsDialog"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('Send SMS to all clients') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</div>
|
</div>
|
||||||
</QToolbar>
|
</QToolbar>
|
||||||
|
@ -213,6 +303,7 @@ const openTicketsDialog = () => {
|
||||||
:filter="{ id: route.params.id }"
|
:filter="{ id: route.params.id }"
|
||||||
:order="['priority ASC']"
|
:order="['priority ASC']"
|
||||||
auto-load
|
auto-load
|
||||||
|
@on-fetch="(data) => (ticketList = data)"
|
||||||
>
|
>
|
||||||
<template #body="{ rows }">
|
<template #body="{ rows }">
|
||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
|
@ -228,19 +319,30 @@ const openTicketsDialog = () => {
|
||||||
>
|
>
|
||||||
<template #body-cell-order="{ row }">
|
<template #body-cell-order="{ row }">
|
||||||
<QTd class="order-field">
|
<QTd class="order-field">
|
||||||
<VnInput
|
<div class="flex no-wrap items-center">
|
||||||
v-model="row.priority"
|
<QIcon
|
||||||
is-outlined
|
name="low_priority"
|
||||||
/>
|
size="xs"
|
||||||
|
class="q-mr-md cursor-pointer"
|
||||||
|
color="primary"
|
||||||
|
@click="setHighestPriority(row, rows)"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
v-model="row.priority"
|
||||||
|
is-outlined
|
||||||
|
@blur="updatePriority(row)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell-city="{ value, row }">
|
<template #body-cell-city="{ value, row }">
|
||||||
<QTd auto-width>
|
<QTd auto-width>
|
||||||
<span
|
<span
|
||||||
class="text-primary cursor-pointer"
|
class="text-primary cursor-pointer"
|
||||||
@click="openBuscaman(entity?.route, row)"
|
@click="goToBuscaman(row)"
|
||||||
>
|
>
|
||||||
{{ value }}
|
{{ value }}
|
||||||
|
<QTooltip>{{ t('Open buscaman') }}</QTooltip>
|
||||||
</span>
|
</span>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
|
@ -260,7 +362,7 @@ const openTicketsDialog = () => {
|
||||||
</span>
|
</span>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell-observations="{ value }">
|
<template #body-cell-observations="{ value, row }">
|
||||||
<QTd auto-width>
|
<QTd auto-width>
|
||||||
<div class="flex items-center no-wrap table-actions">
|
<div class="flex items-center no-wrap table-actions">
|
||||||
<QIcon
|
<QIcon
|
||||||
|
@ -268,6 +370,7 @@ const openTicketsDialog = () => {
|
||||||
color="primary"
|
color="primary"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
@click="confirmRemove(row)"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('globals.remove') }}</QTooltip>
|
<QTooltip>{{ t('globals.remove') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
|
@ -303,7 +406,8 @@ const openTicketsDialog = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-field {
|
.order-field {
|
||||||
max-width: 50px;
|
max-width: 140px;
|
||||||
|
min-width: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-actions {
|
.table-actions {
|
||||||
|
@ -313,6 +417,8 @@ const openTicketsDialog = () => {
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
newRoute: New Route
|
newRoute: New Route
|
||||||
|
confirmDeletion: Confirm deletion
|
||||||
|
confirmDeletionMessage: Are you sure you want to delete this ticket?
|
||||||
es:
|
es:
|
||||||
Order: Orden
|
Order: Orden
|
||||||
Street: Dirección fiscal
|
Street: Dirección fiscal
|
||||||
|
@ -322,4 +428,13 @@ es:
|
||||||
Warehouse: Almacén
|
Warehouse: Almacén
|
||||||
Packages: Bultos
|
Packages: Bultos
|
||||||
Packaging: Encajado
|
Packaging: Encajado
|
||||||
|
confirmDeletion: Confirmar eliminación
|
||||||
|
confirmDeletionMessage: Seguro que quieres eliminar este ticket?
|
||||||
|
Sort routes: Ordenar rutas
|
||||||
|
Open buscaman: Abrir buscaman
|
||||||
|
Delete priority: Borrar orden
|
||||||
|
Renumber all tickets in the order you see on the screen: Renumerar todos los tickets con el orden que ves por pantalla
|
||||||
|
Assign highest priority: Asignar máxima prioridad
|
||||||
|
Send SMS to all clients: Mandar sms a todos los clientes de las rutas
|
||||||
|
Send SMS to the selected tickets: Enviar SMS a los tickets seleccionados
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const BUSCAMAN_URL = 'https://gps.buscalia.com/usuario/localizar.aspx?bmi=true&addr=';
|
||||||
|
|
||||||
|
export async function openBuscaman(vehicleId, tickets) {
|
||||||
|
if (!vehicleId) throw new Error(`The route doesn't have a vehicle`);
|
||||||
|
|
||||||
|
const response = await axios.get(`Routes/${vehicleId}/getDeliveryPoint`);
|
||||||
|
|
||||||
|
if (!response.data) {
|
||||||
|
throw new Error(`The route's vehicle doesn't have a delivery point`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let addresses = response.data;
|
||||||
|
tickets.forEach((ticket, index) => {
|
||||||
|
const previousLine = tickets[index - 1] ? tickets[index - 1].street : null;
|
||||||
|
if (previousLine !== tickets.street) {
|
||||||
|
addresses += `+to:${ticket.postalCode} ${ticket.city} ${ticket.street}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.open(BUSCAMAN_URL + encodeURI(addresses), '_blank');
|
||||||
|
}
|
Loading…
Reference in New Issue