feat: centralized payment gateways + booking widget API
Backend:
- Migration 065: hotel_payment_gateways table (migrates YooKassa from deposit_settings)
- online_bookings table for widget submissions
- Routes: CRUD /api/hotels/:slug/payment-gateways
- Public widget API: /api/widget/:slug/{config,availability,bookings}
- yookassa.ts: add createCharge() for immediate capture
Frontend:
- PaymentSettingsPage: add 'Онлайн-оплата' section with gateway CRUD and module toggles
- DepositSettingsPage: replace YooKassa fields with link to centralized settings
- BookingWidgetPage: connect to real API, show gateway status, real booking submit
- api.ts: add PaymentGateway types, paymentGateways and widget API methods
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -182,59 +182,17 @@ export function DepositSettingsPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<p className="font-medium text-slate-800 dark:text-slate-200 text-sm">ЮКасса (опционально)</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mt-0.5">
|
||||
Укажите реквизиты ЮКасса для создания холда (предавторизации) оплаты.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="form-label">ID магазина (shopId)</label>
|
||||
<input value={shopId} onChange={e => setShopId(e.target.value)} placeholder="123456" className="input w-full" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="form-label">Секретный ключ</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showSecret ? 'text' : 'password'}
|
||||
value={secretKey} onChange={e => setSecretKey(e.target.value)}
|
||||
placeholder={settings?.yookassaSecretKey ? '••••••••' : 'live_xxxx...'}
|
||||
className="input w-full pr-10"
|
||||
/>
|
||||
<button type="button" onClick={() => setShowSecret(s => !s)} className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600">
|
||||
{showSecret ? <EyeOff size={15} /> : <Eye size={15} />}
|
||||
</button>
|
||||
</div>
|
||||
{settings?.yookassaSecretKey && (
|
||||
<p className="text-xs text-slate-400 mt-1">Ключ уже сохранён. Оставьте поле пустым, чтобы не менять.</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="rounded-lg bg-violet-50 dark:bg-violet-900/10 border border-violet-200 dark:border-violet-700 p-3 space-y-1.5">
|
||||
<p className="text-xs font-semibold text-violet-800 dark:text-violet-300">ЮКасса настраивается в одном месте</p>
|
||||
<p className="text-xs text-violet-700 dark:text-violet-400">
|
||||
Реквизиты ЮКасса (Shop ID и секретный ключ) теперь управляются централизованно.
|
||||
Перейдите в <a href="/settings/payments" className="underline font-medium">Настройки оплаты → Онлайн-оплата</a> и добавьте шлюз один раз — он будет работать для депозита, онлайн-бронирования и Room Service.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{shopId && (
|
||||
<div className="border-t border-slate-100 dark:border-slate-700 pt-4">
|
||||
<div className="rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 p-3 space-y-1.5">
|
||||
<p className="text-xs font-semibold text-blue-800 dark:text-blue-300 flex items-center gap-1.5">
|
||||
<Info size={13} /> Настройте webhook в ЮКасса
|
||||
</p>
|
||||
<p className="text-xs text-blue-700 dark:text-blue-400">
|
||||
Чтобы статус депозита обновлялся автоматически, добавьте URL в личном кабинете ЮКасса (Настройки → HTTP-уведомления):
|
||||
</p>
|
||||
<code className="block text-xs font-mono bg-blue-100 dark:bg-blue-900/40 text-blue-900 dark:text-blue-200 rounded px-2 py-1 break-all select-all">
|
||||
https://api.hotelsync.ru/api/webhooks/yookassa
|
||||
</code>
|
||||
<p className="text-xs text-blue-600 dark:text-blue-400">
|
||||
Подписки: <strong>payment.waiting_for_capture</strong>, <strong>payment.succeeded</strong>, <strong>payment.canceled</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{shopId && (
|
||||
<div className="border-t border-slate-100 dark:border-slate-700 pt-4">
|
||||
<p className="font-medium text-slate-800 dark:text-slate-200 text-sm mb-1">QR-код для гостей</p>
|
||||
<div className="border-t border-slate-100 dark:border-slate-700 pt-4">
|
||||
<p className="font-medium text-slate-800 dark:text-slate-200 text-sm mb-1">QR-код для гостей</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mb-4">
|
||||
Распечатайте и разместите на стойке ресепшена.
|
||||
</p>
|
||||
@@ -259,7 +217,6 @@ export function DepositSettingsPage() {
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user