fix(mitglieder): improve Fahrgenehmigungen labels, pagination, and AT20 sync
This commit is contained in:
@@ -20,6 +20,7 @@ import { requirePermission } from '../middleware/rbac.middleware';
|
||||
import { auditExport } from '../middleware/audit.middleware';
|
||||
import auditService, { AuditAction, AuditResourceType, AuditFilters } from '../services/audit.service';
|
||||
import cleanupService from '../services/cleanup.service';
|
||||
import atemschutzService from '../services/atemschutz.service';
|
||||
import userService from '../services/user.service';
|
||||
import pool from '../config/database';
|
||||
import logger from '../utils/logger';
|
||||
@@ -207,6 +208,10 @@ router.post(
|
||||
try {
|
||||
const response = await axios.post(`${FDISK_SYNC_URL}/trigger`, req.body, { timeout: 5000 });
|
||||
res.json({ success: true, data: response.data });
|
||||
// Fire-and-forget: sync AT20 courses to atemschutz_traeger after FDISK data is written
|
||||
atemschutzService.syncLehrgangFromKurse().catch(err =>
|
||||
logger.error('AT20 Atemschutz-Sync fehlgeschlagen', { error: err })
|
||||
);
|
||||
} catch (err: unknown) {
|
||||
if (axios.isAxiosError(err) && err.response?.status === 409) {
|
||||
res.status(409).json({ success: false, message: 'Sync already in progress' });
|
||||
|
||||
@@ -216,6 +216,40 @@ class AtemschutzService {
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// SYNC LEHRGANG FROM FDISK COURSES (AT20)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Scans the ausbildung table for AT20 courses with erfolgscode = 'mit Erfolg'
|
||||
* and upserts atemschutz_traeger records accordingly:
|
||||
* - No record: creates one with atemschutz_lehrgang=true + lehrgang_datum
|
||||
* - Record exists, lehrgang false: sets lehrgang=true + date (if unset)
|
||||
* - Record exists, lehrgang already true: no-op (preserves manual data)
|
||||
*/
|
||||
async syncLehrgangFromKurse(): Promise<{ processed: number }> {
|
||||
try {
|
||||
const result = await pool.query(`
|
||||
INSERT INTO atemschutz_traeger (id, user_id, atemschutz_lehrgang, lehrgang_datum)
|
||||
SELECT uuid_generate_v4(), a.user_id, true, MIN(a.kurs_datum)
|
||||
FROM ausbildung a
|
||||
WHERE a.kurs_kurzbezeichnung = 'AT20'
|
||||
AND a.erfolgscode = 'mit Erfolg'
|
||||
GROUP BY a.user_id
|
||||
ON CONFLICT (user_id) DO UPDATE
|
||||
SET atemschutz_lehrgang = true,
|
||||
lehrgang_datum = COALESCE(atemschutz_traeger.lehrgang_datum, EXCLUDED.lehrgang_datum),
|
||||
updated_at = NOW()
|
||||
`);
|
||||
const processed = result.rowCount ?? 0;
|
||||
logger.info('AT20 Atemschutz-Sync abgeschlossen', { processed });
|
||||
return { processed };
|
||||
} catch (error) {
|
||||
logger.error('AtemschutzService.syncLehrgangFromKurse fehlgeschlagen', { error });
|
||||
throw new Error('AT20 Atemschutz-Sync fehlgeschlagen');
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// EXPIRING CERTIFICATIONS
|
||||
// =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user