- B1: Next.js 15 + Payload CMS 3.0 + Postgres 16, ESLint, Prettier, Husky, Vitest - B2: 9 collections, 6 globals, 12 Page Builder blocks, access control, slugify/revalidate hooks - B3: ezy.com.ua payments, Binotel HMAC webhook, leads API, Telegram bot, Resend email, rate limiting - B4: Tariffs collection with ezy API sync (cron + manual), dynamic pricing source-of-truth - B5: 13 test files covering unit libs and all API routes - B6: Dockerfile multi-stage, docker-compose.prod.yml, nginx.conf SSL, GitHub Actions CI/CD, health endpoint - B7: docs/admin-guide-ua.md (marketer guide), docs/deploy.md (VPS instructions), README quickstart Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
import { getPayload } from 'payload'
|
|
import config from '@payload-config'
|
|
import { getTariffs } from '@/lib/ezy'
|
|
import { logger } from '@/lib/logger'
|
|
|
|
export const dynamic = 'force-dynamic'
|
|
|
|
export async function GET(): Promise<NextResponse> {
|
|
try {
|
|
const ezyTariffs = await getTariffs()
|
|
|
|
const payload = await getPayload({ config })
|
|
const { docs: dbTariffs } = await payload.find({
|
|
collection: 'tariffs',
|
|
where: { visible: { equals: true } },
|
|
limit: 100,
|
|
overrideAccess: true,
|
|
})
|
|
|
|
const merged = ezyTariffs
|
|
.map((t) => {
|
|
const dbRecord = dbTariffs.find((d) => d.ezy_id === t.id)
|
|
if (!dbRecord) return null
|
|
return {
|
|
id: t.id,
|
|
name: dbRecord.display_name ?? t.name,
|
|
price: t.price,
|
|
categoryTag: dbRecord.category_tag,
|
|
description: dbRecord.description,
|
|
image: dbRecord.image,
|
|
icon: dbRecord.icon,
|
|
sort: dbRecord.sort ?? 0,
|
|
}
|
|
})
|
|
.filter(<T>(v: T | null): v is T => v !== null)
|
|
.sort((a, b) => a.sort - b.sort)
|
|
|
|
return NextResponse.json({ tariffs: merged })
|
|
} catch (err) {
|
|
logger.error({ err }, 'Failed to get tariffs from ezy — trying DB fallback')
|
|
|
|
try {
|
|
const payload = await getPayload({ config })
|
|
const { docs } = await payload.find({
|
|
collection: 'tariffs',
|
|
where: { visible: { equals: true } },
|
|
limit: 100,
|
|
overrideAccess: true,
|
|
})
|
|
|
|
if (docs.length === 0) {
|
|
return NextResponse.json({ error: 'Tariffs unavailable' }, { status: 503 })
|
|
}
|
|
|
|
const fallback = docs
|
|
.map((d) => ({
|
|
id: d.ezy_id,
|
|
name: d.display_name ?? d.last_synced_name,
|
|
price: d.last_synced_price,
|
|
categoryTag: d.category_tag,
|
|
description: d.description,
|
|
image: d.image,
|
|
icon: d.icon,
|
|
sort: d.sort ?? 0,
|
|
stale: true,
|
|
}))
|
|
.sort((a, b) => a.sort - b.sort)
|
|
|
|
return NextResponse.json({ tariffs: fallback, warning: 'Prices may be outdated' })
|
|
} catch (dbErr) {
|
|
logger.error({ dbErr }, 'DB fallback also failed')
|
|
return NextResponse.json({ error: 'Service unavailable' }, { status: 503 })
|
|
}
|
|
}
|
|
}
|