629 lines
24 KiB
TypeScript
629 lines
24 KiB
TypeScript
import pool from '../config/database';
|
|
import logger from '../utils/logger';
|
|
import {
|
|
Ausruestung,
|
|
AusruestungKategorie,
|
|
AusruestungListItem,
|
|
AusruestungDetail,
|
|
AusruestungWartungslog,
|
|
CreateAusruestungData,
|
|
UpdateAusruestungData,
|
|
CreateAusruestungWartungslogData,
|
|
UpdateAusruestungWartungslogData,
|
|
AusruestungStatus,
|
|
EquipmentStats,
|
|
VehicleEquipmentWarning,
|
|
} from '../models/equipment.model';
|
|
|
|
class EquipmentService {
|
|
// =========================================================================
|
|
// EQUIPMENT OVERVIEW
|
|
// =========================================================================
|
|
|
|
async getAllEquipment(): Promise<AusruestungListItem[]> {
|
|
try {
|
|
const result = await pool.query(`
|
|
SELECT *
|
|
FROM ausruestung_mit_pruefstatus
|
|
ORDER BY kategorie_kurzname, bezeichnung
|
|
`);
|
|
|
|
return result.rows.map((row) => ({
|
|
...row,
|
|
pruefung_tage_bis_faelligkeit: row.pruefung_tage_bis_faelligkeit != null
|
|
? parseInt(row.pruefung_tage_bis_faelligkeit, 10) : null,
|
|
})) as AusruestungListItem[];
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getAllEquipment failed', { error });
|
|
throw new Error('Failed to fetch equipment');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// EQUIPMENT DETAIL
|
|
// =========================================================================
|
|
|
|
async getEquipmentById(id: string): Promise<AusruestungDetail | null> {
|
|
try {
|
|
const equipmentResult = await pool.query(
|
|
`SELECT * FROM ausruestung_mit_pruefstatus WHERE id = $1`,
|
|
[id]
|
|
);
|
|
|
|
if (equipmentResult.rows.length === 0) return null;
|
|
|
|
const row = equipmentResult.rows[0];
|
|
|
|
const wartungslogResult = await pool.query(
|
|
`SELECT * FROM ausruestung_wartungslog
|
|
WHERE ausruestung_id = $1
|
|
ORDER BY datum DESC, created_at DESC`,
|
|
[id]
|
|
);
|
|
|
|
const equipment: AusruestungDetail = {
|
|
...row,
|
|
pruefung_tage_bis_faelligkeit: row.pruefung_tage_bis_faelligkeit != null
|
|
? parseInt(row.pruefung_tage_bis_faelligkeit, 10) : null,
|
|
wartungslog: wartungslogResult.rows.map(r => ({
|
|
...r,
|
|
kosten: r.kosten != null ? Number(r.kosten) : null,
|
|
})) as AusruestungWartungslog[],
|
|
};
|
|
|
|
return equipment;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getEquipmentById failed', { error, id });
|
|
throw new Error('Failed to fetch equipment');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// EQUIPMENT BY VEHICLE
|
|
// =========================================================================
|
|
|
|
async getEquipmentByVehicle(fahrzeugId: string): Promise<AusruestungListItem[]> {
|
|
try {
|
|
const result = await pool.query(
|
|
`SELECT *
|
|
FROM ausruestung_mit_pruefstatus
|
|
WHERE fahrzeug_id = $1
|
|
ORDER BY kategorie_kurzname, bezeichnung`,
|
|
[fahrzeugId]
|
|
);
|
|
|
|
return result.rows.map((row) => ({
|
|
...row,
|
|
pruefung_tage_bis_faelligkeit: row.pruefung_tage_bis_faelligkeit != null
|
|
? parseInt(row.pruefung_tage_bis_faelligkeit, 10) : null,
|
|
})) as AusruestungListItem[];
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getEquipmentByVehicle failed', { error, fahrzeugId });
|
|
throw new Error('Failed to fetch equipment for vehicle');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// CATEGORIES
|
|
// =========================================================================
|
|
|
|
async getCategories(): Promise<AusruestungKategorie[]> {
|
|
try {
|
|
const result = await pool.query(
|
|
`SELECT * FROM ausruestung_kategorien ORDER BY sortierung`
|
|
);
|
|
return result.rows as AusruestungKategorie[];
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getCategories failed', { error });
|
|
throw new Error('Failed to fetch equipment categories');
|
|
}
|
|
}
|
|
|
|
async getCategoryById(id: string): Promise<AusruestungKategorie | null> {
|
|
try {
|
|
const result = await pool.query(
|
|
`SELECT * FROM ausruestung_kategorien WHERE id = $1`,
|
|
[id]
|
|
);
|
|
return result.rows.length > 0 ? (result.rows[0] as AusruestungKategorie) : null;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getCategoryById failed', { error, id });
|
|
throw new Error('Failed to fetch equipment category');
|
|
}
|
|
}
|
|
|
|
async createCategory(data: { name: string; kurzname: string; sortierung?: number; motorisiert?: boolean }): Promise<AusruestungKategorie> {
|
|
try {
|
|
const result = await pool.query(
|
|
`INSERT INTO ausruestung_kategorien (id, name, kurzname, sortierung, motorisiert)
|
|
VALUES (uuid_generate_v4(), $1, $2, COALESCE($3, (SELECT COALESCE(MAX(sortierung),0)+1 FROM ausruestung_kategorien)), COALESCE($4, false))
|
|
RETURNING *`,
|
|
[data.name, data.kurzname, data.sortierung ?? null, data.motorisiert ?? null]
|
|
);
|
|
logger.info('Equipment category created', { id: result.rows[0].id, name: data.name });
|
|
return result.rows[0] as AusruestungKategorie;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.createCategory failed', { error });
|
|
throw new Error('Failed to create equipment category');
|
|
}
|
|
}
|
|
|
|
async updateCategory(id: string, data: { name?: string; kurzname?: string; sortierung?: number; motorisiert?: boolean }): Promise<AusruestungKategorie | null> {
|
|
try {
|
|
const fields: string[] = [];
|
|
const values: unknown[] = [];
|
|
let p = 1;
|
|
|
|
if (data.name !== undefined) { fields.push(`name = $${p++}`); values.push(data.name); }
|
|
if (data.kurzname !== undefined) { fields.push(`kurzname = $${p++}`); values.push(data.kurzname); }
|
|
if (data.sortierung !== undefined) { fields.push(`sortierung = $${p++}`); values.push(data.sortierung); }
|
|
if (data.motorisiert !== undefined) { fields.push(`motorisiert = $${p++}`); values.push(data.motorisiert); }
|
|
|
|
if (fields.length === 0) throw new Error('No fields to update');
|
|
|
|
values.push(id);
|
|
const result = await pool.query(
|
|
`UPDATE ausruestung_kategorien SET ${fields.join(', ')} WHERE id = $${p} RETURNING *`,
|
|
values
|
|
);
|
|
if (result.rows.length === 0) return null;
|
|
logger.info('Equipment category updated', { id });
|
|
return result.rows[0] as AusruestungKategorie;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.updateCategory failed', { error, id });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async deleteCategory(id: string): Promise<{ deleted: boolean; error?: string }> {
|
|
try {
|
|
// Check if any equipment items reference this category
|
|
const usage = await pool.query(
|
|
`SELECT COUNT(*) AS cnt FROM ausruestung WHERE kategorie_id = $1 AND deleted_at IS NULL`,
|
|
[id]
|
|
);
|
|
const count = parseInt(usage.rows[0].cnt, 10);
|
|
if (count > 0) {
|
|
return { deleted: false, error: `Kategorie wird von ${count} Ausrüstungsgegenständen verwendet und kann nicht gelöscht werden.` };
|
|
}
|
|
const result = await pool.query(
|
|
`DELETE FROM ausruestung_kategorien WHERE id = $1 RETURNING id`,
|
|
[id]
|
|
);
|
|
if (result.rows.length === 0) {
|
|
return { deleted: false, error: 'Kategorie nicht gefunden' };
|
|
}
|
|
logger.info('Equipment category deleted', { id });
|
|
return { deleted: true };
|
|
} catch (error) {
|
|
logger.error('EquipmentService.deleteCategory failed', { error, id });
|
|
throw new Error('Failed to delete equipment category');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// CRUD
|
|
// =========================================================================
|
|
|
|
async createEquipment(data: CreateAusruestungData, createdBy: string): Promise<Ausruestung> {
|
|
try {
|
|
const result = await pool.query(
|
|
`INSERT INTO ausruestung (
|
|
id, bezeichnung, kategorie_id, seriennummer, inventarnummer,
|
|
hersteller, baujahr, status, status_bemerkung, ist_wichtig,
|
|
fahrzeug_id, standort, pruef_intervall_monate,
|
|
letzte_pruefung_am, naechste_pruefung_am, bemerkung
|
|
) VALUES (uuid_generate_v4(),$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
|
|
RETURNING *`,
|
|
[
|
|
data.bezeichnung,
|
|
data.kategorie_id,
|
|
data.seriennummer ?? null,
|
|
data.inventarnummer ?? null,
|
|
data.hersteller ?? null,
|
|
data.baujahr ?? null,
|
|
data.status ?? AusruestungStatus.Einsatzbereit,
|
|
data.status_bemerkung ?? null,
|
|
data.ist_wichtig ?? false,
|
|
data.fahrzeug_id ?? null,
|
|
data.standort ?? 'Lager',
|
|
data.pruef_intervall_monate ?? null,
|
|
data.letzte_pruefung_am ?? null,
|
|
data.naechste_pruefung_am ?? null,
|
|
data.bemerkung ?? null,
|
|
]
|
|
);
|
|
|
|
const equipment = result.rows[0] as Ausruestung;
|
|
logger.info('Equipment created', { id: equipment.id, by: createdBy });
|
|
return equipment;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.createEquipment failed', { error, createdBy });
|
|
throw new Error('Failed to create equipment');
|
|
}
|
|
}
|
|
|
|
async updateEquipment(id: string, data: UpdateAusruestungData, updatedBy: string): Promise<Ausruestung | null> {
|
|
try {
|
|
const fields: string[] = [];
|
|
const values: unknown[] = [];
|
|
let p = 1;
|
|
|
|
const addField = (col: string, value: unknown) => {
|
|
fields.push(`${col} = $${p++}`);
|
|
values.push(value);
|
|
};
|
|
|
|
if (data.bezeichnung !== undefined) addField('bezeichnung', data.bezeichnung);
|
|
if (data.kategorie_id !== undefined) addField('kategorie_id', data.kategorie_id);
|
|
if (data.seriennummer !== undefined) addField('seriennummer', data.seriennummer);
|
|
if (data.inventarnummer !== undefined) addField('inventarnummer', data.inventarnummer);
|
|
if (data.hersteller !== undefined) addField('hersteller', data.hersteller);
|
|
if (data.baujahr !== undefined) addField('baujahr', data.baujahr);
|
|
if (data.status !== undefined) addField('status', data.status);
|
|
if (data.status_bemerkung !== undefined) addField('status_bemerkung', data.status_bemerkung);
|
|
if (data.ist_wichtig !== undefined) addField('ist_wichtig', data.ist_wichtig);
|
|
if (data.fahrzeug_id !== undefined) addField('fahrzeug_id', data.fahrzeug_id);
|
|
if (data.standort !== undefined) addField('standort', data.standort);
|
|
if (data.pruef_intervall_monate !== undefined) addField('pruef_intervall_monate', data.pruef_intervall_monate);
|
|
if (data.letzte_pruefung_am !== undefined) addField('letzte_pruefung_am', data.letzte_pruefung_am);
|
|
if (data.naechste_pruefung_am !== undefined) addField('naechste_pruefung_am', data.naechste_pruefung_am);
|
|
if (data.bemerkung !== undefined) addField('bemerkung', data.bemerkung);
|
|
|
|
if (fields.length === 0) {
|
|
throw new Error('No fields to update');
|
|
}
|
|
|
|
values.push(id);
|
|
const result = await pool.query(
|
|
`UPDATE ausruestung SET ${fields.join(', ')} WHERE id = $${p} AND deleted_at IS NULL RETURNING *`,
|
|
values
|
|
);
|
|
|
|
if (result.rows.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const equipment = result.rows[0] as Ausruestung;
|
|
logger.info('Equipment updated', { id, by: updatedBy });
|
|
return equipment;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.updateEquipment failed', { error, id, updatedBy });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async deleteEquipment(id: string, deletedBy: string): Promise<boolean> {
|
|
try {
|
|
const result = await pool.query(
|
|
`UPDATE ausruestung
|
|
SET deleted_at = NOW()
|
|
WHERE id = $1 AND deleted_at IS NULL
|
|
RETURNING id`,
|
|
[id]
|
|
);
|
|
|
|
if (result.rows.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
logger.info('Equipment soft-deleted', { id, by: deletedBy });
|
|
return true;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.deleteEquipment failed', { error, id });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// STATUS MANAGEMENT
|
|
// =========================================================================
|
|
|
|
async updateStatus(
|
|
id: string,
|
|
status: AusruestungStatus,
|
|
bemerkung: string,
|
|
updatedBy: string
|
|
): Promise<void> {
|
|
try {
|
|
// Get old status for history
|
|
const oldResult = await pool.query(
|
|
`SELECT status FROM ausruestung WHERE id = $1 AND deleted_at IS NULL`,
|
|
[id]
|
|
);
|
|
const oldStatus = oldResult.rows[0]?.status;
|
|
|
|
const result = await pool.query(
|
|
`UPDATE ausruestung
|
|
SET status = $1, status_bemerkung = $2, updated_at = NOW()
|
|
WHERE id = $3 AND deleted_at IS NULL
|
|
RETURNING id`,
|
|
[status, bemerkung || null, id]
|
|
);
|
|
|
|
if (result.rows.length === 0) {
|
|
throw new Error('Equipment not found');
|
|
}
|
|
|
|
// Record status change history
|
|
if (oldStatus && oldStatus !== status) {
|
|
await pool.query(
|
|
`INSERT INTO ausruestung_status_historie (ausruestung_id, alter_status, neuer_status, bemerkung, geaendert_von)
|
|
VALUES ($1, $2, $3, $4, $5)`,
|
|
[id, oldStatus, status, bemerkung || null, updatedBy]
|
|
);
|
|
}
|
|
|
|
logger.info('Equipment status updated', { id, status, by: updatedBy });
|
|
} catch (error) {
|
|
logger.error('EquipmentService.updateStatus failed', { error, id });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// MAINTENANCE LOG
|
|
// =========================================================================
|
|
|
|
async addWartungslog(
|
|
equipmentId: string,
|
|
data: CreateAusruestungWartungslogData,
|
|
createdBy: string
|
|
): Promise<AusruestungWartungslog> {
|
|
try {
|
|
const check = await pool.query(
|
|
`SELECT 1 FROM ausruestung WHERE id = $1 AND deleted_at IS NULL`,
|
|
[equipmentId]
|
|
);
|
|
if (check.rows.length === 0) {
|
|
throw new Error('Equipment not found');
|
|
}
|
|
|
|
const result = await pool.query(
|
|
`INSERT INTO ausruestung_wartungslog (
|
|
ausruestung_id, datum, art, beschreibung,
|
|
ergebnis, kosten, pruefende_stelle, dokument_url, erfasst_von
|
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)
|
|
RETURNING *`,
|
|
[
|
|
equipmentId,
|
|
data.datum,
|
|
data.art,
|
|
data.beschreibung,
|
|
data.ergebnis ?? null,
|
|
data.kosten ?? null,
|
|
data.pruefende_stelle ?? null,
|
|
data.dokument_url ?? null,
|
|
createdBy,
|
|
]
|
|
);
|
|
|
|
const entry = result.rows[0] as AusruestungWartungslog;
|
|
logger.info('Equipment wartungslog entry added', { entryId: entry.id, equipmentId, by: createdBy });
|
|
|
|
// Auto-update next inspection date on the equipment when result is 'bestanden'
|
|
if (data.ergebnis === 'bestanden' && data.naechste_pruefung_am) {
|
|
await pool.query(
|
|
`UPDATE ausruestung SET naechste_pruefung_am = $1, letzte_pruefung_am = $2 WHERE id = $3`,
|
|
[data.naechste_pruefung_am, data.datum, equipmentId]
|
|
);
|
|
}
|
|
|
|
return entry;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.addWartungslog failed', { error, equipmentId });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// DASHBOARD KPI
|
|
// =========================================================================
|
|
|
|
async getEquipmentStats(): Promise<EquipmentStats> {
|
|
try {
|
|
const result = await pool.query(`
|
|
SELECT
|
|
COUNT(*) AS total,
|
|
COUNT(*) FILTER (WHERE status = 'einsatzbereit') AS einsatzbereit,
|
|
COUNT(*) FILTER (WHERE status = 'beschaedigt') AS beschaedigt,
|
|
COUNT(*) FILTER (WHERE status = 'in_wartung') AS in_wartung,
|
|
COUNT(*) FILTER (WHERE status = 'ausser_dienst') AS ausser_dienst,
|
|
COUNT(*) FILTER (
|
|
WHERE naechste_pruefung_am IS NOT NULL
|
|
AND naechste_pruefung_am::date - CURRENT_DATE BETWEEN 0 AND 30
|
|
) AS inspections_due,
|
|
COUNT(*) FILTER (
|
|
WHERE naechste_pruefung_am IS NOT NULL
|
|
AND naechste_pruefung_am::date < CURRENT_DATE
|
|
) AS inspections_overdue,
|
|
COUNT(*) FILTER (
|
|
WHERE ist_wichtig = TRUE
|
|
AND status != 'einsatzbereit'
|
|
) AS wichtig_nicht_bereit
|
|
FROM ausruestung
|
|
WHERE deleted_at IS NULL
|
|
`);
|
|
|
|
const row = result.rows[0] ?? {};
|
|
|
|
return {
|
|
total: parseInt(row.total ?? '0', 10),
|
|
einsatzbereit: parseInt(row.einsatzbereit ?? '0', 10),
|
|
beschaedigt: parseInt(row.beschaedigt ?? '0', 10),
|
|
inWartung: parseInt(row.in_wartung ?? '0', 10),
|
|
ausserDienst: parseInt(row.ausser_dienst ?? '0', 10),
|
|
inspectionsDue: parseInt(row.inspections_due ?? '0', 10),
|
|
inspectionsOverdue: parseInt(row.inspections_overdue ?? '0', 10),
|
|
wichtigNichtBereit: parseInt(row.wichtig_nicht_bereit ?? '0', 10),
|
|
};
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getEquipmentStats failed', { error });
|
|
throw new Error('Failed to fetch equipment stats');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// VEHICLE WARNINGS
|
|
// =========================================================================
|
|
|
|
async getVehicleWarnings(): Promise<VehicleEquipmentWarning[]> {
|
|
try {
|
|
const result = await pool.query(`
|
|
SELECT
|
|
a.fahrzeug_id,
|
|
a.id AS ausruestung_id,
|
|
a.bezeichnung,
|
|
a.status,
|
|
k.name AS kategorie_name
|
|
FROM ausruestung a
|
|
JOIN ausruestung_kategorien k ON k.id = a.kategorie_id
|
|
WHERE a.ist_wichtig = TRUE
|
|
AND a.fahrzeug_id IS NOT NULL
|
|
AND a.status != 'einsatzbereit'
|
|
AND a.deleted_at IS NULL
|
|
ORDER BY a.fahrzeug_id
|
|
`);
|
|
|
|
return result.rows as VehicleEquipmentWarning[];
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getVehicleWarnings failed', { error });
|
|
throw new Error('Failed to fetch vehicle equipment warnings');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// UPCOMING INSPECTIONS
|
|
// =========================================================================
|
|
|
|
async getUpcomingInspections(daysAhead: number = 30): Promise<AusruestungListItem[]> {
|
|
try {
|
|
const result = await pool.query(
|
|
`SELECT *
|
|
FROM ausruestung_mit_pruefstatus
|
|
WHERE pruefung_tage_bis_faelligkeit IS NOT NULL
|
|
AND pruefung_tage_bis_faelligkeit <= $1
|
|
ORDER BY pruefung_tage_bis_faelligkeit ASC`,
|
|
[daysAhead]
|
|
);
|
|
|
|
return result.rows.map((row) => ({
|
|
...row,
|
|
pruefung_tage_bis_faelligkeit: row.pruefung_tage_bis_faelligkeit != null
|
|
? parseInt(row.pruefung_tage_bis_faelligkeit, 10) : null,
|
|
})) as AusruestungListItem[];
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getUpcomingInspections failed', { error, daysAhead });
|
|
throw new Error('Failed to fetch upcoming inspections');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// STATUS HISTORY
|
|
// =========================================================================
|
|
|
|
async getStatusHistory(equipmentId: string) {
|
|
try {
|
|
const result = await pool.query(
|
|
`SELECT h.*, COALESCE(u.name, u.preferred_username, u.email) AS geaendert_von_name
|
|
FROM ausruestung_status_historie h
|
|
LEFT JOIN users u ON u.id = h.geaendert_von
|
|
WHERE h.ausruestung_id = $1
|
|
ORDER BY h.erstellt_am DESC
|
|
LIMIT 50`,
|
|
[equipmentId]
|
|
);
|
|
return result.rows;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.getStatusHistory failed', { error, equipmentId });
|
|
throw new Error('Status-Historie konnte nicht geladen werden');
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// WARTUNGSLOG UPDATE
|
|
// =========================================================================
|
|
|
|
async updateWartungslog(
|
|
equipmentId: string,
|
|
wartungId: number,
|
|
data: UpdateAusruestungWartungslogData,
|
|
updatedBy: string
|
|
): Promise<AusruestungWartungslog> {
|
|
try {
|
|
// Verify the wartung entry belongs to this equipment
|
|
const check = await pool.query(
|
|
`SELECT id FROM ausruestung_wartungslog WHERE id = $1 AND ausruestung_id = $2`,
|
|
[wartungId, equipmentId]
|
|
);
|
|
if (check.rows.length === 0) {
|
|
throw new Error('Wartungseintrag nicht gefunden');
|
|
}
|
|
|
|
const fields: string[] = [];
|
|
const values: unknown[] = [];
|
|
let p = 1;
|
|
|
|
const addField = (col: string, value: unknown) => {
|
|
fields.push(`${col} = $${p++}`);
|
|
values.push(value);
|
|
};
|
|
|
|
if (data.datum !== undefined) addField('datum', data.datum);
|
|
if (data.art !== undefined) addField('art', data.art);
|
|
if (data.beschreibung !== undefined) addField('beschreibung', data.beschreibung);
|
|
if (data.ergebnis !== undefined) addField('ergebnis', data.ergebnis);
|
|
if (data.kosten !== undefined) addField('kosten', data.kosten);
|
|
if (data.pruefende_stelle !== undefined) addField('pruefende_stelle', data.pruefende_stelle);
|
|
|
|
if (fields.length === 0) {
|
|
throw new Error('No fields to update');
|
|
}
|
|
|
|
values.push(wartungId);
|
|
const result = await pool.query(
|
|
`UPDATE ausruestung_wartungslog SET ${fields.join(', ')} WHERE id = $${p} RETURNING *`,
|
|
values
|
|
);
|
|
|
|
const entry = result.rows[0] as AusruestungWartungslog;
|
|
|
|
// Auto-update next inspection date on the equipment when result is 'bestanden'
|
|
if (data.ergebnis === 'bestanden' && data.naechste_pruefung_am) {
|
|
await pool.query(
|
|
`UPDATE ausruestung SET naechste_pruefung_am = $1, letzte_pruefung_am = $2 WHERE id = $3`,
|
|
[data.naechste_pruefung_am, data.datum ?? entry.datum, equipmentId]
|
|
);
|
|
}
|
|
|
|
logger.info('Equipment wartungslog entry updated', { wartungId, equipmentId, by: updatedBy });
|
|
return entry;
|
|
} catch (error) {
|
|
logger.error('EquipmentService.updateWartungslog failed', { error, wartungId, equipmentId });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// WARTUNGSLOG FILE UPLOAD
|
|
// =========================================================================
|
|
|
|
async updateWartungslogFile(wartungId: number, filePath: string) {
|
|
try {
|
|
const result = await pool.query(
|
|
`UPDATE ausruestung_wartungslog SET dokument_url = $1 WHERE id = $2 RETURNING *`,
|
|
[filePath, wartungId]
|
|
);
|
|
if (result.rows.length === 0) {
|
|
throw new Error('Wartungseintrag nicht gefunden');
|
|
}
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
logger.error('EquipmentService.updateWartungslogFile failed', { error, wartungId });
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
export default new EquipmentService();
|