feat: initial commit — asaas-checkout template white-label
Template genérico de checkout com ASAAS, parametrizado via env vars. Inclui fluxo completo: checkout → pedido → polling → webhook → admin. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
48
app/api/pedido/[id]/route.ts
Normal file
48
app/api/pedido/[id]/route.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { NextResponse } from "next/server"
|
||||
import { createServiceClient } from "@/lib/supabase"
|
||||
import { buscarPagamentoAsaas, mapearStatus } from "@/lib/asaas"
|
||||
|
||||
export async function GET(
|
||||
_request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await params
|
||||
const supabase = createServiceClient()
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from("pedidos")
|
||||
.select(
|
||||
"id, status, valor_centavos, metodo_pagamento, pix_copia_cola, pix_qrcode_url, asaas_invoice_url, asaas_payment_id, paid_at, clientes(nome, email), produtos(nome, validade, midia)"
|
||||
)
|
||||
.eq("id", id)
|
||||
.single()
|
||||
|
||||
if (error || !data) {
|
||||
return NextResponse.json({ error: "Pedido não encontrado" }, { status: 404 })
|
||||
}
|
||||
|
||||
// Se ainda está pendente, consulta o ASAAS diretamente para pegar status atualizado
|
||||
if (data.status === "PENDING" && data.asaas_payment_id) {
|
||||
try {
|
||||
const asaasPayment = await buscarPagamentoAsaas(data.asaas_payment_id)
|
||||
const novoStatus = mapearStatus(asaasPayment.status)
|
||||
|
||||
if (novoStatus !== "PENDING") {
|
||||
const isPago = novoStatus === "RECEIVED" || novoStatus === "CONFIRMED"
|
||||
const updateData: Record<string, unknown> = { status: novoStatus }
|
||||
if (isPago) updateData.paid_at = new Date().toISOString()
|
||||
|
||||
await supabase
|
||||
.from("pedidos")
|
||||
.update(updateData)
|
||||
.eq("id", id)
|
||||
|
||||
return NextResponse.json({ ...data, status: novoStatus, paid_at: isPago ? updateData.paid_at : null })
|
||||
}
|
||||
} catch {
|
||||
// Falha silenciosa — retorna o que tem no banco
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json(data)
|
||||
}
|
||||
45
app/api/pedido/[id]/sync/route.ts
Normal file
45
app/api/pedido/[id]/sync/route.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { NextResponse } from "next/server"
|
||||
import { createServiceClient } from "@/lib/supabase"
|
||||
import { buscarPagamentoAsaas, mapearStatus } from "@/lib/asaas"
|
||||
|
||||
export async function POST(
|
||||
_request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await params
|
||||
const supabase = createServiceClient()
|
||||
|
||||
const { data: pedido } = await supabase
|
||||
.from("pedidos")
|
||||
.select("id, status, asaas_payment_id")
|
||||
.eq("id", id)
|
||||
.single()
|
||||
|
||||
if (!pedido) {
|
||||
return NextResponse.json({ error: "Pedido não encontrado" }, { status: 404 })
|
||||
}
|
||||
|
||||
if (!pedido.asaas_payment_id) {
|
||||
return NextResponse.json({ error: "Pedido sem ID ASAAS" }, { status: 400 })
|
||||
}
|
||||
|
||||
try {
|
||||
const asaasPayment = await buscarPagamentoAsaas(pedido.asaas_payment_id)
|
||||
const novoStatus = mapearStatus(asaasPayment.status)
|
||||
const isPago = novoStatus === "RECEIVED" || novoStatus === "CONFIRMED"
|
||||
|
||||
const updateData: Record<string, unknown> = { status: novoStatus }
|
||||
if (isPago && !pedido.status.includes("RECEIVED") && !pedido.status.includes("CONFIRMED")) {
|
||||
updateData.paid_at = new Date().toISOString()
|
||||
}
|
||||
|
||||
await supabase.from("pedidos").update(updateData).eq("id", id)
|
||||
|
||||
return NextResponse.json({ status: novoStatus, asaas_status: asaasPayment.status })
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
{ error: err instanceof Error ? err.message : "Erro ao consultar ASAAS" },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user