Vertragsverwaltung_Plusfit24/app.js
2026-03-27 12:12:28 +00:00

116 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

require('dotenv').config();
const express = require('express');
const session = require('express-session');
const path = require('path');
const bcrypt = require('bcryptjs');
const db = require('./config/database');
const app = express();
// View Engine
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Static Files
app.use(express.static(path.join(__dirname, 'public')));
// Body Parser
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Session
app.use(session({
secret: process.env.SESSION_SECRET || 'plusfit24-secret',
resave: false,
saveUninitialized: false,
cookie: {
secure: false, // auf true setzen wenn HTTPS direkt (nicht via Proxy)
maxAge: 24 * 60 * 60 * 1000 // 24 Stunden
}
}));
// Routen
const indexRouter = require('./routes/index');
const adminRouter = require('./routes/admin');
const apiRouter = require('./routes/api');
const billingRouter = require('./routes/billing');
const cron = require('node-cron');
app.use('/', indexRouter);
app.use('/admin', adminRouter);
app.use('/api', apiRouter);
app.use('/admin/billing', billingRouter);
// 404 Handler
app.use((req, res) => {
res.status(404).render('error', { message: 'Seite nicht gefunden' });
});
// Fehler Handler
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).render('error', { message: 'Ein Fehler ist aufgetreten' });
});
// Admin Account beim Start erstellen falls keiner existiert
async function initAdmin() {
try {
const [rows] = await db.query('SELECT COUNT(*) as count FROM admins');
if (rows[0].count === 0) {
const hash = await bcrypt.hash(process.env.ADMIN_PASSWORD || 'Admin1234!', 12);
await db.query(
'INSERT INTO admins (username, password_hash) VALUES (?, ?)',
[process.env.ADMIN_USER || 'admin', hash]
);
console.log('✅ Admin Account erstellt:', process.env.ADMIN_USER || 'admin');
}
} catch (err) {
console.error('❌ Fehler beim Erstellen des Admin Accounts:', err.message);
}
}
// Auto-Abrechnungslauf jeden 1. des Monats um 06:00 Uhr
cron.schedule('0 6 1 * *', async () => {
const { currentPeriod } = require('./routes/billing');
const period = currentPeriod();
console.log(`⏰ Auto-Abrechnungslauf gestartet für ${period}`);
try {
const [existing] = await db.query('SELECT COUNT(*) as c FROM invoices WHERE period = ?', [period]);
if (existing[0].c > 0) {
console.log(`⏭ Abrechnungslauf für ${period} bereits vorhanden übersprungen`);
return;
}
const [members] = await db.query(`
SELECT m.*, t.price_monthly FROM memberships m
JOIN tariffs t ON m.tariff_id = t.id
WHERE m.status IN ('active','paused')
AND m.contract_start <= LAST_DAY(STR_TO_DATE(CONCAT(?, '-01'), '%Y-%m-%d'))
AND (m.contract_end IS NULL OR m.contract_end >= STR_TO_DATE(CONCAT(?, '-01'), '%Y-%m-%d'))
`, [period, period]);
const [runResult] = await db.query(
'INSERT INTO billing_runs (run_date, period, created_by) VALUES (CURDATE(), ?, ?)',
[period, 'system-auto']
);
let total = 0, count = 0;
for (const m of members) {
const firstPeriod = m.first_payment_date ? m.first_payment_date.toISOString().substring(0,7) : null;
const amount = firstPeriod === period && m.first_payment_amt ? parseFloat(m.first_payment_amt) : parseFloat(m.price_monthly);
await db.query(
'INSERT IGNORE INTO invoices (billing_run_id, membership_id, period, amount, description, iban, account_holder, bank_name) VALUES (?,?,?,?,?,?,?,?)',
[runResult.insertId, m.id, period, amount, `Mitgliedsbeitrag ${period}`, m.iban||'', m.account_holder||'', m.bank_name||'']
);
total += amount; count++;
}
await db.query('UPDATE billing_runs SET total_amount=?, invoice_count=? WHERE id=?', [total, count, runResult.insertId]);
console.log(`✅ Auto-Abrechnungslauf abgeschlossen: ${count} Rechnungen, ${total.toFixed(2)}`);
} catch (err) {
console.error('❌ Auto-Abrechnungslauf Fehler:', err.message);
}
});
const PORT = process.env.PORT || 3100;
app.listen(PORT, async () => {
console.log(`🚀 PlusFit24 Server läuft auf Port ${PORT}`);
await initAdmin();
});