chore: Fix .env.test quotes and format frontend code
- Fix TEST_ORACLE_USER quotes in .env.test for shell source compatibility - Format 14 frontend files with Prettier (stores, views, utils) - All 122 tests passing (77 telegram + 35 backend + 10 E2E) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
import * as XLSX from 'xlsx';
|
||||
import { jsPDF } from 'jspdf';
|
||||
import autoTable from 'jspdf-autotable';
|
||||
import * as XLSX from "xlsx";
|
||||
import { jsPDF } from "jspdf";
|
||||
import autoTable from "jspdf-autotable";
|
||||
|
||||
/**
|
||||
* Format currency values for export
|
||||
*/
|
||||
const formatCurrency = (value) => {
|
||||
if (value == null || value === '-') return '-';
|
||||
return new Intl.NumberFormat('ro-RO', {
|
||||
style: 'currency',
|
||||
currency: 'RON',
|
||||
if (value == null || value === "-") return "-";
|
||||
return new Intl.NumberFormat("ro-RO", {
|
||||
style: "currency",
|
||||
currency: "RON",
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
maximumFractionDigits: 0,
|
||||
}).format(value);
|
||||
};
|
||||
|
||||
@@ -21,15 +21,18 @@ const formatCurrency = (value) => {
|
||||
* @param {String} filename - Name of the file (without extension)
|
||||
* @param {String} sheetName - Name of the Excel sheet
|
||||
*/
|
||||
export const exportToExcel = (data, filename, sheetName = 'Sheet1') => {
|
||||
export const exportToExcel = (data, filename, sheetName = "Sheet1") => {
|
||||
try {
|
||||
const ws = XLSX.utils.json_to_sheet(data);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, sheetName);
|
||||
XLSX.writeFile(wb, `${filename}_${new Date().toISOString().split('T')[0]}.xlsx`);
|
||||
XLSX.writeFile(
|
||||
wb,
|
||||
`${filename}_${new Date().toISOString().split("T")[0]}.xlsx`,
|
||||
);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Excel export failed:', error);
|
||||
console.error("Excel export failed:", error);
|
||||
return { success: false, error };
|
||||
}
|
||||
};
|
||||
@@ -38,12 +41,12 @@ export const exportToExcel = (data, filename, sheetName = 'Sheet1') => {
|
||||
* Format number for PDF export
|
||||
*/
|
||||
const formatNumberForPDF = (value) => {
|
||||
if (value == null || value === '' || value === '-') return '-';
|
||||
if (value == null || value === "" || value === "-") return "-";
|
||||
const num = parseFloat(value);
|
||||
if (isNaN(num)) return '-';
|
||||
return new Intl.NumberFormat('ro-RO', {
|
||||
if (isNaN(num)) return "-";
|
||||
return new Intl.NumberFormat("ro-RO", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
maximumFractionDigits: 2,
|
||||
}).format(num);
|
||||
};
|
||||
|
||||
@@ -58,17 +61,17 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
try {
|
||||
// Check if data exists
|
||||
if (!data || data.length === 0) {
|
||||
console.error('No data to export');
|
||||
return { success: false, error: 'No data available' };
|
||||
console.error("No data to export");
|
||||
return { success: false, error: "No data available" };
|
||||
}
|
||||
|
||||
// Check if jsPDF is properly imported
|
||||
if (typeof jsPDF === 'undefined') {
|
||||
console.error('jsPDF not properly imported');
|
||||
return { success: false, error: 'PDF library not available' };
|
||||
if (typeof jsPDF === "undefined") {
|
||||
console.error("jsPDF not properly imported");
|
||||
return { success: false, error: "PDF library not available" };
|
||||
}
|
||||
|
||||
const doc = new jsPDF('landscape', 'mm', 'a4');
|
||||
const doc = new jsPDF("landscape", "mm", "a4");
|
||||
const pageWidth = doc.internal.pageSize.getWidth();
|
||||
const pageHeight = doc.internal.pageSize.getHeight();
|
||||
const marginLeft = 8;
|
||||
@@ -79,38 +82,38 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
const addHeader = () => {
|
||||
// Line 1: Company name (left aligned, bold, larger font)
|
||||
doc.setFontSize(13);
|
||||
doc.setFont(undefined, 'bold');
|
||||
const companyName = header.companyName || 'N/A';
|
||||
doc.setFont(undefined, "bold");
|
||||
const companyName = header.companyName || "N/A";
|
||||
doc.text(companyName, marginLeft, 15);
|
||||
|
||||
// Line 2: Title "Balanta de Verificare" (centered)
|
||||
doc.setFontSize(14);
|
||||
doc.setFont(undefined, 'bold');
|
||||
const titleWidth = doc.getTextWidth(header.title || '');
|
||||
doc.setFont(undefined, "bold");
|
||||
const titleWidth = doc.getTextWidth(header.title || "");
|
||||
const titleX = marginLeft + (contentWidth - titleWidth) / 2;
|
||||
doc.text(header.title || '', titleX, 24);
|
||||
doc.text(header.title || "", titleX, 24);
|
||||
|
||||
// Line 3: Period (centered, below title)
|
||||
doc.setFontSize(11);
|
||||
doc.setFont(undefined, 'normal');
|
||||
const periodText = header.period || '';
|
||||
doc.setFont(undefined, "normal");
|
||||
const periodText = header.period || "";
|
||||
const periodWidth = doc.getTextWidth(periodText);
|
||||
const periodX = marginLeft + (contentWidth - periodWidth) / 2;
|
||||
doc.text(periodText, periodX, 32);
|
||||
};
|
||||
|
||||
// Prepare table data
|
||||
const tableColumns = columns.map(col => col.header);
|
||||
const tableRows = data.map(row =>
|
||||
columns.map(col => {
|
||||
const tableColumns = columns.map((col) => col.header);
|
||||
const tableRows = data.map((row) =>
|
||||
columns.map((col) => {
|
||||
const value = row[col.field];
|
||||
if (col.type === 'currency') {
|
||||
if (col.type === "currency") {
|
||||
return formatCurrency(value);
|
||||
} else if (col.type === 'number') {
|
||||
} else if (col.type === "number") {
|
||||
return formatNumberForPDF(value);
|
||||
}
|
||||
return value || '-';
|
||||
})
|
||||
return value || "-";
|
||||
}),
|
||||
);
|
||||
|
||||
// Function to add footer (called for each page)
|
||||
@@ -119,8 +122,12 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
|
||||
// Left side: Generation date
|
||||
doc.setFontSize(8);
|
||||
doc.setFont(undefined, 'normal');
|
||||
doc.text(`Generat: ${new Date().toLocaleString('ro-RO')}`, marginLeft, footerY);
|
||||
doc.setFont(undefined, "normal");
|
||||
doc.text(
|
||||
`Generat: ${new Date().toLocaleString("ro-RO")}`,
|
||||
marginLeft,
|
||||
footerY,
|
||||
);
|
||||
|
||||
// Right side: Page numbers
|
||||
const pageText = `Pagina ${pageNum} din ${totalPages}`;
|
||||
@@ -129,7 +136,7 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
};
|
||||
|
||||
// Check if autoTable is available
|
||||
if (typeof autoTable === 'function') {
|
||||
if (typeof autoTable === "function") {
|
||||
// Build column styles - jspdf-autotable uses numeric keys
|
||||
const columnStyles = {};
|
||||
|
||||
@@ -142,37 +149,37 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
|
||||
columns.forEach((col, index) => {
|
||||
// Use custom width if provided, otherwise auto
|
||||
if (col.width && typeof col.width === 'number') {
|
||||
if (col.width && typeof col.width === "number") {
|
||||
widthAllocations[index] = totalWidth * col.width;
|
||||
} else if (col.width === 'auto') {
|
||||
widthAllocations[index] = 'auto';
|
||||
} else if (col.width === "auto") {
|
||||
widthAllocations[index] = "auto";
|
||||
} else {
|
||||
// Default width allocation for Trial Balance (8 columns)
|
||||
const defaultWidths = {
|
||||
0: totalWidth * 0.07, // Cont: ~20mm
|
||||
1: totalWidth * 0.33, // Denumire: ~93mm
|
||||
2: totalWidth * 0.10, // Sold Prec D: ~28mm
|
||||
3: totalWidth * 0.10, // Sold Prec C: ~28mm
|
||||
4: totalWidth * 0.10, // Rulaj D: ~28mm
|
||||
5: totalWidth * 0.10, // Rulaj C: ~28mm
|
||||
6: totalWidth * 0.10, // Sold Final D: ~28mm
|
||||
7: totalWidth * 0.10, // Sold Final C: ~28mm
|
||||
0: totalWidth * 0.07, // Cont: ~20mm
|
||||
1: totalWidth * 0.33, // Denumire: ~93mm
|
||||
2: totalWidth * 0.1, // Sold Prec D: ~28mm
|
||||
3: totalWidth * 0.1, // Sold Prec C: ~28mm
|
||||
4: totalWidth * 0.1, // Rulaj D: ~28mm
|
||||
5: totalWidth * 0.1, // Rulaj C: ~28mm
|
||||
6: totalWidth * 0.1, // Sold Final D: ~28mm
|
||||
7: totalWidth * 0.1, // Sold Final C: ~28mm
|
||||
};
|
||||
widthAllocations[index] = defaultWidths[index] || 'auto';
|
||||
widthAllocations[index] = defaultWidths[index] || "auto";
|
||||
}
|
||||
});
|
||||
|
||||
columns.forEach((col, index) => {
|
||||
columnStyles[index] = {
|
||||
cellWidth: widthAllocations[index]
|
||||
cellWidth: widthAllocations[index],
|
||||
};
|
||||
|
||||
// Set alignment based on type
|
||||
if (col.type === 'number' || col.type === 'currency') {
|
||||
columnStyles[index].halign = 'right';
|
||||
} else if (col.type === 'text') {
|
||||
if (col.type === "number" || col.type === "currency") {
|
||||
columnStyles[index].halign = "right";
|
||||
} else if (col.type === "text") {
|
||||
// All text columns aligned left (including Cont)
|
||||
columnStyles[index].halign = 'left';
|
||||
columnStyles[index].halign = "left";
|
||||
}
|
||||
});
|
||||
|
||||
@@ -186,44 +193,49 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
styles: {
|
||||
fontSize: 9,
|
||||
cellPadding: 2.5,
|
||||
valign: 'middle',
|
||||
valign: "middle",
|
||||
lineColor: [200, 200, 200],
|
||||
lineWidth: 0.1,
|
||||
overflow: 'linebreak'
|
||||
overflow: "linebreak",
|
||||
},
|
||||
headStyles: {
|
||||
fillColor: [41, 128, 185],
|
||||
textColor: 255,
|
||||
fontStyle: 'bold',
|
||||
halign: 'center',
|
||||
fontStyle: "bold",
|
||||
halign: "center",
|
||||
fontSize: 9,
|
||||
cellPadding: 2.5
|
||||
cellPadding: 2.5,
|
||||
},
|
||||
alternateRowStyles: {
|
||||
fillColor: [248, 248, 248]
|
||||
fillColor: [248, 248, 248],
|
||||
},
|
||||
columnStyles: columnStyles,
|
||||
margin: { left: marginLeft, right: marginRight, top: tableStartY, bottom: 15 },
|
||||
margin: {
|
||||
left: marginLeft,
|
||||
right: marginRight,
|
||||
top: tableStartY,
|
||||
bottom: 15,
|
||||
},
|
||||
tableWidth: pageWidth - marginLeft - marginRight, // Use full page width
|
||||
theme: 'grid',
|
||||
didDrawPage: function(data) {
|
||||
theme: "grid",
|
||||
didDrawPage: function (data) {
|
||||
// Add header to each page
|
||||
addHeader();
|
||||
},
|
||||
didParseCell: function(data) {
|
||||
didParseCell: function (data) {
|
||||
// Force alignment based on column type (body cells only)
|
||||
if (data.section === 'body') {
|
||||
if (data.section === "body") {
|
||||
const colIndex = data.column.index;
|
||||
const column = columns[colIndex];
|
||||
|
||||
if (column) {
|
||||
if (column.type === 'number' || column.type === 'currency') {
|
||||
data.cell.styles.halign = 'right';
|
||||
} else if (column.type === 'text') {
|
||||
if (column.type === "number" || column.type === "currency") {
|
||||
data.cell.styles.halign = "right";
|
||||
} else if (column.type === "text") {
|
||||
if (colIndex === 0) {
|
||||
data.cell.styles.halign = 'center';
|
||||
data.cell.styles.halign = "center";
|
||||
} else {
|
||||
data.cell.styles.halign = 'left';
|
||||
data.cell.styles.halign = "left";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,18 +259,18 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
|
||||
// Draw headers
|
||||
doc.setFontSize(8);
|
||||
doc.setFont(undefined, 'bold');
|
||||
doc.setFont(undefined, "bold");
|
||||
tableColumns.forEach((header, index) => {
|
||||
doc.text(header, 14 + (index * 35), yPos);
|
||||
doc.text(header, 14 + index * 35, yPos);
|
||||
});
|
||||
|
||||
// Draw rows
|
||||
doc.setFont(undefined, 'normal');
|
||||
doc.setFont(undefined, "normal");
|
||||
doc.setFontSize(7);
|
||||
tableRows.forEach((row, rowIndex) => {
|
||||
yPos += 7;
|
||||
row.forEach((cell, cellIndex) => {
|
||||
doc.text(String(cell), 14 + (cellIndex * 35), yPos);
|
||||
doc.text(String(cell), 14 + cellIndex * 35, yPos);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -267,11 +279,11 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
}
|
||||
|
||||
// Save PDF
|
||||
doc.save(`${filename}_${new Date().toISOString().split('T')[0]}.pdf`);
|
||||
doc.save(`${filename}_${new Date().toISOString().split("T")[0]}.pdf`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('PDF export error details:', error);
|
||||
return { success: false, error: error.message || 'PDF generation failed' };
|
||||
console.error("PDF export error details:", error);
|
||||
return { success: false, error: error.message || "PDF generation failed" };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -281,31 +293,31 @@ export const exportToPDF = (data, columns, filename, header) => {
|
||||
export const exportGeneralTotals = (summaryData) => {
|
||||
const data = [
|
||||
{
|
||||
Tip: 'Clienți',
|
||||
'Total Facturat': summaryData?.clienti_total_facturat || 0,
|
||||
'Total Încasat': summaryData?.clienti_total_incasat || 0,
|
||||
'Sold Net': summaryData?.clienti_sold_total || 0,
|
||||
'Sold În Termen': summaryData?.clienti_sold_in_termen || 0,
|
||||
'Sold Restant': summaryData?.clienti_sold_restant || 0
|
||||
Tip: "Clienți",
|
||||
"Total Facturat": summaryData?.clienti_total_facturat || 0,
|
||||
"Total Încasat": summaryData?.clienti_total_incasat || 0,
|
||||
"Sold Net": summaryData?.clienti_sold_total || 0,
|
||||
"Sold În Termen": summaryData?.clienti_sold_in_termen || 0,
|
||||
"Sold Restant": summaryData?.clienti_sold_restant || 0,
|
||||
},
|
||||
{
|
||||
Tip: 'Furnizori',
|
||||
'Total Facturat': summaryData?.furnizori_total_facturat || 0,
|
||||
'Total Achitat': summaryData?.furnizori_total_achitat || 0,
|
||||
'Sold Net': summaryData?.furnizori_sold_total || 0,
|
||||
'Sold În Termen': summaryData?.furnizori_sold_in_termen || 0,
|
||||
'Sold Restant': summaryData?.furnizori_sold_restant || 0
|
||||
Tip: "Furnizori",
|
||||
"Total Facturat": summaryData?.furnizori_total_facturat || 0,
|
||||
"Total Achitat": summaryData?.furnizori_total_achitat || 0,
|
||||
"Sold Net": summaryData?.furnizori_sold_total || 0,
|
||||
"Sold În Termen": summaryData?.furnizori_sold_in_termen || 0,
|
||||
"Sold Restant": summaryData?.furnizori_sold_restant || 0,
|
||||
},
|
||||
{
|
||||
Tip: 'Trezorerie',
|
||||
'Total Facturat': '-',
|
||||
'Total Încasat/Achitat': '-',
|
||||
'Sold Net': summaryData?.trezorerie_sold || 0,
|
||||
'Sold În Termen': '-',
|
||||
'Sold Restant': '-'
|
||||
}
|
||||
Tip: "Trezorerie",
|
||||
"Total Facturat": "-",
|
||||
"Total Încasat/Achitat": "-",
|
||||
"Sold Net": summaryData?.trezorerie_sold || 0,
|
||||
"Sold În Termen": "-",
|
||||
"Sold Restant": "-",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -315,27 +327,27 @@ export const exportGeneralTotals = (summaryData) => {
|
||||
export const exportSoldNetBreakdown = (summaryData) => {
|
||||
const data = [
|
||||
{
|
||||
Categorie: 'Clienți - Restant',
|
||||
'TOTAL': summaryData?.clienti_sold_restant || 0,
|
||||
'7 zile': summaryData?.clienti_restant_7 || 0,
|
||||
'14 zile': summaryData?.clienti_restant_14 || 0,
|
||||
'30 zile': summaryData?.clienti_restant_30 || 0,
|
||||
'60 zile': summaryData?.clienti_restant_60 || 0,
|
||||
'90 zile': summaryData?.clienti_restant_90 || 0,
|
||||
'90+ zile': summaryData?.clienti_restant_over_90 || 0
|
||||
Categorie: "Clienți - Restant",
|
||||
TOTAL: summaryData?.clienti_sold_restant || 0,
|
||||
"7 zile": summaryData?.clienti_restant_7 || 0,
|
||||
"14 zile": summaryData?.clienti_restant_14 || 0,
|
||||
"30 zile": summaryData?.clienti_restant_30 || 0,
|
||||
"60 zile": summaryData?.clienti_restant_60 || 0,
|
||||
"90 zile": summaryData?.clienti_restant_90 || 0,
|
||||
"90+ zile": summaryData?.clienti_restant_over_90 || 0,
|
||||
},
|
||||
{
|
||||
Categorie: 'Furnizori - Restant',
|
||||
'TOTAL': summaryData?.furnizori_sold_restant || 0,
|
||||
'7 zile': summaryData?.furnizori_restant_7 || 0,
|
||||
'14 zile': summaryData?.furnizori_restant_14 || 0,
|
||||
'30 zile': summaryData?.furnizori_restant_30 || 0,
|
||||
'60 zile': summaryData?.furnizori_restant_60 || 0,
|
||||
'90 zile': summaryData?.furnizori_restant_90 || 0,
|
||||
'90+ zile': summaryData?.furnizori_restant_over_90 || 0
|
||||
}
|
||||
Categorie: "Furnizori - Restant",
|
||||
TOTAL: summaryData?.furnizori_sold_restant || 0,
|
||||
"7 zile": summaryData?.furnizori_restant_7 || 0,
|
||||
"14 zile": summaryData?.furnizori_restant_14 || 0,
|
||||
"30 zile": summaryData?.furnizori_restant_30 || 0,
|
||||
"60 zile": summaryData?.furnizori_restant_60 || 0,
|
||||
"90 zile": summaryData?.furnizori_restant_90 || 0,
|
||||
"90+ zile": summaryData?.furnizori_restant_over_90 || 0,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -349,14 +361,14 @@ export const exportTrendData = (trendsData, period, chartType) => {
|
||||
|
||||
const data = trendsData.labels.map((label, index) => {
|
||||
const row = { Perioada: label };
|
||||
|
||||
trendsData.datasets.forEach(dataset => {
|
||||
|
||||
trendsData.datasets.forEach((dataset) => {
|
||||
const value = dataset.data[index];
|
||||
row[dataset.label] = value || 0;
|
||||
});
|
||||
|
||||
|
||||
return row;
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user