diff --git a/app/api/0pt/credits/checkout/route.ts b/app/api/0pt/credits/checkout/route.ts index 47c9097..fc86b39 100644 --- a/app/api/0pt/credits/checkout/route.ts +++ b/app/api/0pt/credits/checkout/route.ts @@ -27,6 +27,15 @@ export async function POST(request: NextRequest) { if ('response' in verified) return verified.response; const { tenantId } = verified.scope; + if (process.env.OPT_CREDITS_MODE === 'off') { + return NextResponse.json( + { + error: 'CREDITS_DISABLED', + message: 'Billing is not active yet (pilot mode). No payment can be taken.', + }, + { status: 503 }, + ); + } const book = readCreditPriceBook(); if (!book) { return NextResponse.json( diff --git a/app/api/0pt/credits/packs/route.ts b/app/api/0pt/credits/packs/route.ts index 3250635..d8d0e3c 100644 --- a/app/api/0pt/credits/packs/route.ts +++ b/app/api/0pt/credits/packs/route.ts @@ -27,6 +27,7 @@ export async function GET(request: NextRequest) { return NextResponse.json({ version: book.version, currency: book.currency, + purchases_enabled: process.env.OPT_CREDITS_MODE !== 'off', packs: book.packs.map((pack) => ({ id: pack.id, credits: pack.credits, diff --git a/app/api/0pt/documents/structure/route.ts b/app/api/0pt/documents/structure/route.ts index 7c54fc6..cfa50ba 100644 --- a/app/api/0pt/documents/structure/route.ts +++ b/app/api/0pt/documents/structure/route.ts @@ -163,13 +163,22 @@ export async function POST(request: NextRequest) { const dataClass = body.data_class ?? 'low'; const format = body.format ?? 'json'; + if (pipelineStage !== 'parsed') { + return NextResponse.json( + { + error: 'DOCUMENT_NOT_PARSED', + message: + 'The document has no verified text layer yet (parse_failed or not parsed). OCR is required before structuring.', + }, + { status: 422 }, + ); + } if ( !isValidScopeId(projectId) || !isValidScopeId(documentId) || !isValidScopeId(versionId) || typeof checksum !== 'string' || !/^[0-9a-f]{64}$/.test(checksum) || - pipelineStage !== 'parsed' || typeof instruction !== 'string' || !instruction.trim() || instruction.length > 4000 || diff --git a/app/portal/krediter/page.tsx b/app/portal/krediter/page.tsx index 4c79f8b..570d6fc 100644 --- a/app/portal/krediter/page.tsx +++ b/app/portal/krediter/page.tsx @@ -12,6 +12,7 @@ export default function CreditsPage() { const [balance, setBalance] = useState<{ available: number; reserved: number } | null>(null); const [balanceNote, setBalanceNote] = useState(null); const [packs, setPacks] = useState([]); + const [purchasesEnabled, setPurchasesEnabled] = useState(true); const [currency, setCurrency] = useState('SEK'); const [packsNote, setPacksNote] = useState(null); const [buying, setBuying] = useState(null); @@ -31,10 +32,16 @@ export default function CreditsPage() { } try { const r = await fetch('/api/0pt/credits/packs', { cache: 'no-store' }); - const body = (await r.json()) as { packs?: Pack[]; currency?: string; message?: string }; + const body = (await r.json()) as { + packs?: Pack[]; + currency?: string; + purchases_enabled?: boolean; + message?: string; + }; if (r.ok && body.packs) { setPacks(body.packs); setCurrency(body.currency ?? 'SEK'); + setPurchasesEnabled(body.purchases_enabled !== false); } else { setPacksNote( body.message ?? @@ -127,18 +134,30 @@ export default function CreditsPage() { {formatSEK(pack.amount_minor / 100)}

- + {purchasesEnabled ? ( + + ) : null} ))} )} + {!purchasesEnabled ? ( +

+ {t({ + en: 'Billing is not active yet (pilot). No payment can be taken.', + sv: 'Betalning är inte aktiverad än (pilot). Ingen betalning kan tas.', + })} +

+ ) : null} {status ?

{status}

: null}

{currency}