diff --git a/backend/src/routes/deposit.ts b/backend/src/routes/deposit.ts index 4f48a05..995fe06 100644 --- a/backend/src/routes/deposit.ts +++ b/backend/src/routes/deposit.ts @@ -1,7 +1,8 @@ import { FastifyPluginAsync } from 'fastify' import { db } from '../db' import { createHold, createCharge, capturePayment, cancelPayment, createRefund } from '../services/yookassa' -import { transporter } from '../email' +import { transporter, sendBookingConfirmedEmail } from '../email' +import { broadcast } from './ws' type SlugParam = { Params: { slug: string } } type SlugBookingParam = { Params: { slug: string; bookingId: string } } @@ -731,32 +732,68 @@ ${refund > 0 && (!items || items.length === 0) ? `
Ос
}
}
- // Auto-confirm booking on successful online widget payment
- if (object.status === 'succeeded') {
- const { rows: obRows } = await db.query(
- `SELECT ob.booking_id, ob.hotel_id
+ // Handle online widget booking payment
+ if (object.status === 'succeeded' || object.status === 'canceled') {
+ const { rows: obRows } = await db.query<{
+ id: string; booking_id: string | null; hotel_id: string; slug: string
+ guest_name: string; guest_email: string | null
+ check_in: string; check_out: string; total_amount: string; hotel_name: string
+ }>(
+ `SELECT ob.id, ob.booking_id, ob.hotel_id, h.slug, h.name AS hotel_name,
+ ob.guest_name, ob.guest_email, ob.check_in, ob.check_out, ob.total_amount
FROM online_bookings ob
- WHERE ob.yookassa_payment_id = $1`,
+ JOIN hotels h ON h.id = ob.hotel_id
+ WHERE ob.yookassa_payment_id = $1
+ LIMIT 1`,
[object.id],
)
- if (obRows[0]?.booking_id) {
- await db.query(
- `UPDATE online_bookings SET yookassa_status = 'succeeded' WHERE yookassa_payment_id = $1`,
- [object.id],
- )
- // Check gateway auto_confirm_on_payment
- const { rows: gwRows } = await db.query(
- `SELECT auto_confirm_on_payment FROM hotel_payment_gateways
- WHERE hotel_id = $1 AND is_active = true
- ORDER BY created_at LIMIT 1`,
- [obRows[0].hotel_id],
- )
- const autoConfirm = gwRows[0]?.auto_confirm_on_payment !== false // default true
- if (autoConfirm) {
+ if (obRows[0]) {
+ const ob = obRows[0]
+ if (object.status === 'succeeded') {
await db.query(
- `UPDATE bookings SET status = 'confirmed' WHERE id = $1 AND status = 'inquiry'`,
- [obRows[0].booking_id],
+ `UPDATE online_bookings SET status = 'paid', yookassa_status = 'succeeded' WHERE id = $1`,
+ [ob.id],
)
+ if (ob.booking_id) {
+ const { rows: bRows } = await db.query(
+ `UPDATE bookings
+ SET status = 'confirmed',
+ payment_status = 'paid',
+ paid_amount = total_amount,
+ updated_at = NOW()
+ WHERE id = $1 RETURNING *`,
+ [ob.booking_id],
+ )
+ if (bRows[0]) {
+ broadcast(ob.slug, { type: 'booking:updated', booking: bRows[0] })
+ }
+ }
+ if (ob.guest_email) {
+ sendBookingConfirmedEmail({
+ to: ob.guest_email,
+ guestName: ob.guest_name,
+ hotelName: ob.hotel_name,
+ checkIn: ob.check_in,
+ checkOut: ob.check_out,
+ totalAmount: ob.total_amount,
+ bookingConfirmUrl: `https://app.hotelsync.ru/booking-confirm/${ob.id}`,
+ }).catch(() => {})
+ }
+ } else {
+ await db.query(
+ `UPDATE online_bookings SET status = 'cancelled', yookassa_status = 'canceled' WHERE id = $1`,
+ [ob.id],
+ )
+ if (ob.booking_id) {
+ const { rows: bRows } = await db.query(
+ `UPDATE bookings SET status = 'cancelled', updated_at = NOW()
+ WHERE id = $1 RETURNING *`,
+ [ob.booking_id],
+ )
+ if (bRows[0]) {
+ broadcast(ob.slug, { type: 'booking:updated', booking: bRows[0] })
+ }
+ }
}
}
}
diff --git a/backend/src/routes/yookassaWebhook.ts b/backend/src/routes/yookassaWebhook.ts
index 25f5ab5..45745fd 100644
--- a/backend/src/routes/yookassaWebhook.ts
+++ b/backend/src/routes/yookassaWebhook.ts
@@ -1,96 +1,10 @@
import { FastifyPluginAsync } from 'fastify'
import { db } from '../db'
-import { broadcast } from './ws'
-import { sendBookingConfirmedEmail } from '../email'
+
+// This file provides a public status endpoint for the BookingConfirmPage.
+// YooKassa webhook notifications are handled in deposit.ts at POST /api/webhooks/yookassa
const yookassaWebhookRoutes: FastifyPluginAsync = async (fastify) => {
- // POST /api/yookassa/webhook
- // Receives payment status notifications from YooKassa.
- // YooKassa requires a 200 response; any non-200 triggers retries.
- fastify.post('/api/yookassa/webhook', async (req, reply) => {
- try {
- const body = req.body as Record Настройка вебхука в ЮКассе
+ В личном кабинете ЮКассы перейдите: Настройки → HTTP-уведомления и укажите этот URL для всех событий:
+
+ Включите события: payment.succeeded, payment.canceled, payment.waiting_for_capture
+ Использовать в модулях:
+ https://api.hotelsync.ru/api/webhooks/yookassa
+
+
+