forked from verdnatura/salix-front
Btn dropdown more actions
This commit is contained in:
parent
8c3262bcdf
commit
0666aeb166
|
@ -184,6 +184,7 @@ en:
|
|||
minAmount: 'A minimum amount of 50€ (VAT excluded) is required for your order
|
||||
{ orderId } of { shipped } to receive it without additional shipping costs.'
|
||||
orderChanges: 'Order {orderId} of { shipped }: { changes }'
|
||||
productNotAvailable: 'Verdnatura communicates: Your order {ticketFk} with reception date on {landed}. {notAvailables} not available. Sorry for the inconvenience.'
|
||||
en: English
|
||||
es: Spanish
|
||||
fr: French
|
||||
|
@ -203,6 +204,7 @@ es:
|
|||
Te recomendamos amplíes para no generar costes extra, provocarán un incremento de tu tarifa.
|
||||
¡Un saludo!'
|
||||
orderChanges: 'Pedido {orderId} con llegada estimada día { landing }: { changes }'
|
||||
productNotAvailable: 'Verdnatura le comunica: Pedido {ticketFk} con fecha de recepción {landed}. {notAvailables} no disponible/s. Disculpe las molestias.'
|
||||
en: Inglés
|
||||
es: Español
|
||||
fr: Francés
|
||||
|
@ -222,6 +224,7 @@ fr:
|
|||
Montant minimum nécessaire de 50 euros pour recevoir la commande { orderId } livraison { landing }.
|
||||
Merci.'
|
||||
orderChanges: 'Commande {orderId} livraison {landing} indisponible/s. Désolés pour le dérangement.'
|
||||
productNotAvailable: 'Verdnatura communique : Votre commande {ticketFk} avec date de réception le {landed}. {notAvailables} non disponible. Nous sommes désolés pour les inconvénients.'
|
||||
en: Anglais
|
||||
es: Espagnol
|
||||
fr: Français
|
||||
|
@ -240,7 +243,7 @@ pt:
|
|||
minAmount: 'É necessário um valor mínimo de 50€ (sem IVA) em seu pedido
|
||||
{ orderId } do dia { landing } para recebê-lo sem custos de envio adicionais.'
|
||||
orderChanges: 'Pedido { orderId } com chegada dia { landing }: { changes }'
|
||||
en: Inglês
|
||||
productNotAvailable: 'Verdnatura comunica: Seu pedido {ticketFk} com data de recepção em {landed}. {notAvailables} não disponível/eis. Desculpe pelo transtorno.'
|
||||
es: Espanhol
|
||||
fr: Francês
|
||||
pt: Português
|
||||
|
|
|
@ -5,10 +5,6 @@ import { useI18n } from 'vue-i18n';
|
|||
import { toCurrency } from 'src/filters';
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
mana: {
|
||||
type: Number,
|
||||
default: null,
|
||||
|
@ -38,16 +34,16 @@ const cancel = () => {
|
|||
<template>
|
||||
<QPopupProxy ref="QPopupProxyRef">
|
||||
<div class="container">
|
||||
<QSpinner v-if="!$props.mana" color="orange" size="md" />
|
||||
<QSpinner v-if="!mana" color="orange" size="md" />
|
||||
<div v-else>
|
||||
<div class="header">Mana: {{ toCurrency($props.mana) }}</div>
|
||||
<div class="header">Mana: {{ toCurrency(mana) }}</div>
|
||||
<div class="q-pa-md">
|
||||
<slot />
|
||||
<div class="column items-center q-mt-lg">
|
||||
<div v-if="newPrice" class="column items-center q-mt-lg">
|
||||
<span class="text-primary">{{ t('New price') }}</span>
|
||||
<span class="text-subtitle1">{{
|
||||
toCurrency($props.newPrice)
|
||||
}}</span>
|
||||
<span class="text-subtitle1">
|
||||
{{ toCurrency($props.newPrice) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,6 +12,7 @@ import TicketEditManaProxy from './TicketEditMana.vue';
|
|||
import ItemPicture from 'src/components/ui/ItemPicture.vue';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import TicketSaleMoreActions from './TicketSaleMoreActions.vue';
|
||||
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useSession } from 'composables/useSession';
|
||||
|
@ -232,10 +233,10 @@ const getMana = async () => {
|
|||
await getUsesMana();
|
||||
};
|
||||
|
||||
const selectedValidSales = () => {
|
||||
const selectedValidSales = computed(() => {
|
||||
if (!sales.value) return;
|
||||
return selectedSales.value.filter((sale) => sale.id != undefined);
|
||||
};
|
||||
});
|
||||
|
||||
const onOpenEditPricePopover = async (sale) => {
|
||||
await getMana();
|
||||
|
@ -256,7 +257,7 @@ const onOpenEditDiscountPopover = async (sale) => {
|
|||
} else {
|
||||
edit.value = {
|
||||
discount: null,
|
||||
sales: selectedValidSales(),
|
||||
sales: selectedValidSales.value,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -281,16 +282,17 @@ const changeDiscount = (sale) => {
|
|||
if (newDiscount != null && newDiscount != sale.discount) updateDiscount([sale]);
|
||||
};
|
||||
|
||||
const updateDiscount = async (sales) => {
|
||||
const updateDiscount = async (sales, newDiscount = null) => {
|
||||
const saleIds = sales.map((sale) => sale.id);
|
||||
const _newDiscount = newDiscount || edit.value.discount;
|
||||
const params = {
|
||||
salesIds: saleIds,
|
||||
newDiscount: edit.value.discount,
|
||||
newDiscount: _newDiscount,
|
||||
manaCode: manaCode.value,
|
||||
};
|
||||
await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
for (let sale of sales) sale.discount = edit.value.discount;
|
||||
for (let sale of sales) sale.discount = _newDiscount;
|
||||
edit.value = { ...DEFAULT_EDIT };
|
||||
};
|
||||
|
||||
|
@ -357,8 +359,7 @@ const removeSelectedSales = () => {
|
|||
|
||||
const removeSales = async () => {
|
||||
try {
|
||||
const sales = selectedValidSales();
|
||||
const params = { sales: sales, ticketId: store.data.id };
|
||||
const params = { sales: selectedValidSales.value, ticketId: store.data.id };
|
||||
await axios.post('Sales/deleteSales', params);
|
||||
removeSelectedSales();
|
||||
notify('globals.dataSaved', 'positive');
|
||||
|
@ -421,6 +422,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
|||
ref="stateBtnDropdownRef"
|
||||
color="primary"
|
||||
:label="t('ticketSale.state')"
|
||||
:disable="!isTicketEditable"
|
||||
>
|
||||
<VnSelect
|
||||
:options="editableStatesOptions"
|
||||
|
@ -432,6 +434,16 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
|||
@update:model-value="changeTicketState"
|
||||
/>
|
||||
</QBtnDropdown>
|
||||
<TicketSaleMoreActions
|
||||
:ticket="store.data"
|
||||
:is-ticket-editable="isTicketEditable"
|
||||
:sales="selectedValidSales"
|
||||
:disable="!selectedSales.length"
|
||||
:mana="mana"
|
||||
:ticket-config="ticketConfig"
|
||||
@get-mana="getMana()"
|
||||
@update-discounts="updateDiscount"
|
||||
/>
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="delete"
|
||||
|
@ -620,7 +632,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
|||
:mana="mana"
|
||||
:new-price="getNewPrice"
|
||||
@save="updatePrice(row)"
|
||||
@cancel="updatePrice(row)"
|
||||
>
|
||||
<VnInput
|
||||
v-model.number="edit.price"
|
||||
|
@ -647,7 +658,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
|||
:mana="mana"
|
||||
:new-price="getNewPrice"
|
||||
@save="changeDiscount(row)"
|
||||
@cancel="changeDiscount(row)"
|
||||
>
|
||||
<VnInput
|
||||
v-model.number="edit.discount"
|
||||
|
@ -709,4 +719,5 @@ es:
|
|||
Continue anyway?: ¿Continuar de todas formas?
|
||||
You are going to delete lines of the ticket: Vas a eliminar lineas del ticket
|
||||
Add item: Añadir artículo
|
||||
Select lines to see the options: Selecciona líneas para ver las opciones
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
<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 { useRole } from 'src/composables/useRole';
|
||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||
|
||||
const emit = defineEmits(['updateDiscounts', 'getMana']);
|
||||
|
||||
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 router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const { dialog } = useQuasar();
|
||||
const { notify } = useNotify();
|
||||
const role = useRole();
|
||||
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 hasClaimManagerRole = role.hasAny('claimManager');
|
||||
return landedPlusWeek >= Date.vnNew() || hasClaimManagerRole;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const hasReserves = computed(() => props.sales.some((sale) => sale.reserved == true));
|
||||
|
||||
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');
|
||||
};
|
||||
|
||||
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?'), onCreateClaimAccepted);
|
||||
};
|
||||
|
||||
const onCreateClaimAccepted = async () => {
|
||||
try {
|
||||
const params = { ticketId: ticket.value.id, sales: props.sales };
|
||||
const { data } = await axios.post(`Claims/createFromSales`, params);
|
||||
router.push({ name: 'ClaimBasicData', params: { id: data.id } });
|
||||
} catch (error) {
|
||||
console.error('Error creating claim: ', error);
|
||||
}
|
||||
};
|
||||
|
||||
const setReserved = async (reserved) => {
|
||||
const params = { ticketId: ticket.value.id, sales: props.sales, reserved: reserved };
|
||||
await axios.post(`Sales/reserve`, params);
|
||||
props.sales.forEach((sale) => {
|
||||
sale.reserved = reserved;
|
||||
});
|
||||
};
|
||||
|
||||
const createRefund = async (withWarehouse) => {
|
||||
if (!props.sales) return;
|
||||
|
||||
const salesIds = props.sales.map((sale) => sale.id);
|
||||
const params = { salesIds: salesIds, withWarehouse: withWarehouse, negative: true };
|
||||
const { data } = await axios.post('Sales/clone', params);
|
||||
const [refundTicket] = data;
|
||||
notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
|
||||
router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QBtnDropdown
|
||||
ref="btnDropdownRef"
|
||||
color="primary"
|
||||
:label="t('ticketSale.more')"
|
||||
:disable="disable"
|
||||
>
|
||||
<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')"
|
||||
>
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ t('Send shortage SMS') }}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="isTicketEditable"
|
||||
clickable
|
||||
v-close-popup
|
||||
v-ripple
|
||||
@click="calculateSalePrice()"
|
||||
>
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ t('Recalculate price') }}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem clickable v-ripple @click="emit('getMana')">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ t('Update discount') }}</QItemLabel>
|
||||
</QItemSection>
|
||||
<TicketEditManaProxy :mana="props.mana" @save="changeMultipleDiscount()">
|
||||
<VnInput
|
||||
v-model.number="newDiscount"
|
||||
:label="t('ticketSale.discount')"
|
||||
type="number"
|
||||
/>
|
||||
</TicketEditManaProxy>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="isClaimable"
|
||||
clickable
|
||||
v-close-popup
|
||||
v-ripple
|
||||
@click="createClaim()"
|
||||
>
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ t('Add claim') }}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="isTicketEditable"
|
||||
clickable
|
||||
v-close-popup
|
||||
v-ripple
|
||||
@click="setReserved(true)"
|
||||
>
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ t('Mark as reserved') }}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="isTicketEditable && hasReserves"
|
||||
clickable
|
||||
v-close-popup
|
||||
v-ripple
|
||||
@click="setReserved(false)"
|
||||
>
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ t('Unmark as reserved') }}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem clickable v-ripple>
|
||||
<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)">
|
||||
<QItemSection>
|
||||
{{ t('with warehouse') }}
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-ripple clickable @click="createRefund(false)">
|
||||
<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>
|
|
@ -18,3 +18,4 @@ ticketSale:
|
|||
hasComponentLack: Component lack
|
||||
ok: Ok
|
||||
state: State
|
||||
more: More
|
||||
|
|
|
@ -20,3 +20,4 @@ ticketSale:
|
|||
hasComponentLack: Faltan componentes
|
||||
ok: Ok
|
||||
state: Estado
|
||||
more: Más
|
||||
|
|
Loading…
Reference in New Issue