import type { Request, Response } from "express"; import { ZodError } from "zod"; import { createEstimateBalanceDeleteProjectCommand, createEstimateBalanceInsertProjectCommand, createEstimateBalanceSnapshot, createEstimateBalanceUpdateProjectCommand, parseEstimateBalanceSnapshot, sameEstimateBalance, } from "../../estimate-balance/domain/estimate-balance-command.model.js"; import { createEstimateBalanceRequestSchema, deleteEstimateBalanceRequestSchema, updateEstimateBalanceRequestSchema, } from "../../estimate-balance/api/estimate-balance-request.schemas.js"; import { compareEstimateWithDetailed } from "../../shared/estimate-balance/estimate-balance.js"; import { estimateBalanceRepository } from "../composition/application-repositories.js"; import { projectCommandService } from "../composition/project-command-stores.js"; import { respondWithProjectCommandError } from "./project-command.controller.js"; function params(req: Request) { const { projectId, balanceId } = req.params; return { projectId: typeof projectId === "string" ? projectId : null, balanceId: typeof balanceId === "string" ? balanceId : null, }; } export function listEstimateBalances(req: Request, res: Response) { const { projectId } = params(req); if (!projectId) { return res.status(400).json({ error: "Ungültige Projekt-ID." }); } return res.json(estimateBalanceRepository.listByProject(projectId)); } export function getEstimateBalance(req: Request, res: Response) { const { projectId, balanceId } = params(req); if (!projectId || !balanceId) { return res.status(400).json({ error: "Ungültige Parameter." }); } const balance = estimateBalanceRepository.findById(projectId, balanceId); if (!balance) { return res.status(404).json({ error: "Grobe Leistungsbilanz nicht gefunden." }); } return res.json(balance); } export function createEstimateBalance(req: Request, res: Response) { const { projectId } = params(req); if (!projectId) { return res.status(400).json({ error: "Ungültige Projekt-ID." }); } const parsed = createEstimateBalanceRequestSchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ error: parsed.error.flatten() }); } let template: Parameters[0]["template"] = parsed.data.template === "copy" ? "empty" : parsed.data.template; if (parsed.data.template === "copy") { const source = estimateBalanceRepository.findById( projectId, parsed.data.copyFromBalanceId! ); if (!source) { return res .status(404) .json({ error: "Der zu kopierende Stand wurde nicht gefunden." }); } template = { copyFrom: source }; } try { const balance = createEstimateBalanceSnapshot({ projectId, name: parsed.data.name, workStage: parsed.data.workStage ?? null, dateIso: parsed.data.dateIso ?? null, sortOrder: estimateBalanceRepository.nextSortOrder(projectId), template, }); const result = projectCommandService.executeUser({ projectId, expectedRevision: parsed.data.expectedRevision, description: "Grobe Leistungsbilanz anlegen", command: createEstimateBalanceInsertProjectCommand(balance), }); return res.status(201).json({ ...result, balance }); } catch (error) { return respondWithProjectCommandError(error, res); } } export function updateEstimateBalance(req: Request, res: Response) { const { projectId, balanceId } = params(req); if (!projectId || !balanceId) { return res.status(400).json({ error: "Ungültige Parameter." }); } const parsed = updateEstimateBalanceRequestSchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ error: parsed.error.flatten() }); } let target; try { target = parseEstimateBalanceSnapshot(parsed.data.balance); } catch (error) { return res.status(400).json({ error: "Die grobe Leistungsbilanz enthält ungültige Werte.", issues: error instanceof ZodError ? error.issues : undefined, }); } if (target.id !== balanceId || target.projectId !== projectId) { return res .status(400) .json({ error: "Die Bilanz gehört nicht zu diesem Projekt oder dieser Adresse." }); } const current = estimateBalanceRepository.findById(projectId, balanceId); if (!current) { return res.status(404).json({ error: "Grobe Leistungsbilanz nicht gefunden." }); } if (sameEstimateBalance(current, target)) { return res.json({ unchanged: true, balance: current }); } try { const result = projectCommandService.executeUser({ projectId, expectedRevision: parsed.data.expectedRevision, description: "Grobe Leistungsbilanz bearbeiten", command: createEstimateBalanceUpdateProjectCommand(current, target), }); return res.json({ ...result, balance: estimateBalanceRepository.findById(projectId, balanceId), }); } catch (error) { return respondWithProjectCommandError(error, res); } } export function deleteEstimateBalance(req: Request, res: Response) { const { projectId, balanceId } = params(req); if (!projectId || !balanceId) { return res.status(400).json({ error: "Ungültige Parameter." }); } const parsed = deleteEstimateBalanceRequestSchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ error: parsed.error.flatten() }); } const current = estimateBalanceRepository.findById(projectId, balanceId); if (!current) { return res.status(404).json({ error: "Grobe Leistungsbilanz nicht gefunden." }); } try { const result = projectCommandService.executeUser({ projectId, expectedRevision: parsed.data.expectedRevision, description: "Grobe Leistungsbilanz löschen", command: createEstimateBalanceDeleteProjectCommand(current), }); return res.json(result); } catch (error) { return respondWithProjectCommandError(error, res); } } export function getEstimateComparison(req: Request, res: Response) { const { projectId, balanceId } = params(req); if (!projectId || !balanceId) { return res.status(400).json({ error: "Ungültige Parameter." }); } const balance = estimateBalanceRepository.findById(projectId, balanceId); if (!balance) { return res.status(404).json({ error: "Grobe Leistungsbilanz nicht gefunden." }); } return res.json( compareEstimateWithDetailed( balance, estimateBalanceRepository.listDetailedDeviceRowPower(projectId) ) ); }