Add csv download feature and add descriptors

This commit is contained in:
William Buezas 2023-11-28 10:11:24 -03:00
parent df00ec99eb
commit 7646934431
7 changed files with 83 additions and 48 deletions

View File

@ -2,10 +2,17 @@ import { Notify } from 'quasar';
import { i18n } from 'src/boot/i18n'; import { i18n } from 'src/boot/i18n';
export default function useNotify() { export default function useNotify() {
const notify = (message, type) => { const notify = (message, type, icon) => {
const defaultIcons = {
warning: 'warning',
negative: 'error',
positive: 'check',
};
Notify.create({ Notify.create({
message: i18n.global.t(message), message: i18n.global.t(message),
type: type, type: type,
icon: icon ? icon : defaultIcons[type],
}); });
}; };

View File

@ -37,6 +37,7 @@ export default {
basicData: 'Basic data', basicData: 'Basic data',
}, },
noSelectedRows: `You don't have any line selected`, noSelectedRows: `You don't have any line selected`,
downloadCSVSuccess: 'CSV downloaded successfully',
}, },
errors: { errors: {
statusUnauthorized: 'Access denied', statusUnauthorized: 'Access denied',
@ -422,6 +423,9 @@ export default {
hasToInvoice: 'Has to Invoice', hasToInvoice: 'Has to Invoice',
verifiedData: 'Verified Data', verifiedData: 'Verified Data',
comercial: 'Comercial', comercial: 'Comercial',
errors: {
downloadCsvFailed: 'CSV download failed',
},
}, },
}, },
shelving: { shelving: {

View File

@ -37,6 +37,7 @@ export default {
basicData: 'Datos básicos', basicData: 'Datos básicos',
}, },
noSelectedRows: `No tienes ninguna línea seleccionada`, noSelectedRows: `No tienes ninguna línea seleccionada`,
downloadCSVSuccess: 'Descarga de CSV exitosa',
}, },
errors: { errors: {
statusUnauthorized: 'Acceso denegado', statusUnauthorized: 'Acceso denegado',
@ -424,6 +425,9 @@ export default {
hasToInvoice: 'Facturar', hasToInvoice: 'Facturar',
verifiedData: 'Datos comprobados', verifiedData: 'Datos comprobados',
comercial: 'Comercial', comercial: 'Comercial',
errors: {
downloadCsvFailed: 'Error al descargar CSV',
},
}, },
}, },
shelving: { shelving: {

View File

@ -1,21 +1,26 @@
<script setup> <script setup>
import { onMounted, computed, ref } from 'vue'; import { onMounted, ref, reactive } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import invoiceOutService from 'src/services/invoiceOut.service'; import invoiceOutService from 'src/services/invoiceOut.service';
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
import { QBadge, QBtn, exportFile } from 'quasar'; import { QBadge, QBtn } from 'quasar';
import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js';
import { toDate } from 'src/filters'; import { toDate } from 'src/filters';
const invoiceOutGlobalStore = useInvoiceOutGlobalStore();
const rows = ref([]); const rows = ref([]);
const { t } = useI18n(); const { t } = useI18n();
const payload = ref({ const dateRange = reactive({
from: Date.vnFirstDayOfMonth(), from: Date.vnFirstDayOfMonth(),
to: Date.vnLastDayOfMonth(), to: Date.vnLastDayOfMonth(),
}); });
const selectedCustomerId = ref(0); const selectedCustomerId = ref(0);
const selectedWorkerId = ref(0);
const filter = ref({ const filter = ref({
company: null, company: null,
@ -35,10 +40,12 @@ const tableColumnComponents = {
company: { company: {
component: 'span', component: 'span',
props: {}, props: {},
event: () => {},
}, },
country: { country: {
component: 'span', component: 'span',
props: {}, props: {},
event: () => {},
}, },
clientId: { clientId: {
component: QBtn, component: QBtn,
@ -48,34 +55,42 @@ const tableColumnComponents = {
client: { client: {
component: 'span', component: 'span',
props: {}, props: {},
event: () => {},
}, },
amount: { amount: {
component: 'span', component: 'span',
props: {}, props: {},
event: () => {},
}, },
base: { base: {
component: 'span', component: 'span',
props: {}, props: {},
event: () => {},
}, },
ticketId: { ticketId: {
component: 'span', component: 'span',
props: {}, props: {},
event: () => {},
}, },
active: { active: {
component: 'span', component: 'span',
props: { type: 'boolean' }, props: { type: 'boolean' },
event: () => {},
}, },
hasToInvoice: { hasToInvoice: {
component: 'span', component: 'span',
props: { type: 'boolean' }, props: { type: 'boolean' },
event: () => {},
}, },
verifiedData: { verifiedData: {
component: 'span', component: 'span',
props: { type: 'boolean' }, props: { type: 'boolean' },
event: () => {},
}, },
comercial: { comercial: {
component: QBtn, component: QBtn,
props: { flat: true, color: 'blue' }, props: { flat: true, color: 'blue' },
event: (prop) => selectWorkerId(prop.row.comercialId),
}, },
}; };
@ -149,37 +164,8 @@ const columns = ref([
}, },
]); ]);
const wrapCsvValue = (val, formatFn, row) => { const downloadCSV = async () => {
let formatted = formatFn !== void 0 ? formatFn(val, row) : val; invoiceOutGlobalStore.getNegativeBasesCsv(dateRange.from, dateRange.to);
formatted = formatted === void 0 || formatted === null ? '' : String(formatted);
formatted = formatted.split('"').join('""');
return `"${formatted}"`;
};
const exportTable = () => {
const content = [columns.value.map((col) => wrapCsvValue(col.label))]
.concat(
rows.value.map((row) =>
columns.value
.map((col) =>
wrapCsvValue(
typeof col.field === 'function'
? col.field(row)
: row[col.field === void 0 ? col.name : col.field],
col.format,
row
)
)
.join(',')
)
)
.join('\r\n');
const status = exportFile('table-export.csv', content, 'text/csv');
if (status !== true) {
console.log('Browser denied file download...');
}
}; };
const search = async () => { const search = async () => {
@ -193,7 +179,7 @@ const search = async () => {
}); });
const params = { const params = {
...payload.value, ...dateRange,
filter: { filter: {
limit: 20, limit: 20,
where: { and }, where: { and },
@ -203,10 +189,8 @@ const search = async () => {
}; };
const refresh = () => { const refresh = () => {
payload.value = { dateRange.from = Date.vnFirstDayOfMonth();
from: Date.vnFirstDayOfMonth(), dateRange.to = Date.vnLastDayOfMonth();
to: Date.vnLastDayOfMonth(),
};
filter.value = { filter.value = {
company: null, company: null,
country: null, country: null,
@ -227,6 +211,10 @@ const selectCustomerId = (id) => {
selectedCustomerId.value = id; selectedCustomerId.value = id;
}; };
const selectWorkerId = (id) => {
selectedWorkerId.value = id;
};
onMounted(async () => { onMounted(async () => {
refresh(); refresh();
}); });
@ -252,7 +240,7 @@ onMounted(async () => {
placeholder="dd-mm-aaa" placeholder="dd-mm-aaa"
:label="t('invoiceOut.negativeBases.from')" :label="t('invoiceOut.negativeBases.from')"
class="q-mr-md q" class="q-mr-md q"
:model-value="toDate(payload.from)" :model-value="toDate(dateRange.from)"
> >
<template #append> <template #append>
<QIcon name="event" class="cursor-pointer"> <QIcon name="event" class="cursor-pointer">
@ -261,7 +249,7 @@ onMounted(async () => {
transition-show="scale" transition-show="scale"
transition-hide="scale" transition-hide="scale"
> >
<QDate v-model="payload.from"> <QDate v-model="dateRange.from">
<div class="row items-center justify-end"> <div class="row items-center justify-end">
<QBtn <QBtn
v-close-popup v-close-popup
@ -275,7 +263,6 @@ onMounted(async () => {
</QIcon> </QIcon>
</template> </template>
</QInput> </QInput>
<QInput <QInput
dense dense
lazy-rules lazy-rules
@ -284,7 +271,7 @@ onMounted(async () => {
placeholder="dd-mm-aaa" placeholder="dd-mm-aaa"
:label="t('invoiceOut.negativeBases.to')" :label="t('invoiceOut.negativeBases.to')"
class="q-mr-md q" class="q-mr-md q"
:model-value="toDate(payload.to)" :model-value="toDate(dateRange.to)"
> >
<template #append> <template #append>
<QIcon name="event" class="cursor-pointer"> <QIcon name="event" class="cursor-pointer">
@ -293,7 +280,7 @@ onMounted(async () => {
transition-show="scale" transition-show="scale"
transition-hide="scale" transition-hide="scale"
> >
<QDate v-model="payload.to"> <QDate v-model="dateRange.to">
<div class="row items-center justify-end"> <div class="row items-center justify-end">
<QBtn <QBtn
v-close-popup v-close-popup
@ -311,7 +298,7 @@ onMounted(async () => {
color="primary" color="primary"
icon-right="archive" icon-right="archive"
no-caps no-caps
@click="exportTable" @click="downloadCSV()"
/> />
</div> </div>
</template> </template>
@ -384,7 +371,15 @@ onMounted(async () => {
<QIcon name="" size="xs" /> <QIcon name="" size="xs" />
</QBadge> </QBadge>
</span> </span>
<CustomerDescriptorProxy :id="selectedCustomerId" />
<CustomerDescriptorProxy
v-if="props.col.name === 'clientId'"
:id="selectedCustomerId"
/>
<WorkerDescriptorProxy
v-if="props.col.name === 'comercial'"
:id="selectedWorkerId"
/>
</component> </component>
</QTd> </QTd>
</template> </template>

View File

@ -73,8 +73,8 @@ const isAdministrative = computed(() => {
<span class="link"> <span class="link">
{{ supplier.worker?.user?.nickname || '-' }} {{ supplier.worker?.user?.nickname || '-' }}
<WorkerDescriptorProxy <WorkerDescriptorProxy
:id="supplier.worker?.user?.id"
v-if="supplier.worker?.user?.id" v-if="supplier.worker?.user?.id"
:id="supplier.worker?.user?.id"
/> />
</span> </span>
</template> </template>

View File

@ -21,6 +21,10 @@ const invoiceOutService = {
return await request('GET', 'InvoiceOuts/negativeBases', params); return await request('GET', 'InvoiceOuts/negativeBases', params);
}, },
getNegativeBasesCsv: async (params) => {
return await request('GET', 'InvoiceOuts/negativeBasesCsv', params);
},
getInvoiceDate: async (params) => { getInvoiceDate: async (params) => {
return await request('GET', 'InvoiceOuts/getInvoiceDate', params); return await request('GET', 'InvoiceOuts/getInvoiceDate', params);
}, },

View File

@ -2,6 +2,7 @@ import { defineStore } from 'pinia';
import { useUserConfig } from 'src/composables/useUserConfig'; import { useUserConfig } from 'src/composables/useUserConfig';
import invoiceOutService from 'src/services/invoiceOut.service'; import invoiceOutService from 'src/services/invoiceOut.service';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import { exportFile } from 'quasar';
const { notify } = useNotify(); const { notify } = useNotify();
@ -257,6 +258,26 @@ export const useInvoiceOutGlobalStore = defineStore({
throw err; throw err;
}, },
async getNegativeBasesCsv(from, to) {
try {
const params = { from: from, to: to };
const CSVResponse = await invoiceOutService.getNegativeBasesCsv(params);
if (CSVResponse.data && CSVResponse.data.error) throw new Error();
const status = exportFile('negativeBases.csv', CSVResponse, {
encoding: 'windows-1252',
mimeType: 'text/csv;charset=windows-1252;',
});
if (status) {
notify('globals.downloadCSVSuccess', 'positive');
}
} catch (err) {
notify('invoiceOut.negativeBases.errors.downloadCsvFailed', 'negative');
}
},
// State mutations actions // State mutations actions
setPrinterValue(printer) { setPrinterValue(printer) {