Files
fibdash/src/routes/data/accountingItems.js
sebseb7 fee9f02faa Enhance Accounting Items Management with JTL Kontierung Integration
- Added a new API route to fetch JTL Kontierung data based on transaction ID.
- Implemented loading of JTL Kontierung data in the AccountingItemsManager component.
- Updated UI to display JTL Kontierung data for debugging purposes.
- Enhanced user feedback during processing tasks in the App component with tooltips and progress indicators.
2025-08-08 11:32:57 +02:00

273 lines
8.9 KiB
JavaScript

const express = require('express');
const { authenticateToken } = require('../../middleware/auth');
const router = express.Router();
// Debug: Get JTL Kontierung data for a specific JTL Umsatz (by kZahlungsabgleichUmsatz)
router.get('/jtl-kontierung/:jtlId', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const { jtlId } = req.params;
const query = `
SELECT
uk.data
FROM eazybusiness.dbo.tZahlungsabgleichUmsatz z
LEFT JOIN eazybusiness.dbo.tUmsatzKontierung uk
ON uk.kZahlungsabgleichUmsatz = z.kZahlungsabgleichUmsatz
WHERE z.kZahlungsabgleichUmsatz = @jtlId
`;
const result = await executeQuery(query, { jtlId: parseInt(jtlId, 10) });
// Return undefined when no data found (do not lie with empty array/string)
if (!result.recordset || result.recordset.length === 0) {
return res.json({ data: undefined });
}
// If multiple rows exist, return all; otherwise single object
const rows = result.recordset.map(r => ({ data: r.data }));
if (rows.length === 1) {
return res.json(rows[0]);
}
return res.json(rows);
} catch (error) {
console.error('Error fetching JTL Kontierung data:', error);
res.status(500).json({ error: 'Failed to fetch JTL Kontierung data' });
}
});
// Get accounting items for a specific transaction
router.get('/accounting-items/:transactionId', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const { transactionId } = req.params;
// Try both numeric and string format (similar to banking transactions)
let query, params;
const numericId = parseInt(transactionId, 10);
if (!isNaN(numericId) && numericId.toString() === transactionId) {
// It's a numeric ID - check transaction_id column
query = `
SELECT
ai.*,
k.name as konto_name,
bu.name as bu_name,
bu.vst as bu_vst
FROM fibdash.AccountingItems ai
LEFT JOIN fibdash.Konto k ON ai.konto = k.konto
LEFT JOIN fibdash.BU bu ON ai.bu = bu.bu
WHERE ai.transaction_id = @transactionId
ORDER BY ai.id
`;
params = { transactionId: numericId };
} else {
// It's a string ID - check csv_transaction_id column
query = `
SELECT
ai.*,
k.name as konto_name,
bu.name as bu_name,
bu.vst as bu_vst
FROM fibdash.AccountingItems ai
LEFT JOIN fibdash.Konto k ON ai.konto = k.konto
LEFT JOIN fibdash.BU bu ON ai.bu = bu.bu
WHERE ai.csv_transaction_id = @transactionId
ORDER BY ai.id
`;
params = { transactionId };
}
const result = await executeQuery(query, params);
res.json(result.recordset);
} catch (error) {
console.error('Error fetching accounting items:', error);
res.status(500).json({ error: 'Failed to fetch accounting items' });
}
});
// Create accounting item for a transaction
router.post('/accounting-items', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const {
transaction_id,
csv_transaction_id,
umsatz_brutto,
soll_haben_kz,
konto,
bu,
buchungsdatum,
rechnungsnummer,
buchungstext
} = req.body;
if ((!transaction_id && !csv_transaction_id) || !umsatz_brutto || !soll_haben_kz || !konto || !buchungsdatum) {
return res.status(400).json({
error: 'Transaction ID, amount, debit/credit indicator, account, and booking date are required'
});
}
let insertQuery, queryParams;
if (csv_transaction_id) {
// For CSV transactions, use placeholder transaction_id
insertQuery = `
INSERT INTO fibdash.AccountingItems
(transaction_id, csv_transaction_id, umsatz_brutto, soll_haben_kz, konto, gegenkonto, bu, buchungsdatum, rechnungsnummer, buchungstext)
OUTPUT INSERTED.*
VALUES (-1, @csv_transaction_id, @umsatz_brutto, @soll_haben_kz, @konto, '', @bu, @buchungsdatum, @rechnungsnummer, @buchungstext)
`;
queryParams = {
csv_transaction_id,
umsatz_brutto,
soll_haben_kz,
konto,
bu: bu || null,
buchungsdatum,
rechnungsnummer: rechnungsnummer || null,
buchungstext: buchungstext || null
};
} else {
// For regular transactions
insertQuery = `
INSERT INTO fibdash.AccountingItems
(transaction_id, csv_transaction_id, umsatz_brutto, soll_haben_kz, konto, gegenkonto, bu, buchungsdatum, rechnungsnummer, buchungstext)
OUTPUT INSERTED.*
VALUES (@transaction_id, NULL, @umsatz_brutto, @soll_haben_kz, @konto, '', @bu, @buchungsdatum, @rechnungsnummer, @buchungstext)
`;
queryParams = {
transaction_id,
umsatz_brutto,
soll_haben_kz,
konto,
bu: bu || null,
buchungsdatum,
rechnungsnummer: rechnungsnummer || null,
buchungstext: buchungstext || null
};
}
const result = await executeQuery(insertQuery, queryParams);
res.status(201).json(result.recordset[0]);
} catch (error) {
console.error('Error creating accounting item:', error);
res.status(500).json({ error: 'Failed to create accounting item' });
}
});
// Update accounting item
router.put('/accounting-items/:id', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const { id } = req.params;
const { umsatz_brutto, soll_haben_kz, konto, bu, rechnungsnummer, buchungstext } = req.body;
if (!umsatz_brutto || !soll_haben_kz || !konto) {
return res.status(400).json({ error: 'Amount, debit/credit indicator, and account are required' });
}
const updateQuery = `
UPDATE fibdash.AccountingItems
SET umsatz_brutto = @umsatz_brutto,
soll_haben_kz = @soll_haben_kz,
konto = @konto,
bu = @bu,
rechnungsnummer = @rechnungsnummer,
buchungstext = @buchungstext
OUTPUT INSERTED.*
WHERE id = @id
`;
const result = await executeQuery(updateQuery, {
umsatz_brutto,
soll_haben_kz,
konto,
bu: bu || null,
rechnungsnummer: rechnungsnummer || null,
buchungstext: buchungstext || null,
id: parseInt(id, 10)
});
if (result.recordset.length === 0) {
return res.status(404).json({ error: 'Accounting item not found' });
}
res.json(result.recordset[0]);
} catch (error) {
console.error('Error updating accounting item:', error);
res.status(500).json({ error: 'Failed to update accounting item' });
}
});
// Delete accounting item
router.delete('/accounting-items/:id', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const { id } = req.params;
const deleteQuery = `DELETE FROM fibdash.AccountingItems WHERE id = @id`;
await executeQuery(deleteQuery, { id: parseInt(id, 10) });
res.json({ message: 'Accounting item deleted successfully' });
} catch (error) {
console.error('Error deleting accounting item:', error);
res.status(500).json({ error: 'Failed to delete accounting item' });
}
});
// Get all Konto options
router.get('/kontos', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const query = `SELECT * FROM fibdash.Konto ORDER BY konto`;
const result = await executeQuery(query);
res.json(result.recordset);
} catch (error) {
console.error('Error fetching kontos:', error);
res.status(500).json({ error: 'Failed to fetch kontos' });
}
});
// Create new Konto
router.post('/kontos', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const { konto, name } = req.body;
if (!konto || !name) {
return res.status(400).json({ error: 'Konto and name are required' });
}
const insertQuery = `
INSERT INTO fibdash.Konto (konto, name)
OUTPUT INSERTED.*
VALUES (@konto, @name)
`;
const result = await executeQuery(insertQuery, { konto, name });
res.status(201).json(result.recordset[0]);
} catch (error) {
console.error('Error creating konto:', error);
res.status(500).json({ error: 'Failed to create konto' });
}
});
// Get all BU options
router.get('/bus', authenticateToken, async (req, res) => {
try {
const { executeQuery } = require('../../config/database');
const query = `SELECT * FROM fibdash.BU ORDER BY bu`;
const result = await executeQuery(query);
res.json(result.recordset);
} catch (error) {
console.error('Error fetching BUs:', error);
res.status(500).json({ error: 'Failed to fetch BUs' });
}
});
module.exports = router;