Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

36 - generate financial report #18

Merged
merged 13 commits into from
Sep 5, 2024
52 changes: 38 additions & 14 deletions src/Controllers/financialReportController.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
);
res.sendFile(filePath, (err) => {
if (err) {
console.error("Erro ao enviar o arquivo:", err);

Check warning on line 22 in src/Controllers/financialReportController.js

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
res.status(500).send("Erro ao enviar o arquivo.");
} else {
fs.unlinkSync(filePath); // Remover arquivo após envio
Expand All @@ -30,7 +30,7 @@
// Função simples de sanitização
const sanitizeInput = (input) => {
if (typeof input === "string") {
return input.replace(/[^\w\s\-.,@]/g, ""); // Remover caracteres perigosos, mantendo letras, números, espaços, etc.
return input; // Permite caracteres especiais
}
return input;
};
Expand All @@ -51,35 +51,36 @@
formArquivo,
dataInicio,
dataFinal,
includeFields,
} = req.body;

// Sanitizar entradas
const sanitizedNomeOrigem = sanitizeInput(nomeOrigem);
const sanitizedContaOrigem = sanitizeInput(contaOrigem);
const sanitizedContaDestino = sanitizeInput(contaDestino);
const sanitizedNomeDestino = sanitizeInput(nomeDestino);
const sanitizedTipoDocumento = sanitizeInput(tipoDocumento);
const sanitizedSitPagamento = sanitizeInput(sitPagamento);

// Construir a consulta incluindo contaOrigem e contaDestino
const query = {};

// Adiciona os outros parâmetros da consulta se estiverem presentes
if (sanitizedNomeOrigem) query.nomeOrigem = sanitizedNomeOrigem;
if (sanitizedContaOrigem) query.contaOrigem = sanitizedContaOrigem;
if (sanitizedContaDestino) query.contaDestino = sanitizedContaDestino;
if (sanitizedTipoDocumento)
query.tipoDocumento = sanitizedTipoDocumento;
if (sanitizedNomeDestino) query.nomeDestino = sanitizedNomeDestino;
if (sanitizedSitPagamento) query.sitPagamento = sanitizedSitPagamento;

// Trata as datas de pagamento corretamente
if (sanitizedSitPagamento) {
if (sanitizedSitPagamento === "Pago") {
query.datadePagamento = { $exists: true, $ne: null };
} else if (sanitizedSitPagamento === "Não pago") {
query.datadePagamento = { $eq: null };
}
}
if (dataInicio && !dataFinal) {
query.datadePagamento = { $gte: new Date(dataInicio) };
query.datadeVencimento = { $gte: new Date(dataInicio) };
} else if (!dataInicio && dataFinal) {
query.datadePagamento = { $lte: new Date(dataFinal) };
query.datadeVencimento = { $lte: new Date(dataFinal) };
} else if (dataInicio && dataFinal) {
query.datadePagamento = {
query.datadeVencimento = {
$gte: new Date(dataInicio),
$lte: new Date(dataFinal),
};
Expand All @@ -88,7 +89,6 @@
console.log("Consulta gerada para o banco de dados:", query);

const financialMovements = await FinancialMovements.find(query);

console.log(
"Movimentações financeiras encontradas:",
financialMovements.length
Expand All @@ -100,6 +100,22 @@
.send("Nenhuma movimentação financeira encontrada.");
}

let includeFieldsArray = Object.keys(includeFields).filter(
(key) => includeFields[key] === true
);

const mandatoryFields = [
"contaOrigem",
"contaDestino",
"nomeOrigem",
"nomeDestino",
];
includeFieldsArray = mandatoryFields.concat(
includeFieldsArray.filter(
(field) => !mandatoryFields.includes(field)
)
);

let filePath;
if (formArquivo === "PDF") {
filePath = path.join(
Expand All @@ -108,7 +124,11 @@
`financial_report.pdf`
);
ensureDirectoryExistence(filePath);
await generateFinancialReportPDF(financialMovements, filePath);
await generateFinancialReportPDF(
financialMovements,
filePath,
includeFieldsArray
);
sendAndDeleteFile(res, filePath, "application/pdf");
} else if (formArquivo === "CSV") {
filePath = path.join(
Expand All @@ -117,7 +137,11 @@
`financial_report.csv`
);
ensureDirectoryExistence(filePath);
await generateFinancialReportCSV(financialMovements, filePath);
await generateFinancialReportCSV(
financialMovements,
filePath,
includeFieldsArray
);
sendAndDeleteFile(res, filePath, "text/csv");
} else {
res.status(400).send("Formato de arquivo inválido.");
Expand Down
63 changes: 48 additions & 15 deletions src/Models/csvGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,66 @@ const formatNumericDate = (date) => {
return `${day}/${month}/${year}`;
};

const generateFinancialReportCSV = (financialMovements, filePath) => {
const generateFinancialReportCSV = (
financialMovements,
filePath,
includeFields
) => {
return new Promise((resolve, reject) => {
try {
const fields = [
{ label: "Conta Origem", value: "contaOrigem" },
{ label: "Conta Destino", value: "contaDestino" },
{ label: "Nome Origem", value: "nomeOrigem" },
{ label: "Nome Destino", value: "nomeDestino" },
{ label: "Tipo Documento", value: "tipoDocumento" },
{ label: "Valor Bruto", value: "valorBruto" },
{ label: "Valor Líquido", value: "valorLiquido" },
{ label: "Forma de Pagamento", value: "formadePagamento" },
{
// Define todos os campos possíveis
const allFields = {
tipoDocumento: {
label: "Tipo Documento",
value: "tipoDocumento",
},
valorBruto: { label: "Valor Bruto", value: "valorBruto" },
valorLiquido: { label: "Valor Líquido", value: "valorLiquido" },
contaOrigem: { label: "Conta Origem", value: "contaOrigem" },
nomeOrigem: { label: "Nome Origem", value: "nomeOrigem" },
contaDestino: { label: "Conta Destino", value: "contaDestino" },
nomeDestino: { label: "Nome Destino", value: "nomeDestino" },
dataVencimento: {
label: "Data de Vencimento",
value: (row) => formatNumericDate(row.datadeVencimento),
},
{
dataPagamento: {
label: "Data de Pagamento",
value: (row) => formatNumericDate(row.datadePagamento),
},
{
formaPagamento: {
label: "Forma de Pagamento",
value: "formadePagamento",
},
sitPagamento: {
label: "Situação de Pagamento",
value: (row) => (row.baixada ? "Pago" : "Não pago"),
value: (row) => (row.datadePagamento ? "Pago" : "Não pago"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essa validação deve conferir se, além da data de pagamento preenchida, essa data é menor ou igual a data atual para ser considerada paga

},
{ label: "Descrição", value: "descricao" },
descricao: { label: "Descrição", value: "descricao" },
};

// Reorder the includeFields array based on the desired order
const orderedFields = [
"tipoDocumento",
"valorBruto",
"valorLiquido",
"contaOrigem",
"nomeOrigem",
"contaDestino",
"nomeDestino",
"dataVencimento",
"dataPagamento",
"formaPagamento",
"sitPagamento",
"descricao",
];

// Filtra os campos com base no array `orderedFields`
const fields = orderedFields
.filter((field) => includeFields.includes(field)) // Filtra para pegar apenas os campos selecionados
.map((field) => allFields[field]); // Mapeia para o formato necessário pelo `json2csv`

// Gera o CSV com os campos filtrados
const csv = parse(financialMovements, { fields });

fs.writeFileSync(filePath, csv);
Expand Down
1 change: 0 additions & 1 deletion src/Models/financialMovementsSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ const financialMovementsSchema = new mongoose.Schema({
datadePagamento: {
type: Date,
default: Date.now,
required: true,
},
baixada: {
type: Boolean,
Expand Down
142 changes: 120 additions & 22 deletions src/Models/pdfGenerator.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,148 @@
const PDFDocument = require("pdfkit");
const fs = require("fs");
const path = require("path");

const formatDate = (date) => {
if (!date) return "N/A";
const options = {
weekday: "long",
year: "numeric",
month: "long",
month: "numeric",
day: "numeric",
};
return new Date(date).toLocaleDateString("pt-BR", options);
};

const generateFinancialReportPDF = (financialMovements, filePath) => {
const generateFinancialReportPDF = (
financialMovements,
filePath,
includeFields
) => {
return new Promise((resolve, reject) => {
const doc = new PDFDocument({ margin: 30 });
const stream = fs.createWriteStream(filePath);

// Calcula o somatório dos valores líquidos
const totalValorBruto = financialMovements.reduce((total, movement) => {
return total + (movement.valorBruto || 0);
}, 0);

// Path to the logo
const logoPath = path.join(__dirname, "../assets/sindpol-logo.png");
const logoSize = 50;
const marginRight = 30;
const logoTopMargin = 30;

doc.pipe(stream);

doc.fontSize(18).text("Relatório Financeiro", { align: "center" });
// Function to add the logo to the top right of the current page
const addLogo = () => {
const logoXPosition = doc.page.width - marginRight - logoSize;
doc.image(logoPath, logoXPosition, logoTopMargin, {
width: logoSize,
height: logoSize,
});
};

// Add the logo to the first page
addLogo();

// Add the logo to each new page
doc.on("pageAdded", addLogo);

// Position the title text to align with the logo
const textXPosition = marginRight; // Align the text on the left margin
const titleYPosition = logoTopMargin + logoSize / 2 - 9; // Centered vertically with the logo
doc.fontSize(18).text(
"Relatório Financeiro",
textXPosition,
titleYPosition
);

// Add the total value below the title
doc.fontSize(12).text(
`Valor bruto total do período: R$ ${totalValorBruto.toFixed(2)}`,
textXPosition,
titleYPosition + 20
);

doc.moveDown();

financialMovements.forEach((movement, index) => {
doc.fontSize(12)
.text(`Movimento #${index + 1}`, { underline: true })
.text(`Movimentação financeira #${index + 1}`, {
underline: true,
})
.moveDown();

doc.text(`Conta Origem: ${movement.contaOrigem}`);
doc.text(`Conta Destino: ${movement.contaDestino}`);
doc.text(`Nome Origem: ${movement.nomeOrigem}`);
doc.text(`Nome Destino: ${movement.nomeDestino}`);
doc.text(`Tipo Documento: ${movement.tipoDocumento}`);
doc.text(`Valor Bruto: ${movement.valorBruto}`);
doc.text(`Valor Líquido: ${movement.valorLiquido || "N/A"}`);
doc.text(`Forma de Pagamento: ${movement.formadePagamento}`);
doc.text(
`Data de Vencimento: ${formatDate(movement.datadeVencimento)}`
);
doc.text(
`Data de Pagamento: ${formatDate(movement.datadePagamento)}`
);
doc.text(
`Situação de Pagamento: ${movement.baixada ? "Pago" : "Não pago"}`
);
doc.text(`Descrição: ${movement.descricao || "N/A"}`);
// Add the fields based on includeFields
if (includeFields.includes("tipoDocumento")) {
doc.text(`Tipo Documento: ${movement.tipoDocumento}`);
}
if (includeFields.includes("valorBruto")) {
doc.text(`Valor Bruto: R$ ${movement.valorBruto}`);
}
if (includeFields.includes("valorLiquido")) {
doc.text(`Valor Líquido: R$ ${movement.valorLiquido || "N/A"}`);
}
if (
includeFields.includes("contaOrigem") ||
includeFields.includes("nomeOrigem")
) {
let contaOrigemText = includeFields.includes("contaOrigem")
? `Conta Origem: ${movement.contaOrigem}`
: "";
let nomeOrigemText = includeFields.includes("nomeOrigem")
? `${movement.nomeOrigem}`
: "";
if (contaOrigemText && nomeOrigemText) {
doc.text(`${contaOrigemText} - ${nomeOrigemText}`);
} else if (contaOrigemText) {
doc.text(contaOrigemText);
} else if (nomeOrigemText) {
doc.text(nomeOrigemText);
}
}
if (
includeFields.includes("contaDestino") ||
includeFields.includes("nomeDestino")
) {
let contaDestinoText = includeFields.includes("contaDestino")
? `Conta Destino: ${movement.contaDestino}`
: "";
let nomeDestinoText = includeFields.includes("nomeDestino")
? `${movement.nomeDestino}`
: "";
if (contaDestinoText && nomeDestinoText) {
doc.text(`${contaDestinoText} - ${nomeDestinoText}`);
} else if (contaDestinoText) {
doc.text(contaDestinoText);
} else if (nomeDestinoText) {
doc.text(nomeDestinoText);
}
}
if (includeFields.includes("dataVencimento")) {
doc.text(
`Data de Vencimento: ${formatDate(movement.datadeVencimento)}`
);
}
if (includeFields.includes("dataPagamento")) {
doc.text(
`Data de Pagamento: ${formatDate(movement.datadePagamento)}`
);
}
if (includeFields.includes("sitPagamento")) {
const situacaoPagamento = movement.datadePagamento
? "Pago"
: "Não pago";
doc.text(`Situação de Pagamento: ${situacaoPagamento}`);
}
if (includeFields.includes("formaPagamento")) {
doc.text(`Forma de Pagamento: ${movement.formadePagamento}`);
}
if (includeFields.includes("descricao")) {
doc.text(`Descrição: ${movement.descricao || "N/A"}`);
}

doc.moveDown();
});
Expand Down
Loading
Loading