This commit is contained in:
sebseb7
2025-07-20 04:46:01 +02:00
parent 102a4ec9ff
commit 9a0c985bfa
13 changed files with 1473 additions and 155 deletions

View File

@@ -110,14 +110,48 @@ const getJTLTransactions = async () => {
}
};
// Get transactions for a specific month
router.get('/transactions/:monthYear', authenticateToken, async (req, res) => {
// Get transactions for a specific time period (month, quarter, or year)
router.get('/transactions/:timeRange', authenticateToken, async (req, res) => {
try {
const { monthYear } = req.params;
const { timeRange } = req.params;
const transactions = parseCSV();
const monthTransactions = transactions
.filter(t => t.monthYear === monthYear)
let filteredTransactions = [];
let periodDescription = '';
if (timeRange.includes('-Q')) {
// Quarter format: YYYY-Q1, YYYY-Q2, etc.
const [year, quarterPart] = timeRange.split('-Q');
const quarter = parseInt(quarterPart);
const startMonth = (quarter - 1) * 3 + 1;
const endMonth = startMonth + 2;
filteredTransactions = transactions.filter(t => {
if (!t.monthYear) return false;
const [tYear, tMonth] = t.monthYear.split('-');
const monthNum = parseInt(tMonth);
return tYear === year && monthNum >= startMonth && monthNum <= endMonth;
});
periodDescription = `Q${quarter} ${year}`;
} else if (timeRange.length === 4) {
// Year format: YYYY
filteredTransactions = transactions.filter(t => {
if (!t.monthYear) return false;
const [tYear] = t.monthYear.split('-');
return tYear === timeRange;
});
periodDescription = `Jahr ${timeRange}`;
} else {
// Month format: YYYY-MM
filteredTransactions = transactions.filter(t => t.monthYear === timeRange);
const [year, month] = timeRange.split('-');
const date = new Date(year, month - 1);
periodDescription = date.toLocaleDateString('de-DE', { month: 'long', year: 'numeric' });
}
const monthTransactions = filteredTransactions
.sort((a, b) => b.parsedDate - a.parsedDate); // Newest first
// Get JTL transactions for comparison
@@ -128,13 +162,34 @@ router.get('/transactions/:monthYear', authenticateToken, async (req, res) => {
console.log('JTL database not available, continuing without JTL data');
}
// Filter JTL transactions for the selected month
const [year, month] = monthYear.split('-');
const jtlMonthTransactions = jtlTransactions.filter(jtl => {
const jtlDate = new Date(jtl.dBuchungsdatum);
return jtlDate.getFullYear() === parseInt(year) &&
jtlDate.getMonth() === parseInt(month) - 1;
});
// Filter JTL transactions for the selected time period
let jtlMonthTransactions = [];
if (timeRange.includes('-Q')) {
const [year, quarterPart] = timeRange.split('-Q');
const quarter = parseInt(quarterPart);
const startMonth = (quarter - 1) * 3 + 1;
const endMonth = startMonth + 2;
jtlMonthTransactions = jtlTransactions.filter(jtl => {
const jtlDate = new Date(jtl.dBuchungsdatum);
const jtlMonth = jtlDate.getMonth() + 1; // 0-based to 1-based
return jtlDate.getFullYear() === parseInt(year) &&
jtlMonth >= startMonth && jtlMonth <= endMonth;
});
} else if (timeRange.length === 4) {
jtlMonthTransactions = jtlTransactions.filter(jtl => {
const jtlDate = new Date(jtl.dBuchungsdatum);
return jtlDate.getFullYear() === parseInt(timeRange);
});
} else {
const [year, month] = timeRange.split('-');
jtlMonthTransactions = jtlTransactions.filter(jtl => {
const jtlDate = new Date(jtl.dBuchungsdatum);
return jtlDate.getFullYear() === parseInt(year) &&
jtlDate.getMonth() === parseInt(month) - 1;
});
}
// Add JTL status to each CSV transaction
const transactionsWithJTL = monthTransactions.map(transaction => {
@@ -199,7 +254,7 @@ router.get('/transactions/:monthYear', authenticateToken, async (req, res) => {
'Betrag': jtl.fBetrag ? jtl.fBetrag.toString().replace('.', ',') : '0,00',
numericAmount: parseFloat(jtl.fBetrag) || 0,
parsedDate: new Date(jtl.dBuchungsdatum),
monthYear: monthYear,
monthYear: timeRange,
hasJTL: true,
jtlId: jtl.kZahlungsabgleichUmsatz,
isFromCSV: false,
@@ -229,7 +284,8 @@ router.get('/transactions/:monthYear', authenticateToken, async (req, res) => {
res.json({
transactions: allTransactions,
summary,
monthYear
timeRange,
periodDescription
});
} catch (error) {
console.error('Error getting transactions:', error);
@@ -290,25 +346,61 @@ const quote = (str, maxLen = 60) => {
};
// DATEV export endpoint
router.get('/datev/:monthYear', authenticateToken, async (req, res) => {
router.get('/datev/:timeRange', authenticateToken, async (req, res) => {
try {
const { monthYear } = req.params;
const [year, month] = monthYear.split('-');
const { timeRange } = req.params;
// Get transactions for the month
// Get transactions for the time period
const transactions = parseCSV();
const monthTransactions = transactions
.filter(t => t.monthYear === monthYear)
let filteredTransactions = [];
let periodStart, periodEnd, filename;
if (timeRange.includes('-Q')) {
// Quarter format: YYYY-Q1, YYYY-Q2, etc.
const [year, quarterPart] = timeRange.split('-Q');
const quarter = parseInt(quarterPart);
const startMonth = (quarter - 1) * 3 + 1;
const endMonth = startMonth + 2;
filteredTransactions = transactions.filter(t => {
if (!t.monthYear) return false;
const [tYear, tMonth] = t.monthYear.split('-');
const monthNum = parseInt(tMonth);
return tYear === year && monthNum >= startMonth && monthNum <= endMonth;
});
periodStart = `${year}${startMonth.toString().padStart(2, '0')}01`;
periodEnd = new Date(year, endMonth, 0).toISOString().slice(0, 10).replace(/-/g, '');
filename = `DATEV_${year}_Q${quarter}.csv`;
} else if (timeRange.length === 4) {
// Year format: YYYY
filteredTransactions = transactions.filter(t => {
if (!t.monthYear) return false;
const [tYear] = t.monthYear.split('-');
return tYear === timeRange;
});
periodStart = `${timeRange}0101`;
periodEnd = `${timeRange}1231`;
filename = `DATEV_${timeRange}.csv`;
} else {
// Month format: YYYY-MM
const [year, month] = timeRange.split('-');
filteredTransactions = transactions.filter(t => t.monthYear === timeRange);
periodStart = `${year}${month.padStart(2, '0')}01`;
periodEnd = new Date(year, month, 0).toISOString().slice(0, 10).replace(/-/g, '');
filename = `DATEV_${year}_${month.padStart(2, '0')}.csv`;
}
const monthTransactions = filteredTransactions
.sort((a, b) => a.parsedDate - b.parsedDate); // Oldest first for DATEV
if (!monthTransactions.length) {
return res.status(404).json({ error: 'No transactions found for this month' });
return res.status(404).json({ error: 'No transactions found for this time period' });
}
// Build DATEV format
const periodStart = `${year}${month.padStart(2, '0')}01`;
const periodEnd = new Date(year, month, 0).toISOString().slice(0, 10).replace(/-/g, '');
const header = buildDatevHeader(periodStart, periodEnd);
const rows = monthTransactions.map((transaction, index) => {
@@ -335,7 +427,6 @@ router.get('/datev/:monthYear', authenticateToken, async (req, res) => {
const csv = [header, DATEV_COLS, ...rows].join('\r\n');
// Set headers for file download
const filename = `DATEV_${year}_${month.padStart(2, '0')}.csv`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.setHeader('Content-Type', 'text/csv; charset=latin1');