chore: remove obsolete Android app configuration files
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 44s

- Deleted build.gradle.kts, gradle.properties, and gradlew files as part of the cleanup process.
- Removed local.properties and various generated files from the .gradle directory to streamline the project structure.
- Cleared out unnecessary build artifacts and intermediate files to improve project maintainability.
This commit is contained in:
Torsten Schulz (local)
2026-04-21 15:15:21 +02:00
parent c8dedb10cc
commit 41bbf81958
4144 changed files with 4975 additions and 61401 deletions

View File

@@ -0,0 +1,202 @@
import fs from 'fs';
import multer from 'multer';
import path from 'path';
import billingService from '../services/billingService.js';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const dir = 'uploads/billing-templates';
fs.mkdirSync(dir, { recursive: true });
cb(null, dir);
},
filename: (req, file, cb) => {
const ext = path.extname(file.originalname) || '.pdf';
cb(null, `billing-template-${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}`);
}
});
const upload = multer({
storage,
limits: { fileSize: 10 * 1024 * 1024 },
fileFilter: (req, file, cb) => {
const ext = path.extname(file.originalname || '').toLowerCase();
const isPdf = ext === '.pdf' || (file.mimetype || '').includes('pdf');
if (!isPdf) {
return cb(new Error('Nur PDF-Dateien sind erlaubt.'));
}
cb(null, true);
}
});
export const uploadBillingTemplateMiddleware = upload.single('templatePdf');
export const listTemplates = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { clubId } = req.params;
const result = await billingService.listTemplates(userToken, clubId);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[listTemplates] Error:', error);
res.status(500).json({ success: false, error: 'Vorlagen konnten nicht geladen werden.' });
}
};
export const createTemplate = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { clubId } = req.params;
const result = await billingService.createTemplate(userToken, clubId, req.body || {}, req.file);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[createTemplate] Error:', error);
res.status(500).json({ success: false, error: 'Vorlage konnte nicht gespeichert werden.' });
}
};
export const deleteTemplate = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { templateId } = req.params;
const result = await billingService.deleteTemplate(userToken, templateId);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[deleteTemplate] Error:', error);
res.status(500).json({ success: false, error: 'Vorlage konnte nicht gelöscht werden.' });
}
};
export const updateTemplateFields = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { templateId } = req.params;
const result = await billingService.saveTemplateFields(userToken, templateId, req.body?.fields || []);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[updateTemplateFields] Error:', error);
res.status(500).json({ success: false, error: 'Felder konnten nicht gespeichert werden.' });
}
};
export const createRun = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { clubId } = req.params;
const result = await billingService.createRun(userToken, clubId, req.body || {});
res.status(result.status).json(result.response);
} catch (error) {
console.error('[createRun] Error:', error);
res.status(500).json({ success: false, error: 'Abrechnungslauf konnte nicht erstellt werden.' });
}
};
export const listRuns = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { clubId } = req.params;
const result = await billingService.listRuns(userToken, clubId);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[listRuns] Error:', error);
res.status(500).json({ success: false, error: 'Abrechnungsläufe konnten nicht geladen werden.' });
}
};
export const getRunDetails = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { runId } = req.params;
const result = await billingService.getRunDetails(userToken, runId);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[getRunDetails] Error:', error);
res.status(500).json({ success: false, error: 'Abrechnungslauf konnte nicht geladen werden.' });
}
};
export const deleteRun = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { runId } = req.params;
const result = await billingService.deleteRun(userToken, runId);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[deleteRun] Error:', error);
res.status(500).json({ success: false, error: 'Abrechnung konnte nicht gelöscht werden.' });
}
};
export const getUserSettings = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { clubId } = req.params;
const result = await billingService.getUserSettings(userToken, clubId);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[getUserSettings] Error:', error);
res.status(500).json({ success: false, error: 'Einstellungen konnten nicht geladen werden.' });
}
};
export const calculateHoursPreview = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { clubId } = req.params;
const { monthFrom, monthTo } = req.query;
const result = await billingService.calculateHoursPreview(userToken, clubId, monthFrom, monthTo);
res.status(result.status).json(result.response);
} catch (error) {
console.error('[calculateHoursPreview] Error:', error);
res.status(500).json({ success: false, error: 'Stunden konnten nicht berechnet werden.' });
}
};
export const generateRun = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { runId } = req.params;
const result = await billingService.generateRun(userToken, runId, req.body || {});
res.status(result.status).json(result.response);
} catch (error) {
console.error('[generateRun] Error:', error);
const message = String(error?.message || '');
if (message.includes('Formularfelder') || message.includes('Feldnamen') || message.includes('Fehlend:')) {
return res.status(400).json({ success: false, error: message });
}
res.status(500).json({ success: false, error: 'Abrechnung konnte nicht erzeugt werden.' });
}
};
export const downloadTemplatePdf = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { templateId } = req.params;
const result = await billingService.downloadTemplatePdf(userToken, templateId);
if (result.status !== 200) {
return res.status(result.status).json(result.response);
}
res.setHeader('Content-Disposition', `inline; filename="${result.file.name}"`);
res.setHeader('Content-Type', result.file.mimeType);
return res.sendFile(result.file.path);
} catch (error) {
console.error('[downloadTemplatePdf] Error:', error);
res.status(500).json({ success: false, error: 'PDF konnte nicht geladen werden.' });
}
};
export const downloadRunPdf = async (req, res) => {
try {
const { authcode: userToken } = req.headers;
const { runId } = req.params;
const result = await billingService.downloadGeneratedRunPdf(userToken, runId);
if (result.status !== 200) {
return res.status(result.status).json(result.response);
}
res.setHeader('Content-Disposition', `attachment; filename="${result.file.name}"`);
res.setHeader('Content-Type', result.file.mimeType);
return res.sendFile(result.file.path);
} catch (error) {
console.error('[downloadRunPdf] Error:', error);
res.status(500).json({ success: false, error: 'Abrechnungs-PDF konnte nicht geladen werden.' });
}
};