297 lines
9.4 KiB
Vue
297 lines
9.4 KiB
Vue
<script setup>
|
|
import { computed, ref } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useQuasar } from 'quasar';
|
|
import { useRouter } from 'vue-router';
|
|
|
|
import VnSmsDialog from 'components/common/VnSmsDialog.vue';
|
|
import TicketEditManaProxy from './TicketEditMana.vue';
|
|
import VnInput from 'src/components/common/VnInput.vue';
|
|
|
|
import useNotify from 'src/composables/useNotify.js';
|
|
import axios from 'axios';
|
|
import { toDateFormat } from 'src/filters/date';
|
|
import { useAcl } from 'src/composables/useAcl';
|
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
|
|
|
const emit = defineEmits(['updateDiscounts', 'getMana', 'refreshTable']);
|
|
|
|
const props = defineProps({
|
|
disable: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
isTicketEditable: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
ticket: {
|
|
type: Object,
|
|
required: true,
|
|
default: () => {},
|
|
},
|
|
sales: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
mana: {
|
|
type: Number,
|
|
default: null,
|
|
},
|
|
ticketConfig: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
});
|
|
|
|
const { push } = useRouter();
|
|
const { t } = useI18n();
|
|
const { dialog } = useQuasar();
|
|
const { notify } = useNotify();
|
|
const acl = useAcl();
|
|
const btnDropdownRef = ref(null);
|
|
const { openConfirmationModal } = useVnConfirm();
|
|
|
|
const newDiscount = ref(null);
|
|
const ticket = computed(() => props.ticket);
|
|
const isClaimable = computed(() => {
|
|
if (ticket.value) {
|
|
const landedPlusWeek = new Date(ticket.value.landed);
|
|
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
|
|
const createAfterDeadline = acl.hasAny([
|
|
{ model: 'Claim', props: 'createAfterDeadline', accessType: 'WRITE' },
|
|
]);
|
|
return landedPlusWeek >= Date.vnNew() || createAfterDeadline;
|
|
}
|
|
return false;
|
|
});
|
|
const sendSms = async (params) => {
|
|
await axios.post(`Tickets/${ticket.value.id}/sendSms`, params);
|
|
notify(t('SMS sent'), 'positive');
|
|
};
|
|
|
|
const showSmsDialog = (template) => {
|
|
const address = ticket.value.address;
|
|
const client = ticket.value.client;
|
|
const phone = address.mobile || address.phone || client.mobile || client.phone;
|
|
const items = props.sales.map((sale) => {
|
|
return `${sale.quantity} ${sale.concept}`;
|
|
});
|
|
|
|
const notAvailables = items.join(', ');
|
|
|
|
const data = {
|
|
ticketId: ticket.value.id,
|
|
destinationFk: ticket.value.clientFk,
|
|
destination: phone,
|
|
ticketFk: ticket.value.id,
|
|
created: ticket.value.updated,
|
|
landed: toDateFormat(ticket.value.landed),
|
|
notAvailables,
|
|
};
|
|
|
|
dialog({
|
|
component: VnSmsDialog,
|
|
componentProps: {
|
|
phone: phone,
|
|
template: template,
|
|
locale: client?.user?.lang ?? 'default_locale',
|
|
data: data,
|
|
promise: sendSms,
|
|
},
|
|
});
|
|
};
|
|
|
|
const calculateSalePrice = async () => {
|
|
if (!props.sales) return;
|
|
|
|
await axios.post(`Sales/recalculatePrice`, props.sales);
|
|
notify(t('globals.dataSaved'), 'positive');
|
|
emit('refreshTable', props.sales);
|
|
};
|
|
|
|
const changeMultipleDiscount = () => {
|
|
const hasChanges = props.sales.some((sale) => {
|
|
return sale.discount != newDiscount.value;
|
|
});
|
|
|
|
if (newDiscount.value != null && hasChanges)
|
|
emit('updateDiscounts', props.sales, newDiscount.value);
|
|
btnDropdownRef.value.hide();
|
|
};
|
|
|
|
const createClaim = () => {
|
|
const today = new Date();
|
|
today.setHours(0, 0, 0, 0);
|
|
const timeDifference = today.getTime() - new Date(ticket.value.landed).getTime();
|
|
const pastDays = Math.floor(timeDifference / 86400000);
|
|
if (pastDays >= props.ticketConfig[0].daysForWarningClaim)
|
|
openConfirmationModal(
|
|
t('Claim out of time'),
|
|
t('Do you want to continue?'),
|
|
onCreateClaimAccepted,
|
|
);
|
|
else
|
|
openConfirmationModal(
|
|
t('Do you want to create a claim?'),
|
|
false,
|
|
onCreateClaimAccepted,
|
|
);
|
|
};
|
|
|
|
const onCreateClaimAccepted = async () => {
|
|
const params = { ticketId: ticket.value.id, sales: props.sales };
|
|
const { data } = await axios.post(`Claims/createFromSales`, params);
|
|
push({ name: 'ClaimBasicData', params: { id: data.id } });
|
|
};
|
|
|
|
const createRefund = async (withWarehouse) => {
|
|
if (!props.ticket) return;
|
|
|
|
const params = {
|
|
ticketsIds: [props.ticket.id],
|
|
withWarehouse: withWarehouse,
|
|
negative: true,
|
|
};
|
|
|
|
const { data } = await axios.post('Tickets/cloneAll', params);
|
|
const [refundTicket] = data;
|
|
notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
|
|
push({ name: 'TicketSale', params: { id: refundTicket.id } });
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<QBtnDropdown
|
|
ref="btnDropdownRef"
|
|
color="primary"
|
|
:label="t('ticketSale.more')"
|
|
:disable="disable"
|
|
data-cy="ticketSaleMoreActionsDropdown"
|
|
>
|
|
<template #label>
|
|
<QTooltip>{{ t('Select lines to see the options') }}</QTooltip>
|
|
</template>
|
|
<QList>
|
|
<QItem
|
|
v-if="ticket"
|
|
clickable
|
|
v-close-popup
|
|
v-ripple
|
|
@click="showSmsDialog('productNotAvailable')"
|
|
data-cy="sendShortageSMSItem"
|
|
>
|
|
<QItemSection>
|
|
<QItemLabel>{{ t('Send shortage SMS') }}</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
<QItem
|
|
v-if="isTicketEditable"
|
|
clickable
|
|
v-close-popup
|
|
v-ripple
|
|
@click="calculateSalePrice()"
|
|
data-cy="recalculatePriceItem"
|
|
>
|
|
<QItemSection>
|
|
<QItemLabel>{{ t('Recalculate price') }}</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
<QItem
|
|
clickable
|
|
v-ripple
|
|
@click="emit('getMana')"
|
|
data-cy="updateDiscountItem"
|
|
>
|
|
<QItemSection>
|
|
<QItemLabel>{{ t('Update discount') }}</QItemLabel>
|
|
</QItemSection>
|
|
<TicketEditManaProxy :mana="props.mana" @save="changeMultipleDiscount()">
|
|
<VnInput
|
|
v-model.number="newDiscount"
|
|
:label="t('ticketSale.discount')"
|
|
type="number"
|
|
data-cy="ticketSaleDiscountInput"
|
|
/>
|
|
</TicketEditManaProxy>
|
|
</QItem>
|
|
<QItem
|
|
v-if="isClaimable"
|
|
clickable
|
|
v-close-popup
|
|
v-ripple
|
|
@click="createClaim()"
|
|
data-cy="createClaimItem"
|
|
>
|
|
<QItemSection>
|
|
<QItemLabel>{{ t('Add claim') }}</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
<QItem
|
|
v-if="isTicketEditable"
|
|
clickable
|
|
v-close-popup
|
|
v-ripple
|
|
@click="setReserved(true)"
|
|
data-cy="markAsReservedItem"
|
|
>
|
|
<QItemSection>
|
|
<QItemLabel>{{ t('Mark as reserved') }}</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
<QItem clickable v-ripple data-cy="ticketSaleRefundItem">
|
|
<QItemSection>
|
|
<QItemLabel>{{ t('Refund') }}</QItemLabel>
|
|
</QItemSection>
|
|
<QItemSection side>
|
|
<QIcon name="keyboard_arrow_right" />
|
|
</QItemSection>
|
|
<QMenu anchor="top end" self="top start" auto-close bordered>
|
|
<QList>
|
|
<QItem
|
|
v-ripple
|
|
clickable
|
|
@click="createRefund(true)"
|
|
data-cy="ticketSaleRefundWithWarehouse"
|
|
>
|
|
<QItemSection>
|
|
{{ t('with warehouse') }}
|
|
</QItemSection>
|
|
</QItem>
|
|
<QItem
|
|
v-ripple
|
|
clickable
|
|
@click="createRefund(false)"
|
|
data-cy="ticketSaleRefundWithoutWarehouse"
|
|
>
|
|
<QItemSection>
|
|
{{ t('without warehouse') }}
|
|
</QItemSection>
|
|
</QItem>
|
|
</QList>
|
|
</QMenu>
|
|
</QItem>
|
|
</QList>
|
|
</QBtnDropdown>
|
|
</template>
|
|
|
|
<i18n>
|
|
en:
|
|
refundTicketCreated: 'The following refund ticket have been created {ticketId}'
|
|
es:
|
|
SMS sent: SMS enviado
|
|
Send shortage SMS: Enviar SMS faltas
|
|
Recalculate price: Recalcular precio
|
|
Update discount: Actualizar descuento
|
|
Add claim: Crear reclamación
|
|
Mark as reserved: Marcar como reservado
|
|
Unmark as reserved: Desmarcar como reservado
|
|
Refund: Abono
|
|
with warehouse: con almacén
|
|
without warehouse: sin almacén
|
|
Claim out of time: Reclamación fuera de plazo
|
|
Do you want to continue?: ¿Desea continuar?
|
|
Do you want to create a claim?: ¿Quieres crear una reclamación?
|
|
refundTicketCreated: 'The following refund ticket have been created: {ticketId}'
|
|
</i18n>
|