diff --git a/backend/scripts/send-test-webhook.ts b/backend/scripts/send-test-webhook.ts new file mode 100644 index 0000000..5ccc600 --- /dev/null +++ b/backend/scripts/send-test-webhook.ts @@ -0,0 +1,67 @@ +import 'dotenv/config'; +import crypto from 'crypto'; +import { PrismaClient } from '@prisma/client'; + +/** + * Simuliert eine eingehende Bank-Transaktion und schickt sie signiert an den + * lokal laufenden Webhook-Endpokt. Nutzung (nach `npm run seed` + `npm run dev`): + * + * npx ts-node scripts/send-test-webhook.ts "Zimmer 1" + * + * Ohne Argument wird die erste offene Zahlung aus der DB genommen. + */ +async function main() { + const prisma = new PrismaClient(); + const roomFilter = process.argv[2]; + + const payment = await prisma.payment.findFirst({ + where: { + status: 'PENDING', + ...(roomFilter + ? { contract: { room: { roomNumber: { equals: roomFilter } } } } + : {}), + }, + include: { contract: { include: { room: true, user: true } } }, + }); + + if (!payment) { + console.error('Keine offene Zahlung gefunden. Vorher `npm run seed` ausführen.'); + process.exit(1); + } + + const body = { + transactionId: `test-tx-${Date.now()}`, + accountIban: process.env.WG_ACCOUNT_IBAN ?? 'DE89370400440532013000', + amount: Number(payment.amount), + currency: 'EUR', + remittanceInfo: `Miete ${payment.contract.room.roomNumber} ${payment.contract.user.fullName}`, + bookingDate: new Date().toISOString(), + signature: '', // wird unten berechnet + }; + + const rawBodyWithoutSignature = JSON.stringify({ ...body, signature: '' }); + const secret = process.env.BANKING_WEBHOOK_SECRET ?? 'local_dev_secret_change_me'; + const signature = crypto.createHmac('sha256', secret).update(rawBodyWithoutSignature, 'utf8').digest('hex'); + + // Der Server berechnet die Signatur über den kompletten rohen Body inkl. + // Feld "signature" (leer) — daher senden wir exakt denselben String, den + // wir signiert haben, nicht ein neu serialisiertes Objekt. + const res = await fetch('http://localhost:3000/v1/webhooks/banking/transactions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Signature': signature, + }, + body: rawBodyWithoutSignature, + }); + + console.log('Status:', res.status); + console.log(await res.json()); + + await prisma.$disconnect(); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +});