diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 3344f53b4b..1fc4947f07 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -49,6 +49,10 @@ const $props = defineProps({ type: Object, default: null, }, + bottom: { + type: Object, + default: null, + }, cardClass: { type: String, default: 'flex-one', @@ -388,6 +392,11 @@ defineExpose({ @click="stateStore.toggleRightDrawer()" /> + + + + + + + + diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index 50d620a348..651bcefb03 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -28,7 +28,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { delete params.filter; store.userParams = { ...params, ...store.userParams }; store.userFilter = { ...filter, ...store.userFilter }; - if (filter.order) store.order = filter.order; + if (filter?.order) store.order = filter.order; } }); diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 6943252c9a..a04b3af152 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -578,6 +578,8 @@ ticket: warehouse: Warehouse customerCard: Customer card alias: Alias + ticketList: Ticket List + newOrder: New Order boxing: expedition: Expedition item: Item @@ -628,6 +630,11 @@ ticket: weight: Weight goTo: Go to summaryAmount: Summary + purchaseRequest: Purchase request + service: Service + description: Description + attender: Attender + ok: Ok create: client: Client address: Address @@ -651,7 +658,6 @@ invoiceOut: client: Client company: Company customerCard: Customer card - ticketList: Ticket List summary: issued: Issued created: Created diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index f32562313e..642017c8ed 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -584,6 +584,8 @@ ticket: warehouse: Almacén customerCard: Ficha del cliente alias: Alias + ticketList: Listado de tickets + newOrder: Nuevo pedido boxing: expedition: Expedición item: Artículo @@ -634,6 +636,10 @@ ticket: weight: Peso goTo: Ir a summaryAmount: Resumen + purchaseRequest: Petición de compra + service: Servicio + description: Descripción + attender: Comprador create: client: Cliente address: Dirección diff --git a/src/pages/Ticket/Card/TicketDescriptor.vue b/src/pages/Ticket/Card/TicketDescriptor.vue index f68c897dbb..e4a349f121 100644 --- a/src/pages/Ticket/Card/TicketDescriptor.vue +++ b/src/pages/Ticket/Card/TicketDescriptor.vue @@ -87,6 +87,11 @@ const filter = { }; const data = ref(useCardDescription()); + +function ticketFilter(ticket) { + console.log('ticket: ', ticket); + return JSON.stringify({ clientFk: ticket.clientFk }); +} @@ -159,6 +164,22 @@ const data = ref(useCardDescription()); > {{ t('ticket.card.customerCard') }} + + {{ t('ticket.card.ticketList') }} + + + {{ t('ticket.card.newOrder') }} + diff --git a/src/pages/Ticket/Card/TicketDescriptorMenu.vue b/src/pages/Ticket/Card/TicketDescriptorMenu.vue index c7784bc2a0..31f85582c6 100644 --- a/src/pages/Ticket/Card/TicketDescriptorMenu.vue +++ b/src/pages/Ticket/Card/TicketDescriptorMenu.vue @@ -24,6 +24,7 @@ const { openReport, sendEmail } = usePrintService(); const ticket = ref(props.ticket); const ticketId = currentRoute.value.params.id; +const showWeightDialog = ref(false); const actions = { clone: async () => { 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(); +} - {{ t('Open Delivery Note...') }} + {{ t('Show Delivery Note...') }} - {{ t('With prices') }} + {{ t('as PDF') }} - {{ t('Without prices') }} + {{ t('as PDF without prices') }} - {{ t('As CSV') }} + {{ t('as CSV') }} @@ -196,21 +233,21 @@ function openConfirmDialog(callback) { v-ripple clickable > - {{ t('With prices') }} + {{ t('Send PDF') }} - {{ t('Without prices') }} + {{ t('Send PDF to tablet') }} - {{ t('As CSV') }} + {{ t('Send CSV') }} @@ -219,7 +256,7 @@ function openConfirmDialog(callback) { - {{ t('Open Proforma Invoice') }} + {{ t('Show Proforma') }} @@ -235,24 +272,54 @@ function openConfirmDialog(callback) { {{ t('Pending payment') }} - {{ t('Minimum amount') }} + {{ t('Minimum import') }} - {{ t('Order changes') }} + {{ t('Notify changes') }} + + + + + {{ t('Regenerate PDF invoice') }} + {{ t('To clone ticket') }} + + + + + {{ t('Set ticket weight') }} + + + + + + + {{ t('Close') }} + + + {{ t('Save') }} + + + + @@ -266,20 +333,26 @@ function openConfirmDialog(callback) { es: - Open Delivery Note...: Abrir albarán... + Show Delivery Note...: Ver albarán... Send Delivery Note...: Enviar albarán... - With prices: Con precios - Without prices: Sin precios - As CSV: Como CSV - Open Proforma Invoice: Abrir factura proforma + as PDF: como PDF + as PDF without prices: como PDF sin precios + as CSV: Como CSV + Send PDF: Enviar PDF + Send PDF to tablet: Enviar PDF a tablet + Send CSV: Enviar CSV + Show Proforma: Ver proforma Delete ticket: Eliminar ticket Send SMS...: Enviar SMS Pending payment: Pago pendiente - Minimum amount: Importe mínimo - Order changes: Cambios del pedido + Minimum import: Importe mínimo + Notify changes: Notificar cambios Ticket deleted: Ticket eliminado You can undo this action within the first hour: Puedes deshacer esta acción dentro de la primera hora To clone ticket: Clonar ticket Ticket cloned: Ticked clonado 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 diff --git a/src/pages/Ticket/Card/TicketSale.vue b/src/pages/Ticket/Card/TicketSale.vue index 8539132856..f2c5228b44 100644 --- a/src/pages/Ticket/Card/TicketSale.vue +++ b/src/pages/Ticket/Card/TicketSale.vue @@ -22,6 +22,7 @@ import { useVnConfirm } from 'composables/useVnConfirm'; import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; import VnTable from 'src/components/VnTable/VnTable.vue'; +import FormModelPopup from 'src/components/FormModelPopup.vue'; const route = useRoute(); const router = useRouter(); @@ -50,6 +51,9 @@ const transfer = ref({ lastActiveTickets: [], sales: [], }); +const tableRef = ref([]); +const formModelPopupRef = ref(); +const showForm = ref(false); watch( () => route.params.id, @@ -395,7 +399,7 @@ const changeTicketState = async (val) => { }; const removeSelectedSales = () => { - selectedSales.value.forEach((sale) => { + selectedRows.value.forEach((sale) => { const index = sales.value.indexOf(sale); sales.value.splice(index, 1); }); @@ -403,17 +407,16 @@ const removeSelectedSales = () => { const removeSales = async () => { 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); removeSelectedSales(); notify('globals.dataSaved', 'positive'); + window.location.reload(); } catch (err) { console.error('Error deleting sales', err); } }; -const insertRow = () => sales.value.push({ ...DEFAULT_EDIT }); - const setTransferParams = async () => { try { const checkedSales = JSON.parse(JSON.stringify(selectedSales.value)); @@ -442,6 +445,15 @@ onMounted(async () => { }); 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(); +} @@ -455,12 +467,6 @@ onUnmounted(() => (stateStore.rightDrawer = false)); auto-load @on-fetch="(data) => (isLocked = data)" /> - (itemsWithNameOptions = data)" - /> (stateStore.rightDrawer = false)); - - + {{ row.visible }} @@ -667,7 +673,7 @@ onUnmounted(() => (stateStore.rightDrawer = false)); - + {{ toCurrency(row.price) }} (stateStore.rightDrawer = false)); - + {{ toPercentage(row.discount / 100) }} (stateStore.rightDrawer = false)); {{ toCurrency(row.quantity * row.price) }} - - + {{ t('Add item') }} - + + + + + + + + + diff --git a/src/pages/Ticket/Card/TicketService.vue b/src/pages/Ticket/Card/TicketService.vue index 63dd454baf..bdfb7ea8c8 100644 --- a/src/pages/Ticket/Card/TicketService.vue +++ b/src/pages/Ticket/Card/TicketService.vue @@ -50,7 +50,7 @@ const createRefund = async () => { if (!selected.value.length) return; const params = { - servicesIds: selected.value.map((s) => +s.ticketFk), + servicesIds: selected.value.map((s) => +s.id), withWarehouse: false, negative: true, }; diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue index 295e8bca50..4a0839655c 100644 --- a/src/pages/Ticket/Card/TicketSummary.vue +++ b/src/pages/Ticket/Card/TicketSummary.vue @@ -425,7 +425,7 @@ async function changeState(value) { - + {{ t('ticket.summary.created') }} {{ t('ticket.summary.package') }} {{ t('ticket.summary.quantity') }} @@ -445,7 +445,7 @@ async function changeState(value) { /> - + {{ t('ticket.summary.quantity') }} {{ t('globals.description') }} {{ t('ticket.summary.price') }} @@ -466,6 +466,49 @@ async function changeState(value) { + + + + + + {{ t('ticket.summary.description') }} + {{ t('ticket.summary.created') }} + {{ t('ticket.summary.requester') }} + {{ t('ticket.summary.attender') }} + {{ t('ticket.summary.quantity') }} + {{ t('ticket.summary.price') }} + {{ t('ticket.summary.item') }} + {{ t('ticket.summary.ok') }} + + + + + {{ toDate(props.row.created) }} + {{ props.row.description }} + {{ props.row.requester?.user?.username }} + {{ props.row.atender?.user?.username }} + {{ props.row.quantity }} + {{ toCurrency(props.row.price) }} + + + {{ props.row.itemFk }} + + + + + + + + + + diff --git a/src/pages/Ticket/Card/TicketTracking.vue b/src/pages/Ticket/Card/TicketTracking.vue index 62d755c4dc..f747ae0240 100644 --- a/src/pages/Ticket/Card/TicketTracking.vue +++ b/src/pages/Ticket/Card/TicketTracking.vue @@ -94,13 +94,11 @@ const openCreateModal = () => createTrackingDialogRef.value.show(); :no-data-label="t('globals.noResults')" > - - - - {{ row.user?.name }} - - - + + + {{ row.user?.name }} + + diff --git a/src/pages/Ticket/Card/TicketVolume.vue b/src/pages/Ticket/Card/TicketVolume.vue index a021cfbf15..a47a127c13 100644 --- a/src/pages/Ticket/Card/TicketVolume.vue +++ b/src/pages/Ticket/Card/TicketVolume.vue @@ -134,12 +134,10 @@ onUnmounted(() => (stateStore.rightDrawer = false)); > - - - {{ row.itemFk }} - - - + + {{ row.itemFk }} + + diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue index bf4000fdfc..1c926491c3 100644 --- a/src/pages/Ticket/TicketAdvance.vue +++ b/src/pages/Ticket/TicketAdvance.vue @@ -3,8 +3,8 @@ import { onMounted, ref, computed, reactive } from 'vue'; import { useI18n } from 'vue-i18n'; import FetchData from 'components/FetchData.vue'; -import VnInput from 'src/components/common/VnInput.vue'; -import VnSelect from 'src/components/common/VnSelect.vue'; +// import VnInput from 'src/components/common/VnInput.vue'; +// import VnSelect from 'src/components/common/VnSelect.vue'; import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.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 { toDateFormat } from 'src/filters/date.js'; import axios from 'axios'; +import VnTable from 'src/components/VnTable/VnTable.vue'; const state = useState(); const { t } = useI18n(); const { openConfirmationModal } = useVnConfirm(); const { notify } = useNotify(); const user = state.getUser(); - +const tableRef = ref(); const itemPackingTypesOptions = ref([]); const zonesOptions = ref([]); const selectedTickets = ref([]); @@ -44,15 +45,14 @@ const exprBuilder = (param, value) => { case 'notMovableLines': case 'futureZoneFk': return { [param]: value }; - case 'iptColFilter': - return { ipt: { like: `%${value}%` } }; - case 'futureIptColFilter': - return { futureIpt: { like: `%${value}%` } }; + case 'ipt': + return { [param]: { like: `%${value}%` } }; + case 'futureIpt': + return { [param]: { like: `%${value}%` } }; } }; const userParams = reactive({}); - const arrayData = useArrayData('AdvanceTickets', { url: 'Tickets/getTicketsAdvance', userParams: userParams, @@ -82,220 +82,123 @@ const getInputEvents = (col) => { }; }; -const ticketColumns = computed(() => [ +const columns = computed(() => [ { label: '', name: 'icons', - align: 'left', - columnFilter: null, + hidden: true, }, { - label: t('advanceTickets.ticketId'), - name: 'ticketId', align: 'center', - sortable: true, - columnFilter: { - component: VnInput, - type: 'text', - filterValue: null, - filterParamKey: 'id', - event: getInputEvents, - attrs: { - dense: true, - }, - }, + label: t('advanceTickets.ticketId'), + name: 'id', }, { + align: 'left', label: t('advanceTickets.ipt'), name: 'ipt', - field: 'ipt', - align: 'left', - sortable: true, columnFilter: { - component: VnSelect, - filterParamKey: 'iptColFilter', - type: 'select', - filterValue: null, - event: getInputEvents, + component: 'select', attrs: { - options: itemPackingTypesOptions.value, - 'option-value': 'code', - 'option-label': 'description', - dense: true, + url: 'itemPackingTypes', + fields: ['code', 'description'], + where: { isActive: true }, + optionValue: 'code', + optionLabel: 'description', }, }, - format: (val) => dashIfEmpty(val), + format: (row, dashIfEmpty) => dashIfEmpty(row.ipt), }, { + align: 'left', label: t('advanceTickets.state'), name: 'state', - align: 'left', - sortable: true, - columnFilter: null, + hidden: true, }, { + align: 'left', label: t('advanceTickets.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'), name: 'lines', - field: 'lines', - align: 'left', - sortable: true, - columnFilter: { - component: VnInput, - type: 'text', - filterValue: null, - event: getInputEvents, - attrs: { - dense: true, - }, - }, - format: (val) => dashIfEmpty(val), + format: (row, dashIfEmpty) => dashIfEmpty(row.lines), }, { + align: 'left', label: t('advanceTickets.import'), - field: 'import', - name: 'import', - align: 'left', - sortable: true, + name: 'totalWithVat', + hidden: true, + format: (row) => toCurrency(row.totalWithVat), }, { + align: 'left', label: t('advanceTickets.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'), name: 'futureIpt', - field: 'futureIpt', - align: 'left', - sortable: true, columnFilter: { - component: VnSelect, - filterParamKey: 'futureIptColFilter', - type: 'select', - filterValue: null, - event: getInputEvents, + component: 'select', attrs: { - options: itemPackingTypesOptions.value, - 'option-value': 'code', - 'option-label': 'description', - dense: true, + url: 'itemPackingTypes', + fields: ['code', 'description'], + where: { isActive: true }, + optionValue: 'code', + optionLabel: 'description', }, }, - format: (val) => dashIfEmpty(val), + format: (row, dashIfEmpty) => dashIfEmpty(row.futureIpt), }, { + align: 'left', label: t('advanceTickets.futureState'), name: 'futureState', - align: 'left', - sortable: true, - columnFilter: null, - format: (val) => dashIfEmpty(val), + hidden: true, }, { + align: 'left', label: t('advanceTickets.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'), - name: 'futureZoneName', - field: 'futureZoneName', - align: 'left', - sortable: true, + name: 'futureZoneFk', + columnClass: 'expand', columnFilter: { - component: VnSelect, - type: 'select', - filterValue: null, - filterParamKey: 'futureZoneFk', - event: getInputEvents, + component: 'select', + inWhere: true, attrs: { - options: zonesOptions.value, - 'option-value': 'id', - 'option-label': 'name', - dense: true, + url: 'Zones', + fields: ['id', 'name'], }, }, - format: (val) => dashIfEmpty(val), + columnField: { + component: null, + }, + format: (row, dashIfEmpty) => dashIfEmpty(row.futureZoneName), }, { + align: 'left', label: t('advanceTickets.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'), 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', - sortable: true, - columnFilter: null, + label: t('advanceTickets.futureImport'), + name: 'futureTotalWithVat', + hidden: true, + format: (row) => toCurrency(row.futureTotalWithVat), }, ]); @@ -457,6 +360,13 @@ onMounted(async () => { const filter = { limit: 0 }; 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'; +}; @@ -480,9 +390,9 @@ onMounted(async () => { @on-fetch="(data) => (zonesOptions = data)" /> @@ -531,73 +441,32 @@ onMounted(async () => { - - - - - {{ t('advanceTickets.destination') }} - {{ toDateFormat(userParams.dateToAdvance) }} - - - {{ t('advanceTickets.origin') }} - {{ toDateFormat(userParams.dateFuture) }} - - - - - - - - {{ col.label }} - - + + + + {{ t('advanceTickets.destination') }} + {{ toDateFormat(userParams.dateToAdvance) }} + + + {{ t('advanceTickets.origin') }} + {{ toDateFormat(userParams.dateFuture) }} + - - - - - - - - - - - {{ col.label }} - - - + { - - - - {{ row.id }} - - - + + + {{ row.id }} + + - - - - {{ row.state }} - - + + + {{ row.state }} + - - - - {{ toCurrency(row.totalWithVat || 0) }} - - + + + {{ toCurrency(row.totalWithVat || 0) }} + - - - + + + + {{ row.futureId }} - - + + - - - - {{ row.futureState }} - - + + + {{ row.futureState }} + - - - - {{ toCurrency(row.futureTotalWithVat || 0) }} - - + + + {{ toCurrency(row.futureTotalWithVat || 0) }} + - + { } .horizontal-separator { - border-bottom: 4px solid white !important; + width: 100%; + margin-top: 1%; + border-bottom: 5px solid white !important; } diff --git a/src/pages/Ticket/TicketList.vue b/src/pages/Ticket/TicketList.vue index ad53935bcf..30e3654902 100644 --- a/src/pages/Ticket/TicketList.vue +++ b/src/pages/Ticket/TicketList.vue @@ -2,7 +2,9 @@ import axios from 'axios'; import { computed, ref } from 'vue'; import { useI18n } from 'vue-i18n'; +import { useQuasar } from 'quasar'; import { toDate, toCurrency } from 'src/filters/index'; +import useNotify from 'src/composables/useNotify'; import TicketSummary from './Card/TicketSummary.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; 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 VnInputDate from 'src/components/common/VnInputDate.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 { viewSummary } = useSummaryDialog(); const tableRef = ref(); +const quasar = useQuasar(); +const { notify } = useNotify(); const clientsOptions = ref([]); const addressesOptions = ref([]); const agenciesOptions = 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(() => [ { @@ -187,9 +200,158 @@ const fetchAddresses = async (formData) => { const getColor = (row) => { 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); +} + (companiesOptions = data)" + auto-load + /> + (accountingOptions = data)" + auto-load + /> { :columns="columns" redirect="ticket" auto-load + v-model:selected="selectedRows" + :table="{ + 'row-key': 'id', + selection: 'multiple', + }" > @@ -306,6 +473,135 @@ const getColor = (row) => { + + + + {{ t('ticketList.createInvoice') }} + + + + + + {{ t('ticketList.accountPayment') }} + + + + + + {{ t('ticketList.addPayment') }} + + + + + + + + + + + + {{ t('ticketList.cash') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ t('ticketList.sendDocuware') }} + + diff --git a/src/pages/Ticket/locale/en.yml b/src/pages/Ticket/locale/en.yml index 66a3787dda..ddd33128e9 100644 --- a/src/pages/Ticket/locale/en.yml +++ b/src/pages/Ticket/locale/en.yml @@ -66,6 +66,8 @@ advanceTickets: advanceWithoutNegativeTitle: Advance tickets (without negatives) advanceWithoutNegativeSubtitle: Advance {selectedTickets} tickets confirmation errorsList: Errors list + search: Search advance tickets + searchInfo: Search advance tickets by ID or client ID futureTickets: problems: Problems ticketId: ID @@ -239,3 +241,20 @@ ticketList: summary: Summary client: Customer 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 diff --git a/src/pages/Ticket/locale/es.yml b/src/pages/Ticket/locale/es.yml index 59f5a7f917..97fd63060f 100644 --- a/src/pages/Ticket/locale/es.yml +++ b/src/pages/Ticket/locale/es.yml @@ -113,6 +113,8 @@ advanceTickets: advanceWithoutNegativeTitle: Adelantar tickets (sin negativos) advanceWithoutNegativeSubtitle: '¿Desea adelantar {selectedTickets} tickets?' errorsList: Lista de errores + search: Buscar por tickets adelantados + searchInfo: Buscar tickets adelantados por el identificador o el identificador del cliente futureTickets: problems: Problemas ticketId: ID @@ -242,3 +244,20 @@ ticketList: summary: Resumen client: Cliente 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