Finanzen: Einstellungen und Fixkostenliste
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6e43d54fe8
commit
34ff97e924
6 files changed
+923
-30
No files matched your search
@@ -5,10 +5,20 @@ import { EnableBankingError } from '../../services/finance/enableBanking.js'
|
||||
import { completeBankAuth, startBankAuth, syncBank } from '../../services/finance/bankSync.js'
|
||||
import { getConnection, listTransactions, saveConnection } from '../../services/finance/bankStore.js'
|
||||
import { AssignError, assignTransaction, unassignTransaction, withSuggestions } from '../../services/finance/assign.js'
|
||||
import {
|
||||
SettingsError,
|
||||
createFixedCost,
|
||||
deleteFixedCost,
|
||||
getSettings,
|
||||
listFixedCosts,
|
||||
patchSettings,
|
||||
updateFixedCost,
|
||||
} from '../../services/finance/settings.js'
|
||||
|
||||
/**
|
||||
* Finanzen im WOMS (nur Admins): Bankstatus, Abruf, Neuverbindung, Buchungen und deren Zuordnung. Die Handler sind klein und rufen
|
||||
* die Dienste in server/services/finance auf; weitere Finanz-Routen kommen in dieselbe Datei.
|
||||
* Finanzen im WOMS (nur Admins): Bankstatus, Abruf, Neuverbindung, Buchungen und deren Zuordnung, Einstellungen und
|
||||
* Fixkosten. Die Handler sind klein und rufen die Dienste in server/services/finance auf; weitere Finanz-Routen kommen
|
||||
* in dieselbe Datei.
|
||||
*/
|
||||
const router = Router()
|
||||
|
||||
@@ -39,8 +49,8 @@ function publicConnection(connection) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Buchung ohne Appwrite-Metafelder ($createdAt, $permissions, ...); nur $id bleibt. */
|
||||
const publicTransaction = (doc) => Object.fromEntries(Object.entries(doc).filter(([key]) => key === '$id' || !key.startsWith('$')))
|
||||
/** Dokument ohne Appwrite-Metafelder ($createdAt, $permissions, ...); nur $id bleibt. */
|
||||
const publicDoc = (doc) => Object.fromEntries(Object.entries(doc).filter(([key]) => key === '$id' || !key.startsWith('$')))
|
||||
|
||||
/** Fehlerart fuers Protokoll: nie die Meldung (sie koennte Kennungen der Bank oder von Appwrite enthalten). */
|
||||
const logFailure = (what, err) => console.error(`[finanzen] ${what} fehlgeschlagen:`, err?.name || 'Error', err?.status ?? '', err?.code ?? '')
|
||||
@@ -115,7 +125,7 @@ router.post('/bank/rueckkehr', async (req, res) => {
|
||||
router.get('/buchungen', async (_req, res) => {
|
||||
try {
|
||||
// Vorschlaege kommen von Stripe: ein Ausfall dort (stripeFehler) macht die Liste nie kaputt
|
||||
return res.json(await withSuggestions((await listTransactions()).map(publicTransaction)))
|
||||
return res.json(await withSuggestions((await listTransactions()).map(publicDoc)))
|
||||
} catch (err) {
|
||||
logFailure('Buchungen laden', err)
|
||||
return res.status(500).json({ error: 'Buchungen konnten nicht geladen werden.' })
|
||||
@@ -148,7 +158,7 @@ router.post('/buchungen/:id/zuordnen', async (req, res) => {
|
||||
const { invoiceId, payoutId, fixedCostId, category, note } = req.body || {}
|
||||
try {
|
||||
const buchung = await assignTransaction(req.params.id, { invoiceId, payoutId, fixedCostId, category, note })
|
||||
return res.json({ buchung: publicTransaction(buchung) })
|
||||
return res.json({ buchung: publicDoc(buchung) })
|
||||
} catch (err) {
|
||||
return sendAssignError(res, 'Buchung zuordnen', err)
|
||||
}
|
||||
@@ -156,10 +166,69 @@ router.post('/buchungen/:id/zuordnen', async (req, res) => {
|
||||
|
||||
router.delete('/buchungen/:id/zuordnung', async (req, res) => {
|
||||
try {
|
||||
return res.json({ buchung: publicTransaction(await unassignTransaction(req.params.id)) })
|
||||
return res.json({ buchung: publicDoc(await unassignTransaction(req.params.id)) })
|
||||
} catch (err) {
|
||||
return sendAssignError(res, 'Zuordnung lösen', err)
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Antwort auf einen Fehler bei Einstellungen und Fixkosten: SettingsError (400 ungueltige Eingabe, 404 unbekannte
|
||||
* Position, mit anzeigbarer Meldung); alles andere (Appwrite) wird protokolliert und ist ein 500 ohne dessen Meldung.
|
||||
*/
|
||||
function sendSettingsError(res, what, err) {
|
||||
if (err instanceof SettingsError) return res.status(err.status).json({ error: err.message })
|
||||
logFailure(what, err)
|
||||
return res.status(500).json({ error: 'Interner Fehler.' })
|
||||
}
|
||||
|
||||
router.get('/einstellungen', async (_req, res) => {
|
||||
try {
|
||||
return res.json({ einstellungen: await getSettings() })
|
||||
} catch (err) {
|
||||
return sendSettingsError(res, 'Einstellungen laden', err)
|
||||
}
|
||||
})
|
||||
|
||||
router.patch('/einstellungen', async (req, res) => {
|
||||
try {
|
||||
return res.json({ einstellungen: await patchSettings(req.body) })
|
||||
} catch (err) {
|
||||
return sendSettingsError(res, 'Einstellungen speichern', err)
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/fixkosten', async (_req, res) => {
|
||||
try {
|
||||
return res.json({ fixkosten: (await listFixedCosts()).map(publicDoc) })
|
||||
} catch (err) {
|
||||
return sendSettingsError(res, 'Fixkosten laden', err)
|
||||
}
|
||||
})
|
||||
|
||||
router.post('/fixkosten', async (req, res) => {
|
||||
try {
|
||||
return res.status(201).json({ position: publicDoc(await createFixedCost(req.body)) })
|
||||
} catch (err) {
|
||||
return sendSettingsError(res, 'Fixkosten anlegen', err)
|
||||
}
|
||||
})
|
||||
|
||||
router.patch('/fixkosten/:id', async (req, res) => {
|
||||
try {
|
||||
return res.json({ position: publicDoc(await updateFixedCost(req.params.id, req.body)) })
|
||||
} catch (err) {
|
||||
return sendSettingsError(res, 'Fixkosten ändern', err)
|
||||
}
|
||||
})
|
||||
|
||||
router.delete('/fixkosten/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteFixedCost(req.params.id)
|
||||
return res.json({ ok: true })
|
||||
} catch (err) {
|
||||
return sendSettingsError(res, 'Fixkosten löschen', err)
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
Reference in new issue
Block a user