#7553 modified TicketExpedition & changes in ticket section #571

Merged
jon merged 79 commits from 7553_FixTicketExpedition into dev 2024-09-25 05:51:16 +00:00
15 changed files with 730 additions and 346 deletions
Showing only changes of commit 4a57c53c3d - Show all commits

View File

@ -49,6 +49,10 @@ const $props = defineProps({
type: Object, type: Object,
default: null, default: null,
}, },
bottom: {
type: Object,
default: null,
},
cardClass: { cardClass: {
type: String, type: String,
default: 'flex-one', default: 'flex-one',
@ -388,6 +392,11 @@ defineExpose({
@click="stateStore.toggleRightDrawer()" @click="stateStore.toggleRightDrawer()"
/> />
</template> </template>
<template #top>
<div class="full-width-slot">
<slot name="before-header" />
</div>
</template>
<template #header-cell="{ col }"> <template #header-cell="{ col }">
<QTh v-if="col.visible ?? true"> <QTh v-if="col.visible ?? true">
<div <div
@ -482,6 +491,9 @@ defineExpose({
/> />
</QTd> </QTd>
</template> </template>
<template #bottom v-if="bottom">
<slot name="bottom-table" />
</template>
<template #item="{ row, colsMap }"> <template #item="{ row, colsMap }">
<component <component
:is="$props.redirect ? 'router-link' : 'span'" :is="$props.redirect ? 'router-link' : 'span'"
@ -780,4 +792,13 @@ es:
cursor: text; cursor: text;
user-select: all; user-select: all;
} }
.full-width-slot {
width: 100%;
display: flex;
text-align: center;
color: var(--vn-text-color);
margin-bottom: -1%;
background-color: var(--vn-header-color);
}
</style> </style>

View File

@ -28,7 +28,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
delete params.filter; delete params.filter;
store.userParams = { ...params, ...store.userParams }; store.userParams = { ...params, ...store.userParams };
store.userFilter = { ...filter, ...store.userFilter }; store.userFilter = { ...filter, ...store.userFilter };
if (filter.order) store.order = filter.order; if (filter?.order) store.order = filter.order;
} }
}); });

View File

@ -578,6 +578,8 @@ ticket:
warehouse: Warehouse warehouse: Warehouse
customerCard: Customer card customerCard: Customer card
alias: Alias alias: Alias
ticketList: Ticket List
newOrder: New Order
boxing: boxing:
expedition: Expedition expedition: Expedition
item: Item item: Item
@ -628,6 +630,11 @@ ticket:
weight: Weight weight: Weight
goTo: Go to goTo: Go to
summaryAmount: Summary summaryAmount: Summary
purchaseRequest: Purchase request
service: Service
description: Description
attender: Attender
ok: Ok
create: create:
client: Client client: Client
address: Address address: Address
@ -651,7 +658,6 @@ invoiceOut:
client: Client client: Client
company: Company company: Company
customerCard: Customer card customerCard: Customer card
ticketList: Ticket List
summary: summary:
issued: Issued issued: Issued
created: Created created: Created

View File

@ -584,6 +584,8 @@ ticket:
warehouse: Almacén warehouse: Almacén
customerCard: Ficha del cliente customerCard: Ficha del cliente
alias: Alias alias: Alias
ticketList: Listado de tickets
newOrder: Nuevo pedido
boxing: boxing:
expedition: Expedición expedition: Expedición
item: Artículo item: Artículo
@ -634,6 +636,10 @@ ticket:
weight: Peso weight: Peso
goTo: Ir a goTo: Ir a
summaryAmount: Resumen summaryAmount: Resumen
purchaseRequest: Petición de compra
service: Servicio
description: Descripción
attender: Comprador
create: create:
client: Cliente client: Cliente
address: Dirección address: Dirección

View File

@ -87,6 +87,11 @@ const filter = {
}; };
const data = ref(useCardDescription()); const data = ref(useCardDescription());
function ticketFilter(ticket) {
console.log('ticket: ', ticket);
return JSON.stringify({ clientFk: ticket.clientFk });
}
</script> </script>
<template> <template>
@ -159,6 +164,22 @@ const data = ref(useCardDescription());
> >
<QTooltip>{{ t('ticket.card.customerCard') }}</QTooltip> <QTooltip>{{ t('ticket.card.customerCard') }}</QTooltip>
</QBtn> </QBtn>
<QBtn
size="md"
icon="vn:ticket"
color="primary"
:to="{ name: 'TicketList', query: { table: ticketFilter(entity) } }"
>
<QTooltip>{{ t('ticket.card.ticketList') }}</QTooltip>
</QBtn>
<QBtn
size="md"
icon="vn:basketadd"
color="primary"
:to="{ name: 'OrderList' }"
>
<QTooltip>{{ t('ticket.card.newOrder') }}</QTooltip>
</QBtn>
</QCardActions> </QCardActions>
</template> </template>
</CardDescriptor> </CardDescriptor>

View File

@ -24,6 +24,7 @@ const { openReport, sendEmail } = usePrintService();
const ticket = ref(props.ticket); const ticket = ref(props.ticket);
const ticketId = currentRoute.value.params.id; const ticketId = currentRoute.value.params.id;
const showWeightDialog = ref(false);
const actions = { const actions = {
clone: async () => { clone: async () => {
const opts = { message: t('Ticket cloned'), type: 'positive' }; const opts = { message: t('Ticket cloned'), type: 'positive' };
@ -153,30 +154,66 @@ function openConfirmDialog(callback) {
}, },
}); });
} }
function createPdfDialog() {
dialog({
component: VnConfirm,
componentProps: {
promise: createPdfInvoice,
},
});
}
async function createPdfInvoice() {
const { data } = await axios.get('invoiceOuts', {
params: {
filter: JSON.stringify({
where: { ref: ticket.value.refFk },
}),
},
});
const invoiceId = data[0].id;
const { response } = await axios.post(`InvoiceOuts/${invoiceId}/createPdf`);
if (!response) {
notify({
message: 'The invoice PDF document has been regenerated',
type: 'positive',
});
}
}
function setWeightToTicket(weight) {
console.log('weight: ', weight);
const { data } = axios.patch(`Tickets/${ticketId}`, {
weight: weight,
});
console.log('data: ', data);
if (data) window.location.reload();
}
</script> </script>
<template> <template>
<QItem v-ripple clickable> <QItem v-ripple clickable>
<QItemSection avatar> <QItemSection avatar>
<QIcon name="picture_as_pdf" /> <QIcon name="picture_as_pdf" />
</QItemSection> </QItemSection>
<QItemSection>{{ t('Open Delivery Note...') }}</QItemSection> <QItemSection>{{ t('Show Delivery Note...') }}</QItemSection>
<QItemSection side> <QItemSection side>
<QIcon name="keyboard_arrow_right" /> <QIcon name="keyboard_arrow_right" />
</QItemSection> </QItemSection>
<QMenu anchor="top end" self="top start" auto-close bordered> <QMenu anchor="top end" self="top start" auto-close bordered>
<QList> <QList>
<QItem @click="openDeliveryNote('deliveryNote')" v-ripple clickable> <QItem @click="openDeliveryNote('deliveryNote')" v-ripple clickable>
<QItemSection>{{ t('With prices') }}</QItemSection> <QItemSection>{{ t('as PDF') }}</QItemSection>
</QItem> </QItem>
<QItem @click="openDeliveryNote('withoutPrices')" v-ripple clickable> <QItem @click="openDeliveryNote('withoutPrices')" v-ripple clickable>
<QItemSection>{{ t('Without prices') }}</QItemSection> <QItemSection>{{ t('as PDF without prices') }}</QItemSection>
</QItem> </QItem>
<QItem <QItem
@click="openDeliveryNote('deliveryNote', 'csv')" @click="openDeliveryNote('deliveryNote', 'csv')"
v-ripple v-ripple
clickable clickable
> >
<QItemSection>{{ t('As CSV') }}</QItemSection> <QItemSection>{{ t('as CSV') }}</QItemSection>
</QItem> </QItem>
</QList> </QList>
</QMenu> </QMenu>
@ -196,21 +233,21 @@ function openConfirmDialog(callback) {
v-ripple v-ripple
clickable clickable
> >
<QItemSection>{{ t('With prices') }}</QItemSection> <QItemSection>{{ t('Send PDF') }}</QItemSection>
</QItem> </QItem>
<QItem <QItem
@click="sendDeliveryNoteConfirmation('withoutPrices')" @click="sendDeliveryNoteConfirmation('withoutPrices')"
v-ripple v-ripple
clickable clickable
> >
<QItemSection>{{ t('Without prices') }}</QItemSection> <QItemSection>{{ t('Send PDF to tablet') }}</QItemSection>
</QItem> </QItem>
<QItem <QItem
@click="sendDeliveryNoteConfirmation('deliveryNote', 'csv')" @click="sendDeliveryNoteConfirmation('deliveryNote', 'csv')"
v-ripple v-ripple
clickable clickable
> >
<QItemSection>{{ t('As CSV') }}</QItemSection> <QItemSection>{{ t('Send CSV') }}</QItemSection>
</QItem> </QItem>
</QList> </QList>
</QMenu> </QMenu>
@ -219,7 +256,7 @@ function openConfirmDialog(callback) {
<QItemSection avatar> <QItemSection avatar>
<QIcon name="receipt" /> <QIcon name="receipt" />
</QItemSection> </QItemSection>
<QItemSection>{{ t('Open Proforma Invoice') }}</QItemSection> <QItemSection>{{ t('Show Proforma') }}</QItemSection>
</QItem> </QItem>
<QItem v-ripple clickable> <QItem v-ripple clickable>
<QItemSection avatar> <QItemSection avatar>
@ -235,24 +272,54 @@ function openConfirmDialog(callback) {
<QItemSection>{{ t('Pending payment') }}</QItemSection> <QItemSection>{{ t('Pending payment') }}</QItemSection>
</QItem> </QItem>
<QItem @click="showSmsDialog('minAmount')" v-ripple clickable> <QItem @click="showSmsDialog('minAmount')" v-ripple clickable>
<QItemSection>{{ t('Minimum amount') }}</QItemSection> <QItemSection>{{ t('Minimum import') }}</QItemSection>
</QItem> </QItem>
<QItem <QItem
@click="showSmsDialogWithChanges('orderChanges')" @click="showSmsDialogWithChanges('orderChanges')"
v-ripple v-ripple
clickable clickable
> >
<QItemSection>{{ t('Order changes') }}</QItemSection> <QItemSection>{{ t('Notify changes') }}</QItemSection>
</QItem> </QItem>
</QList> </QList>
</QMenu> </QMenu>
</QItem> </QItem>
<QItem @click="createPdfDialog()" v-ripple clickable>
<QItemSection avatar>
<QIcon name="picture_as_pdf" />
</QItemSection>
<QItemSection>{{ t('Regenerate PDF invoice') }}</QItemSection>
</QItem>
<QItem @click="openConfirmDialog('clone')" v-ripple clickable> <QItem @click="openConfirmDialog('clone')" v-ripple clickable>
<QItemSection avatar> <QItemSection avatar>
<QIcon name="content_copy" /> <QIcon name="content_copy" />
</QItemSection> </QItemSection>
<QItemSection>{{ t('To clone ticket') }}</QItemSection> <QItemSection>{{ t('To clone ticket') }}</QItemSection>
</QItem> </QItem>
<QItem @click="showWeightDialog = !showWeightDialog" v-ripple clickable>
<QItemSection avatar>
<QIcon name="content_paste" />
</QItemSection>
<QItemSection>{{ t('Set ticket weight') }}</QItemSection>
</QItem>
<QDialog v-model="showWeightDialog" transition-show="scale" transition-hide="scale">
<QCard>
<QCardSection>
<QInput
v-model="weight"
type="number"
:label="t('Weight')"
@update:model-value="setWeightToTicket"
/>
<QBtn flat v-close-popup class="text-primary">
{{ t('Close') }}
</QBtn>
<QBTn flat @click="setWeightToTicket" class="text-primary">
{{ t('Save') }}
</QBTn>
</QCardSection>
</QCard>
</QDialog>
<template v-if="!ticket.isDeleted"> <template v-if="!ticket.isDeleted">
<QSeparator /> <QSeparator />
<QItem @click="openConfirmDialog('remove')" v-ripple clickable> <QItem @click="openConfirmDialog('remove')" v-ripple clickable>
@ -266,20 +333,26 @@ function openConfirmDialog(callback) {
<i18n> <i18n>
es: es:
Open Delivery Note...: Abrir albarán... Show Delivery Note...: Ver albarán...
Send Delivery Note...: Enviar albarán... Send Delivery Note...: Enviar albarán...
With prices: Con precios as PDF: como PDF
Without prices: Sin precios as PDF without prices: como PDF sin precios
As CSV: Como CSV as CSV: Como CSV
Open Proforma Invoice: Abrir factura proforma Send PDF: Enviar PDF
Send PDF to tablet: Enviar PDF a tablet
Send CSV: Enviar CSV
Show Proforma: Ver proforma
Delete ticket: Eliminar ticket Delete ticket: Eliminar ticket
Send SMS...: Enviar SMS Send SMS...: Enviar SMS
Pending payment: Pago pendiente Pending payment: Pago pendiente
Minimum amount: Importe mínimo Minimum import: Importe mínimo
Order changes: Cambios del pedido Notify changes: Notificar cambios
Ticket deleted: Ticket eliminado Ticket deleted: Ticket eliminado
You can undo this action within the first hour: Puedes deshacer esta acción dentro de la primera hora You can undo this action within the first hour: Puedes deshacer esta acción dentro de la primera hora
To clone ticket: Clonar ticket To clone ticket: Clonar ticket
Ticket cloned: Ticked clonado Ticket cloned: Ticked clonado
It was not able to clone the ticket: No se pudo clonar el ticket It was not able to clone the ticket: No se pudo clonar el ticket
Regenerate PDF invoice: Regenerar PDF factura
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado
Set ticket weight: Establecer peso al ticket
</i18n> </i18n>

View File

@ -22,6 +22,7 @@ import { useVnConfirm } from 'composables/useVnConfirm';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import axios from 'axios'; import axios from 'axios';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import FormModelPopup from 'src/components/FormModelPopup.vue';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -50,6 +51,9 @@ const transfer = ref({
lastActiveTickets: [], lastActiveTickets: [],
sales: [], sales: [],
}); });
const tableRef = ref([]);
const formModelPopupRef = ref();
const showForm = ref(false);
watch( watch(
() => route.params.id, () => route.params.id,
@ -395,7 +399,7 @@ const changeTicketState = async (val) => {
}; };
const removeSelectedSales = () => { const removeSelectedSales = () => {
selectedSales.value.forEach((sale) => { selectedRows.value.forEach((sale) => {
const index = sales.value.indexOf(sale); const index = sales.value.indexOf(sale);
sales.value.splice(index, 1); sales.value.splice(index, 1);
}); });
@ -403,17 +407,16 @@ const removeSelectedSales = () => {
const removeSales = async () => { const removeSales = async () => {
try { try {
const params = { sales: selectedValidSales.value, ticketId: store.data.id }; const params = { sales: selectedRows.value, ticketId: store.data.id };
await axios.post('Sales/deleteSales', params); await axios.post('Sales/deleteSales', params);
removeSelectedSales(); removeSelectedSales();
notify('globals.dataSaved', 'positive'); notify('globals.dataSaved', 'positive');
window.location.reload();
} catch (err) { } catch (err) {
console.error('Error deleting sales', err); console.error('Error deleting sales', err);
} }
}; };
const insertRow = () => sales.value.push({ ...DEFAULT_EDIT });
const setTransferParams = async () => { const setTransferParams = async () => {
try { try {
const checkedSales = JSON.parse(JSON.stringify(selectedSales.value)); const checkedSales = JSON.parse(JSON.stringify(selectedSales.value));
@ -442,6 +445,15 @@ onMounted(async () => {
}); });
onUnmounted(() => (stateStore.rightDrawer = false)); onUnmounted(() => (stateStore.rightDrawer = false));
async function save(item) {
const { data } = await axios.post(`Tickets/${route.params.id}/addSale`, {
id: route.params.id,
barcode: item.itemFk,
quantity: parseInt(item.quantity),
});
if (data) window.location.reload();
}
</script> </script>
<template> <template>
@ -455,12 +467,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
auto-load auto-load
@on-fetch="(data) => (isLocked = data)" @on-fetch="(data) => (isLocked = data)"
/> />
<FetchData
url="Items/withName"
:filter="{ fields: ['id', 'name'], order: 'id DESC' }"
auto-load
@on-fetch="(data) => (itemsWithNameOptions = data)"
/>
<FetchData <FetchData
url="States/editableStates" url="States/editableStates"
:filter="{ fields: ['code', 'name', 'id', 'alertLevel'], order: 'name ASC' }" :filter="{ fields: ['code', 'name', 'id', 'alertLevel'], order: 'name ASC' }"
@ -560,13 +566,13 @@ onUnmounted(() => (stateStore.rightDrawer = false));
</QCardSection> </QCardSection>
</div></QDrawer </div></QDrawer
> >
<!-- TODO: el botón de añadir filas como está en salix-->
<VnTable <VnTable
ref="tableRef" ref="tableRef"
data-key="TicketSales" data-key="TicketSales"
:url="`Tickets/${route.params.id}/getSales`" :url="`Tickets/${route.params.id}/getSales`"
:columns="columns" :columns="columns"
v-model:selected="selectedRows" v-model:selected="selectedRows"
:bottom="true"
:table="{ :table="{
'row-key': 'id', 'row-key': 'id',
selection: 'multiple', selection: 'multiple',
@ -625,7 +631,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
</div> </div>
</template> </template>
<template #column-visible="{ row }"> <template #column-visible="{ row }">
<QBadge :color="row.available < 0 ? 'alert' : 'transparent'" dense> <QBadge :color="row.visible < 0 ? 'alert' : 'transparent'" dense>
{{ row.visible }} {{ row.visible }}
</QBadge> </QBadge>
</template> </template>
@ -667,7 +673,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
<template #column-price="{ row }"> <template #column-price="{ row }">
<QTd> <QTd>
<template v-if="isTicketEditable && row.id"> <template v-if="isTicketEditable && row.id">
<QBtn flat color="primary" dense @click="onOpenEditPricePopover(row)"> <QBtn flat class="link" dense @click="onOpenEditPricePopover(row)">
{{ toCurrency(row.price) }} {{ toCurrency(row.price) }}
</QBtn> </QBtn>
<TicketEditManaProxy <TicketEditManaProxy
@ -689,12 +695,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
<template #column-discount="{ row }"> <template #column-discount="{ row }">
<QTd> <QTd>
<template v-if="!isLocked && row.id"> <template v-if="!isLocked && row.id">
<QBtn <QBtn flat class="link" dense @click="onOpenEditDiscountPopover(row)">
flat
color="primary"
dense
@click="onOpenEditDiscountPopover(row)"
>
{{ toPercentage(row.discount / 100) }} {{ toPercentage(row.discount / 100) }}
</QBtn> </QBtn>
<TicketEditManaProxy <TicketEditManaProxy
@ -715,21 +716,54 @@ onUnmounted(() => (stateStore.rightDrawer = false));
<template #column-amount="{ row }"> <template #column-amount="{ row }">
{{ toCurrency(row.quantity * row.price) }} {{ toCurrency(row.quantity * row.price) }}
</template> </template>
<template #bottom-row> <template #bottom-table v-if="isTicketEditable">
<QBtn <QIcon
class="cursor-pointer fill-icon q-ml-md q-my-lg" @click="showForm = !showForm"
class="fill-icon-on-hover"
color="primary" color="primary"
icon="add_circle" name="add_circle"
size="md" size="sm"
round
flat
:disable="!isTicketEditable"
@click="insertRow()"
> >
<QTooltip> <QTooltip>
{{ t('Add item') }} {{ t('Add item') }}
</QTooltip> </QTooltip>
</QBtn> </QIcon>
<QDialog v-model="showForm" transition-show="scale" transition-hide="scale">
<FormModelPopup
ref="formModelPopupRef"
:url-create="`Tickets/${route.params.id}/addSale`"
:title="t('New item')"
:form-initial-data="{
price: 0,
discount: 0,
visible: 0,
available: 0,
packaging: null,
}"
:save-fn="save"
>
<template #form-inputs="{ data }">
<VnSelect
url="Items/withName"
:option-filter="{
order: 'id DESC',
}"
:fields="['id', 'name']"
:label="t('Items')"
option-label="name"
option-value="id"
:options="itemsWithNameOptions"
hide-selected
v-model="data.itemFk"
/>
<VnInput
v-model="data.quantity"
:label="t('Quantity')"
type="number"
/>
</template>
</FormModelPopup>
</QDialog>
</template> </template>
</VnTable> </VnTable>

View File

@ -50,7 +50,7 @@ const createRefund = async () => {
if (!selected.value.length) return; if (!selected.value.length) return;
const params = { const params = {
servicesIds: selected.value.map((s) => +s.ticketFk), servicesIds: selected.value.map((s) => +s.id),
withWarehouse: false, withWarehouse: false,
negative: true, negative: true,
}; };

View File

@ -425,7 +425,7 @@ async function changeState(value) {
<VnTitle :url="ticketUrl + 'package'" :text="t('globals.packages')" /> <VnTitle :url="ticketUrl + 'package'" :text="t('globals.packages')" />
<QTable :rows="ticket.packagings" flat> <QTable :rows="ticket.packagings" flat>
<template #header="props"> <template #header="props">
<QTr :props="props"> <QTr class="tr-header" :props="props">
<QTh auto-width>{{ t('ticket.summary.created') }}</QTh> <QTh auto-width>{{ t('ticket.summary.created') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.package') }}</QTh> <QTh auto-width>{{ t('ticket.summary.package') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.quantity') }}</QTh> <QTh auto-width>{{ t('ticket.summary.quantity') }}</QTh>
@ -445,7 +445,7 @@ async function changeState(value) {
/> />
<QTable :rows="ticket.services" flat> <QTable :rows="ticket.services" flat>
<template #header="props"> <template #header="props">
<QTr :props="props"> <QTr class="tr-header" :props="props">
<QTh auto-width>{{ t('ticket.summary.quantity') }}</QTh> <QTh auto-width>{{ t('ticket.summary.quantity') }}</QTh>
<QTh auto-width>{{ t('globals.description') }}</QTh> <QTh auto-width>{{ t('globals.description') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.price') }}</QTh> <QTh auto-width>{{ t('ticket.summary.price') }}</QTh>
@ -466,6 +466,49 @@ async function changeState(value) {
</template> </template>
</QTable> </QTable>
</QCard> </QCard>
<QCard class="vn-max" v-if="ticket.requests.length > 0">
<VnTitle
:url="ticketUrl + 'request'"
:text="t('ticket.summary.purchaseRequest')"
/>
<QTable :rows="ticket.requests" flat>
<template #header="props">
<QTr class="tr-header" :props="props">
<QTh auto-width>{{ t('ticket.summary.description') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.created') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.requester') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.attender') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.quantity') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.price') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.item') }}</QTh>
<QTh auto-width>{{ t('ticket.summary.ok') }}</QTh>
</QTr>
</template>
<template #body="props">
<QTr :props="props">
<QTd>{{ toDate(props.row.created) }}</QTd>
<QTd>{{ props.row.description }}</QTd>
<QTd>{{ props.row.requester?.user?.username }}</QTd>
<QTd>{{ props.row.atender?.user?.username }}</QTd>
<QTd>{{ props.row.quantity }}</QTd>
<QTd>{{ toCurrency(props.row.price) }}</QTd>
<QTd>
<span class="link" v-if="props.row.isOk">
{{ props.row.itemFk }}
<ItemDescriptorProxy :id="props.row.itemFk" />
</span>
</QTd>
<QTd>
<QCheckbox
v-model="props.row.isOk"
disable
:toggle-indeterminate="false"
/>
</QTd>
</QTr>
</template>
</QTable>
</QCard>
</template> </template>
</CardSummary> </CardSummary>
</template> </template>

View File

@ -94,13 +94,11 @@ const openCreateModal = () => createTrackingDialogRef.value.show();
:no-data-label="t('globals.noResults')" :no-data-label="t('globals.noResults')"
> >
<template #body-cell-worker="{ row }"> <template #body-cell-worker="{ row }">
<QTd @click.stop> <QTd>
<span class="link"> <QBtn flat class="link" @click.stop>
<QBtn flat> {{ row.user?.name }}
Review

Aqui habia un cambio con respecto al orden de los filtros. Seguro que jorge sabe donde se hace porque lo hizo para InvoiceInSummary

Aqui habia un cambio con respecto al orden de los filtros. Seguro que jorge sabe donde se hace porque lo hizo para InvoiceInSummary
{{ row.user?.name }} <WorkerDescriptorProxy :id="row.user?.worker?.id" />
<WorkerDescriptorProxy :id="row.user?.worker?.id" /> </QBtn>
</QBtn>
</span>
</QTd> </QTd>
</template> </template>
</QTable> </QTable>

View File

@ -134,12 +134,10 @@ onUnmounted(() => (stateStore.rightDrawer = false));
> >
<template #body-cell-item="{ row }"> <template #body-cell-item="{ row }">
<QTd> <QTd>
<span class="link"> <QBtn flat class="link" @click.stop>
<QBtn flat> {{ row.itemFk }}
{{ row.itemFk }} <ItemDescriptorProxy :id="row.itemFk" />
<ItemDescriptorProxy :id="row.itemFk" /> </QBtn>
</QBtn>
</span>
</QTd> </QTd>
</template> </template>
<template #body-cell-description="{ row }"> <template #body-cell-description="{ row }">

View File

@ -3,8 +3,8 @@ import { onMounted, ref, computed, reactive } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import VnInput from 'src/components/common/VnInput.vue'; // import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; // import VnSelect from 'src/components/common/VnSelect.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue'; import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
@ -19,13 +19,14 @@ import useNotify from 'src/composables/useNotify.js';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
import { toDateFormat } from 'src/filters/date.js'; import { toDateFormat } from 'src/filters/date.js';
import axios from 'axios'; import axios from 'axios';
import VnTable from 'src/components/VnTable/VnTable.vue';
const state = useState(); const state = useState();
const { t } = useI18n(); const { t } = useI18n();
const { openConfirmationModal } = useVnConfirm(); const { openConfirmationModal } = useVnConfirm();
const { notify } = useNotify(); const { notify } = useNotify();
const user = state.getUser(); const user = state.getUser();
const tableRef = ref();
const itemPackingTypesOptions = ref([]); const itemPackingTypesOptions = ref([]);
const zonesOptions = ref([]); const zonesOptions = ref([]);
const selectedTickets = ref([]); const selectedTickets = ref([]);
@ -44,15 +45,14 @@ const exprBuilder = (param, value) => {
case 'notMovableLines': case 'notMovableLines':
case 'futureZoneFk': case 'futureZoneFk':
return { [param]: value }; return { [param]: value };
case 'iptColFilter': case 'ipt':
return { ipt: { like: `%${value}%` } }; return { [param]: { like: `%${value}%` } };
case 'futureIptColFilter': case 'futureIpt':
return { futureIpt: { like: `%${value}%` } }; return { [param]: { like: `%${value}%` } };
} }
}; };
const userParams = reactive({}); const userParams = reactive({});
const arrayData = useArrayData('AdvanceTickets', { const arrayData = useArrayData('AdvanceTickets', {
url: 'Tickets/getTicketsAdvance', url: 'Tickets/getTicketsAdvance',
userParams: userParams, userParams: userParams,
@ -82,220 +82,123 @@ const getInputEvents = (col) => {
}; };
}; };
const ticketColumns = computed(() => [ const columns = computed(() => [
{ {
label: '', label: '',
name: 'icons', name: 'icons',
align: 'left', hidden: true,
columnFilter: null,
}, },
{ {
label: t('advanceTickets.ticketId'),
name: 'ticketId',
align: 'center', align: 'center',
sortable: true, label: t('advanceTickets.ticketId'),
columnFilter: { name: 'id',
component: VnInput,
type: 'text',
filterValue: null,
filterParamKey: 'id',
event: getInputEvents,
attrs: {
dense: true,
},
},
}, },
{ {
align: 'left',
label: t('advanceTickets.ipt'), label: t('advanceTickets.ipt'),
name: 'ipt', name: 'ipt',
field: 'ipt',
align: 'left',
sortable: true,
columnFilter: { columnFilter: {
component: VnSelect, component: 'select',
filterParamKey: 'iptColFilter',
type: 'select',
filterValue: null,
event: getInputEvents,
attrs: { attrs: {
options: itemPackingTypesOptions.value, url: 'itemPackingTypes',
'option-value': 'code', fields: ['code', 'description'],
'option-label': 'description', where: { isActive: true },
dense: true, optionValue: 'code',
optionLabel: 'description',
}, },
}, },
format: (val) => dashIfEmpty(val), format: (row, dashIfEmpty) => dashIfEmpty(row.ipt),
}, },
{ {
align: 'left',
label: t('advanceTickets.state'), label: t('advanceTickets.state'),
name: 'state', name: 'state',
align: 'left', hidden: true,
sortable: true,
columnFilter: null,
}, },
{ {
align: 'left',
label: t('advanceTickets.liters'), label: t('advanceTickets.liters'),
name: 'liters', name: 'liters',
field: 'liters',
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
}, },
{ {
align: 'left',
label: t('advanceTickets.lines'), label: t('advanceTickets.lines'),
name: 'lines', name: 'lines',
field: 'lines', format: (row, dashIfEmpty) => dashIfEmpty(row.lines),
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
format: (val) => dashIfEmpty(val),
}, },
{ {
align: 'left',
label: t('advanceTickets.import'), label: t('advanceTickets.import'),
field: 'import', name: 'totalWithVat',
name: 'import', hidden: true,
align: 'left', format: (row) => toCurrency(row.totalWithVat),
sortable: true,
}, },
{ {
align: 'left',
label: t('advanceTickets.futureId'), label: t('advanceTickets.futureId'),
name: 'futureId', name: 'futureId',
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
filterParamKey: 'futureId',
event: getInputEvents,
attrs: {
dense: true,
},
},
}, },
{ {
align: 'left',
label: t('advanceTickets.futureIpt'), label: t('advanceTickets.futureIpt'),
name: 'futureIpt', name: 'futureIpt',
field: 'futureIpt',
align: 'left',
sortable: true,
columnFilter: { columnFilter: {
component: VnSelect, component: 'select',
filterParamKey: 'futureIptColFilter',
type: 'select',
filterValue: null,
event: getInputEvents,
attrs: { attrs: {
options: itemPackingTypesOptions.value, url: 'itemPackingTypes',
'option-value': 'code', fields: ['code', 'description'],
'option-label': 'description', where: { isActive: true },
dense: true, optionValue: 'code',
optionLabel: 'description',
}, },
}, },
format: (val) => dashIfEmpty(val), format: (row, dashIfEmpty) => dashIfEmpty(row.futureIpt),
}, },
{ {
align: 'left',
label: t('advanceTickets.futureState'), label: t('advanceTickets.futureState'),
name: 'futureState', name: 'futureState',
align: 'left', hidden: true,
sortable: true,
columnFilter: null,
format: (val) => dashIfEmpty(val),
}, },
{ {
align: 'left',
label: t('advanceTickets.futureLiters'), label: t('advanceTickets.futureLiters'),
name: 'futureLiters', name: 'futureLiters',
field: 'futureLiters',
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
format: (val) => dashIfEmpty(val),
}, },
{ {
align: 'left',
label: t('advanceTickets.futureZone'), label: t('advanceTickets.futureZone'),
name: 'futureZoneName', name: 'futureZoneFk',
field: 'futureZoneName', columnClass: 'expand',
align: 'left',
sortable: true,
columnFilter: { columnFilter: {
component: VnSelect, component: 'select',
type: 'select', inWhere: true,
filterValue: null,
filterParamKey: 'futureZoneFk',
event: getInputEvents,
attrs: { attrs: {
options: zonesOptions.value, url: 'Zones',
'option-value': 'id', fields: ['id', 'name'],
'option-label': 'name',
dense: true,
}, },
}, },
format: (val) => dashIfEmpty(val), columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.futureZoneName),
}, },
{ {
align: 'left',
label: t('advanceTickets.notMovableLines'), label: t('advanceTickets.notMovableLines'),
name: 'notMovableLines', name: 'notMovableLines',
field: 'notMovableLines',
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
format: (val) => dashIfEmpty(val),
}, },
{ {
align: 'left',
label: t('advanceTickets.futureLines'), label: t('advanceTickets.futureLines'),
name: 'futureLines', name: 'futureLines',
field: 'futureLines',
align: 'left',
sortable: true,
columnFilter: {
component: VnInput,
type: 'text',
filterValue: null,
event: getInputEvents,
attrs: {
dense: true,
},
},
format: (val) => dashIfEmpty(val),
}, },
{ {
label: t('advanceTickets.futureImport'),
name: 'futureImport',
align: 'left', align: 'left',
sortable: true, label: t('advanceTickets.futureImport'),
columnFilter: null, name: 'futureTotalWithVat',
hidden: true,
format: (row) => toCurrency(row.futureTotalWithVat),
}, },
]); ]);
@ -457,6 +360,13 @@ onMounted(async () => {
const filter = { limit: 0 }; const filter = { limit: 0 };
await arrayData.addFilter({ filter, userParams }); await arrayData.addFilter({ filter, userParams });
}); });
const getColor = (row) => {
return row?.classColor ? `bg-${row.classColor}` : 'bg-orange';
};
const getFutureColor = (row) => {
return row?.futureClassColor ? `bg-${row.futureClassColor}` : 'bg-orange';
};
</script> </script>
<template> <template>
@ -480,9 +390,9 @@ onMounted(async () => {
@on-fetch="(data) => (zonesOptions = data)" @on-fetch="(data) => (zonesOptions = data)"
/> />
<VnSearchbar <VnSearchbar
data-key="WeeklyTickets" data-key="AdvanceTickets"
:label="t('weeklyTickets.search')" :label="t('advanceTickets.search')"
:info="t('weeklyTickets.searchInfo')" :info="t('advanceTickets.searchInfo')"
/> />
<VnSubToolbar> <VnSubToolbar>
<template #st-data> <template #st-data>
@ -531,73 +441,32 @@ onMounted(async () => {
</template> </template>
</RightMenu> </RightMenu>
<QPage class="column items-center q-pa-md"> <QPage class="column items-center q-pa-md">
<QTable <VnTable
:rows="tickets" ref="tableRef"
:columns="ticketColumns" data-key="AdvanceTickets"
row-key="index" url="TicketWeeklies/filter"
selection="multiple" :columns="columns"
auto-load
:right-search="false"
:disable-option="{ card: true }"
v-model:selected="selectedTickets" v-model:selected="selectedTickets"
:pagination="{ rowsPerPage: 0 }" :table="{
:no-data-label="t('globals.noResults')" 'row-key': 'id',
style="max-width: 99%" selection: 'multiple',
}"
> >
<template #header="props"> <!--TODO: arreglar estilos-->
<QTr :props="props"> <template #before-header>
<QTh <span class="horizontal-separator" translate>
class="horizontal-separator text-uppercase color-vn-label" {{ t('advanceTickets.destination') }}
colspan="7" {{ toDateFormat(userParams.dateToAdvance) }}
translate </span>
> <span class="horizontal-separator" translate>
{{ t('advanceTickets.destination') }} {{ t('advanceTickets.origin') }}
{{ toDateFormat(userParams.dateToAdvance) }} {{ toDateFormat(userParams.dateFuture) }}
</QTh> </span>
<QTh
class="horizontal-separator text-uppercase color-vn-label"
colspan="9"
translate
>
{{ t('advanceTickets.origin') }}
{{ toDateFormat(userParams.dateFuture) }}
</QTh>
</QTr>
<QTr>
<QTh>
<QCheckbox v-model="props.selected" />
</QTh>
<QTh
v-for="(col, index) in ticketColumns"
:key="index"
:class="{ 'vertical-separator': col.name === 'futureId' }"
>
{{ col.label }}
</QTh>
</QTr>
</template> </template>
<template #top-row="{ cols }"> <template #column-icons="{ row }">
<QTr>
<QTd />
<QTd
v-for="(col, index) in cols"
:key="index"
style="max-width: 100px"
>
<component
:is="col.columnFilter.component"
v-if="col.columnFilter"
v-model="col.columnFilter.filterValue"
v-bind="col.columnFilter.attrs"
v-on="col.columnFilter.event(col)"
dense
/>
</QTd>
</QTr>
</template>
<template #header-cell-availableLines="{ col }">
<QTh class="vertical-separator">
{{ col.label }}
</QTh>
</template>
<template #body-cell-icons="{ row }">
<QTd class="q-gutter-x-xs"> <QTd class="q-gutter-x-xs">
<QIcon <QIcon
v-if="row.futureAgency !== row.agency && row.agency" v-if="row.futureAgency !== row.agency && row.agency"
@ -624,73 +493,52 @@ onMounted(async () => {
</QIcon> </QIcon>
</QTd> </QTd>
</template> </template>
<template #body-cell-ticketId="{ row }"> <template #column-id="{ row }">
<QTd> <span class="link" @click.stop>
<QBtn flat class="link"> {{ row.id }}
{{ row.id }} <TicketDescriptorProxy :id="row.id" />
<TicketDescriptorProxy :id="row.id" /> </span>
</QBtn>
</QTd>
</template> </template>
<template #body-cell-state="{ row }"> <template #column-state="{ row }">
<QTd> <QChip :class="getColor(row)" dense square>
<QBadge {{ row.state }}
text-color="black" </QChip>
:color="row.classColor"
class="q-ma-none"
dense
>
{{ row.state }}
</QBadge>
</QTd>
</template> </template>
<template #body-cell-import="{ row }"> <template #column-totalWithVat="{ row }">
<QTd> <QBadge
<QBadge :text-color="isLessThan50(row.totalWithVat) ? 'black' : 'white'"
:text-color="isLessThan50(row.totalWithVat) ? 'black' : 'white'" :color="totalPriceColor(row.totalWithVat)"
:color="totalPriceColor(row.totalWithVat)" class="q-ma-none"
class="q-ma-none" dense
dense >
> {{ toCurrency(row.totalWithVat || 0) }}
{{ toCurrency(row.totalWithVat || 0) }} </QBadge>
</QBadge>
</QTd>
</template> </template>
<template #body-cell-futureId="{ row }"> <template #column-futureId="{ row }">
<QTd class="vertical-separator"> <!--TODO: arreglar estilos para que se muestre como antes, slot?-->
<QBtn flat class="link" dense> <div class="vertical-separator">
<span class="link" @click.stop>
{{ row.futureId }} {{ row.futureId }}
<TicketDescriptorProxy :id="row.futureId" /> <TicketDescriptorProxy :id="row.futureId" />
</QBtn> </span>
</QTd> </div>
</template> </template>
<template #body-cell-futureState="{ row }"> <template #column-futureState="{ row }">
<QTd> <QChip :class="getFutureColor(row)" dense square>
<QBadge {{ row.futureState }}
text-color="black" </QChip>
:color="row.futureClassColor"
class="q-ma-none"
dense
>
{{ row.futureState }}
</QBadge>
</QTd>
</template> </template>
<template #body-cell-futureImport="{ row }"> <template #column-futureTotalWithVat="{ row }">
<QTd> <QBadge
<QBadge :text-color="isLessThan50(row.futureTotalWithVat) ? 'black' : 'white'"
:text-color=" :color="totalPriceColor(row.futureTotalWithVat)"
isLessThan50(row.futureTotalWithVat) ? 'black' : 'white' class="q-ma-none"
" dense
:color="totalPriceColor(row.futureTotalWithVat)" >
class="q-ma-none" {{ toCurrency(row.futureTotalWithVat || 0) }}
dense </QBadge>
>
{{ toCurrency(row.futureTotalWithVat || 0) }}
</QBadge>
</QTd>
</template> </template>
</QTable> </VnTable>
<VnProgress <VnProgress
:progress="progressPercentage" :progress="progressPercentage"
:cancelled="cancelProgress" :cancelled="cancelProgress"
@ -714,6 +562,8 @@ onMounted(async () => {
} }
.horizontal-separator { .horizontal-separator {
border-bottom: 4px solid white !important; width: 100%;
margin-top: 1%;
border-bottom: 5px solid white !important;
} }
</style> </style>

View File

@ -2,7 +2,9 @@
import axios from 'axios'; import axios from 'axios';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import { toDate, toCurrency } from 'src/filters/index'; import { toDate, toCurrency } from 'src/filters/index';
import useNotify from 'src/composables/useNotify';
import TicketSummary from './Card/TicketSummary.vue'; import TicketSummary from './Card/TicketSummary.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
@ -10,14 +12,25 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnRow from 'src/components/ui/VnRow.vue'; import VnRow from 'src/components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import FetchData from 'src/components/FetchData.vue';
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const tableRef = ref(); const tableRef = ref();
const quasar = useQuasar();
const { notify } = useNotify();
const clientsOptions = ref([]); const clientsOptions = ref([]);
const addressesOptions = ref([]); const addressesOptions = ref([]);
const agenciesOptions = ref([]); const agenciesOptions = ref([]);
const selectedClient = ref(); const selectedClient = ref();
const selectedRows = ref([]);
const hasSelectedRows = computed(() => selectedRows.value.length > 0);
const showForm = ref(false);
const dialogData = ref();
const companiesOptions = ref([]);
const accountingOptions = ref([]);
const amountToReturn = ref();
const columns = computed(() => [ const columns = computed(() => [
{ {
@ -187,9 +200,158 @@ const fetchAddresses = async (formData) => {
const getColor = (row) => { const getColor = (row) => {
return row?.classColor ? `bg-${row.classColor}` : 'bg-orange'; return row?.classColor ? `bg-${row.classColor}` : 'bg-orange';
}; };
async function makeInvoice(ticket) {
const ticketsIds = ticket.map((item) => item.id);
const { data } = await axios.post(`Tickets/invoiceTicketsAndPdf`, { ticketsIds });
const response = data;
if (response)
quasar.notify({
message: t('globals.dataSaved'),
type: 'positive',
});
}
async function sendDocuware(ticket) {
try {
let ticketIds = ticket.map((item) => item.id);
const { data } = await axios.post(`Docuwares/upload`, {
fileCabinet: 'deliveryNote',
ticketIds,
});
for (let ticket of ticketIds) {
ticket.stateFk = data.id;
ticket.state = data.name;
ticket.alertLevel = data.alertLevel;
ticket.alertLevelCode = data.code;
}
notify('globals.dataSaved', 'positive');
} catch (err) {
console.log('err: ', err);
}
}
function openBalanceDialog(ticket) {
const checkedTickets = ticket;
const amountPaid = ref(0);
const clientFk = ref(null);
const description = ref([]);
const firstTicketClientId = checkedTickets[0].clientFk;
const isSameClient = checkedTickets.every(
(ticket) => ticket.clientFk === firstTicketClientId
);
if (!isSameClient) {
throw new Error('You cannot make a payment on account from multiple clients');
}
for (let ticketData of checkedTickets) {
console.log('ticketData: ', ticketData);
amountPaid.value += ticketData.totalWithVat;
clientFk.value = ticketData.clientFk;
description.value.push(ticketData.id);
}
const balanceCreateDialog = ref({
amountPaid: amountPaid.value,
clientFk: clientFk.value,
description: `Albaran: ${description.value.join(', ')}`,
});
dialogData.value = balanceCreateDialog;
showForm.value = true;
}
async function onSubmit() {
const { data: email } = await axios.get('Clients', {
params: {
filter: JSON.stringify({ where: { id: dialogData.value.value.clientFk } }),
},
});
const { data } = await axios.post(
`Clients/${dialogData.value.value.clientFk}/createReceipt`,
{
payed: dialogData.value.payed,
companyFk: dialogData.value.companyFk,
bankFk: dialogData.value.bankFk,
amountPaid: dialogData.value.value.amountPaid,
description: dialogData.value.value.description,
clientFk: dialogData.value.value.clientFk,
email: email[0].email,
}
);
if (data) notify('globals.dataSaved', 'positive');
showForm.value = false;
}
const setAmountToReturn = (newAmountGiven) => {
const amountPaid = dialogData.value.value.amountPaid;
amountToReturn.value = newAmountGiven - amountPaid;
};
function setReference(data) {
console.log('entity: ', data);
let newDescription = '';
switch (data) {
case 1:
newDescription = `${t(
'ticketList.creditCard'
)}, ${dialogData.value.value.description.replace(
/^(Credit Card, |Cash, |Transfers, )/,
''
)}`;
break;
case 2:
newDescription = `${t(
'ticketList.cash'
)}, ${dialogData.value.value.description.replace(
/^(Credit Card, |Cash, |Transfers, )/,
''
)}`;
break;
case 3:
newDescription = `${newDescription.replace(
/^(Credit Card, |Cash, |Transfers, )/,
''
)}`;
break;
case 4:
newDescription = `${t(
'ticketList.transfers'
)}, ${dialogData.value.value.description.replace(
/^(Credit Card, |Cash, |Transfers, )/,
''
)}`;
break;
case 3317:
newDescription = '';
break;
default:
break;
}
dialogData.value.value.description = newDescription;
console.log('Updated description:', dialogData.value.value.description);
}
</script> </script>
<template> <template>
<FetchData
url="Companies"
@on-fetch="(data) => (companiesOptions = data)"
auto-load
/>
<FetchData
url="Accountings"
@on-fetch="(data) => (accountingOptions = data)"
auto-load
/>
<VnSearchbar <VnSearchbar
data-key="Tickets" data-key="Tickets"
:label="t('Search ticket')" :label="t('Search ticket')"
@ -209,6 +371,11 @@ const getColor = (row) => {
:columns="columns" :columns="columns"
redirect="ticket" redirect="ticket"
auto-load auto-load
v-model:selected="selectedRows"
:table="{
'row-key': 'id',
selection: 'multiple',
}"
> >
<template #more-create-dialog="{ data }"> <template #more-create-dialog="{ data }">
<VnRow> <VnRow>
@ -306,6 +473,135 @@ const getColor = (row) => {
</QChip> </QChip>
</template> </template>
</VnTable> </VnTable>
<QPageSticky :offset="[20, 80]" style="z-index: 2">
<QBtn
v-if="hasSelectedRows"
@click="makeInvoice(selectedRows)"
color="primary"
fab
icon="vn:invoice-in"
/>
<QTooltip>
{{ t('ticketList.createInvoice') }}
</QTooltip>
</QPageSticky>
<QPageSticky v-if="hasSelectedRows" :offset="[20, 140]" style="z-index: 2">
<QBtn
@click.stop="openBalanceDialog(selectedRows)"
color="primary"
fab
icon="vn:recovery"
/>
<QTooltip>
{{ t('ticketList.accountPayment') }}
</QTooltip>
</QPageSticky>
<QDialog ref="dialogRef" v-model="showForm">
<QCard class="q-pa-md q-mb-md">
<QForm @submit="onSubmit()" class="q-pa-sm">
{{ t('ticketList.addPayment') }}
<VnRow>
<VnInputDate
:label="t('ticketList.date')"
v-model="dialogData.payed"
/>
<VnSelect
:label="t('ticketList.company')"
v-model="dialogData.companyFk"
:options="companiesOptions"
option-value="id"
option-label="code"
hide-selected
>
</VnSelect>
</VnRow>
<VnRow>
<VnSelect
:label="t('ticketList.bank')"
v-model="dialogData.bankFk"
:options="accountingOptions"
option-value="id"
option-label="bank"
hide-selected
@update:model-value="setReference"
/>
<VnInput
:label="t('ticketList.amount')"
v-model="dialogData.value.amountPaid"
/>
</VnRow>
<VnRow v-if="dialogData.bankFk === 2">
<span>
{{ t('ticketList.cash') }}
</span>
</VnRow>
<VnRow v-if="dialogData.bankFk === 2">
<VnInput
:label="t('ticketList.deliveredAmount')"
v-model="dialogData.value.amountGiven"
@update:model-value="setAmountToReturn"
type="number"
/>
<VnInput
:label="t('ticketList.amountToReturn')"
:model-value="amountToReturn"
type="number"
readonly
/>
</VnRow>
<VnRow v-if="dialogData.bankFk === 3 || dialogData.bankFk === 3117">
<VnInput
:label="t('ticketList.compensation')"
v-model="dialogData.value.compensation"
type="text"
/>
</VnRow>
jon marked this conversation as resolved Outdated

falta añadir toDate, porque sigue mostrándolo mal a pesar de dar format en la declaraciones de columnas

falta añadir toDate, porque sigue mostrándolo mal a pesar de dar format en la declaraciones de columnas
<VnRow>
<VnInput
:label="t('ticketList.reference')"
v-model="dialogData.value.description"
type="text"
/>
</VnRow>
<VnRow v-if="dialogData.bankFk === 2">
<QCheckbox
:label="t('ticketList.viewReceipt')"
v-model="dialogData.value.viewReceipt"
:toggle-indeterminate="false"
/>
<QCheckbox
:label="t('ticketList.sendEmail')"
v-model="dialogData.value.senEmail"
:toggle-indeterminate="false"
/>
</VnRow>
<div class="q-mt-lg row justify-end">
<QBtn
:label="t('globals.save')"
color="primary"
@click="onSubmit()"
/>
<QBtn
flat
:label="t('globals.close')"
color="primary"
v-close-popup
/>
</div>
</QForm>
</QCard>
</QDialog>
<QPageSticky v-if="hasSelectedRows" :offset="[20, 200]" style="z-index: 2">
<QBtn
@click="sendDocuware(selectedRows)"
color="primary"
fab
icon="install_mobile"
/>
<QTooltip>
{{ t('ticketList.sendDocuware') }}
</QTooltip>
</QPageSticky>
</template> </template>
<i18n> <i18n>

View File

@ -66,6 +66,8 @@ advanceTickets:
advanceWithoutNegativeTitle: Advance tickets (without negatives) advanceWithoutNegativeTitle: Advance tickets (without negatives)
advanceWithoutNegativeSubtitle: Advance {selectedTickets} tickets confirmation advanceWithoutNegativeSubtitle: Advance {selectedTickets} tickets confirmation
errorsList: Errors list errorsList: Errors list
search: Search advance tickets
searchInfo: Search advance tickets by ID or client ID
futureTickets: futureTickets:
problems: Problems problems: Problems
ticketId: ID ticketId: ID
@ -239,3 +241,20 @@ ticketList:
summary: Summary summary: Summary
client: Customer client: Customer
createTicket: Create ticket createTicket: Create ticket
createInvoice: Create invoice
accountPayment: Account payment
sendDocuware: Set delivered and send delivery note(s) to the tablet
addPayment: Add payment
date: Date
company: Company
amount: Amount
reference: Reference
bank: Bank
cash: Cash
deliveredAmount: Delivered amount
amountToReturn: Amount to return
viewReceipt: View receipt
sendEmail: Send email
compensation: Compensation
creditCard: Credit card
transfers: Transfers

View File

@ -113,6 +113,8 @@ advanceTickets:
advanceWithoutNegativeTitle: Adelantar tickets (sin negativos) advanceWithoutNegativeTitle: Adelantar tickets (sin negativos)
advanceWithoutNegativeSubtitle: '¿Desea adelantar {selectedTickets} tickets?' advanceWithoutNegativeSubtitle: '¿Desea adelantar {selectedTickets} tickets?'
errorsList: Lista de errores errorsList: Lista de errores
search: Buscar por tickets adelantados
searchInfo: Buscar tickets adelantados por el identificador o el identificador del cliente
futureTickets: futureTickets:
problems: Problemas problems: Problemas
ticketId: ID ticketId: ID
@ -242,3 +244,20 @@ ticketList:
summary: Resumen summary: Resumen
client: Cliente client: Cliente
createTicket: Crear ticket createTicket: Crear ticket
createInvoice: Crear factura
accountPayment: Pago a cuenta...
sendDocuware: Marcar como servido/s y enviar albarán/es a la tablet
addPayment: Añadir pago
date: Fecha
company: Empresa
amount: Importe
reference: Referencia
bank: Caja
cash: Efectivo
deliveredAmount: Cantidad entregada
amountToReturn: Cantidad a devolver
viewReceipt: Ver recibido
sendEmail: Enviar correo
compensation: Compensación
creditCard: Tarjeta de crédito
transfers: Transferencias