import { defineStore } from 'pinia'; import { useUserConfig } from 'src/composables/useUserConfig'; import { exportFile } from 'quasar'; import { useArrayData } from 'composables/useArrayData'; import useNotify from 'src/composables/useNotify.js'; import axios from 'axios'; const { notify } = useNotify(); export const useInvoiceOutGlobalStore = defineStore({ id: 'invoiceOutGlobal', state: () => ({ initialDataLoading: true, formInitialData: { companyFk: null, invoiceDate: null, maxShipped: null, clientId: null, printer: null, serialType: 'global', }, addresses: [], minInvoicingDate: null, parallelism: null, invoicing: false, isInvoicing: false, status: null, addressIndex: 0, errors: [], printer: null, nRequests: 0, nPdfs: 0, totalPdfs: 0, }), actions: { async init() { await this.fetchAllData(); }, async fetchAllData() { try { const date = Date.vnNew(); this.formInitialData.maxShipped = new Date( date.getFullYear(), date.getMonth(), 0 ) .toISOString() .substring(0, 10); await Promise.all([ this.fetchParallelism(), this.fetchInvoiceOutConfig(), ]); this.initialDataLoading = false; } catch (err) { console.error('Error fetching invoice out global initial data'); } }, async fetchInvoiceOutConfig(formData = this.formInitialData) { try { const userInfo = await useUserConfig().fetch(); const params = { companyFk: userInfo.companyFk, serialType: formData.serialType, }; const { data } = await axios.get('InvoiceOuts/getInvoiceDate', { params, }); this.minInvoicingDate = data?.issued ? new Date(data.issued) : Date.vnNew(); this.formInitialData.invoiceDate = this.minInvoicingDate; formData.invoiceDate = this.minInvoicingDate; } catch (err) { console.error('Error fetching invoice out global initial data'); throw new Error(); } }, async fetchParallelism() { const filter = { fields: ['parallelism'] }; const { data } = await axios.get('InvoiceOutConfigs/findOne', { filter, }); this.parallelism = data.parallelism; }, async makeInvoice(formData, clientsToInvoice) { this.invoicing = true; const promises = []; try { this.printer = formData.printer; const params = { invoiceDate: new Date(formData.invoiceDate), maxShipped: new Date(formData.maxShipped), clientId: formData.clientId ? formData.clientId : null, companyFk: formData.companyFk, serialType: formData.serialType, }; this.validateMakeInvoceParams(params, clientsToInvoice); if (clientsToInvoice == 'all') params.clientId = undefined; const { data } = await axios.post('InvoiceOuts/clientsToInvoice', params); this.addresses = data; if (!this.addresses || !this.addresses.length > 0) { notify( 'invoiceOut.globalInvoices.errors.noTicketsToInvoice', 'negative' ); throw new Error("There aren't addresses to invoice"); } this.status = 'invoicing'; for (let index = 0; index < this.parallelism; index++) { promises.push(this.invoiceClient(formData, index)); } await Promise.all(promises); } catch (err) { this.handleError(err); } }, validateMakeInvoceParams(params, clientsToInvoice) { if (clientsToInvoice === 'one' && !params.clientId) { notify('invoiceOut.globalInvoices.errors.chooseValidClient', 'negative'); throw new Error('Invalid client'); } if (!params.invoiceDate || !params.maxShipped) { notify('invoiceOut.globalInvoices.errors.fillDates', 'negative'); throw new Error('Missing dates'); } if (params.invoiceDate < params.maxShipped) { notify( 'invoiceOut.globalInvoices.errors.invoiceDateLessThanMaxDate', 'negative' ); throw new Error('Invalid date range'); } const invoiceDateTime = new Date(params.invoiceDate).getTime(); const minInvoiceDateTime = new Date(this.minInvoicingDate).getTime(); if (this.minInvoicingDate && invoiceDateTime < minInvoiceDateTime) { notify( 'invoiceOut.globalInvoices.errors.invoiceWithFutureDate', 'negative' ); throw new Error('Invoice date in the future'); } if (!params.serialType) { notify( 'invoiceOut.globalInvoices.errors.chooseValidSerialType', 'negative' ); throw new Error('Invalid Serial Type'); } if (clientsToInvoice === 'all' && params.serialType !== 'global') { notify( 'invoiceOut.globalInvoices.errors.invalidSerialTypeForAll', 'negative' ); throw new Error('For "all" clients, the serialType must be "global"'); } if (!params.companyFk) { notify('invoiceOut.globalInvoices.errors.chooseValidCompany', 'negative'); throw new Error('Invalid company'); } if (!this.printer) { notify('invoiceOut.globalInvoices.errors.chooseValidPrinter', 'negative'); throw new Error('Invalid printer'); } }, async invoiceClient(formData, index) { const address = this.addresses[index]; if (!address || !this.status || this.status == 'stopping') { this.status = 'stopping'; this.invoicing = false; return; } try { const params = { clientId: address.clientId, addressId: address.id, invoiceDate: new Date(formData.invoiceDate), maxShipped: new Date(formData.maxShipped), companyFk: formData.companyFk, serialType: formData.serialType, }; this.invoicing = true; const { data } = await axios.post('InvoiceOuts/invoiceClient', params); if (data) await this.makePdfAndNotify(data, address); this.isInvoicing = false; } catch (err) { if (err?.response?.status >= 400 && err?.response?.status < 500) { this.invoiceClientError(address, err.response?.data?.error?.message); return; } else { this.invoicing = false; notify( 'invoiceOut.globalInvoices.errors.criticalInvoiceError', 'negative' ); throw new Error('Critical invoicing error, process stopped'); } } finally { this.addressIndex++; if (this.status != 'stopping') await this.invoiceClient(formData, this.addressIndex); } }, async makePdfAndNotify(invoiceId, client) { try { this.nRequests++; this.totalPdfs++; const params = { printerFk: this.printer }; await axios.post(`InvoiceOuts/${invoiceId}/makePdfAndNotify`, params); this.nPdfs++; this.nRequests--; } catch (err) { this.invoiceClientError(client, err.response?.data?.error?.message, true); } }, invoiceClientError(client, message, isWarning) { this.errors.unshift({ client, message, isWarning }); }, handleError(err) { this.invoicing = false; throw err; }, async getNegativeBasesCsv() { try { const arrayData = useArrayData('InvoiceOutNegative'); const params = arrayData.store.userParams; const { data } = await axios.get('InvoiceOuts/negativeBasesCsv', { params, }); if (data?.data?.error) throw new Error(); const status = exportFile('negativeBases.csv', data, { encoding: 'windows-1252', mimeType: 'text/csv;charset=windows-1252;', }); if (status) { notify('globals.downloadCSVSuccess', 'positive'); } } catch (err) { notify('invoiceOut.negativeBases.errors.downloadCsvFailed', 'negative'); throw new Error(); } }, // State mutations actions setStatusValue(status) { this.status = status; }, }, getters: { getNAddresses(state) { return state.addresses.length; }, getPercentage(state) { if (this.getNAdresses <= 0 || !state.addressIndex) { return 0; } let porcentaje = (state.addressIndex / this.getNAddresses) * 100; return porcentaje?.toFixed(2); }, getAddressNumber(state) { return state.addressIndex; }, }, });