diff --git a/Dockerfile b/Dockerfile index 12292e2..065ce06 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,4 +24,4 @@ COPY --from=builder /app/dist ./dist EXPOSE 3000 -CMD ["node", "dist/server.cjs"] +CMD ["sh", "-c", "npx prisma db push && node dist/server.cjs"] diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8f2e96b..d262b8a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -256,6 +256,8 @@ model SystemSettings { asaasWebhookSecret String @default("") @map("asaas_webhook_secret") helpText String @db.Text @default("# Central de Ajuda") @map("help_text") enableBoleto Boolean @default(true) @map("enable_boleto") + enableInstallmentBoleto Boolean @default(false) @map("enable_installment_boleto") + maxBoletoInstallments Int @default(3) @map("max_boleto_installments") evolutionApiUrl String @default("https://evolution.microtecinformaticacurso.com.br") @map("evolution_api_url") evolutionApiKey String @default("") @map("evolution_api_key") diff --git a/server.ts b/server.ts index 049ebea..6c998ba 100644 --- a/server.ts +++ b/server.ts @@ -1218,6 +1218,8 @@ app.get('/api/settings', authenticateToken, async (req: AuthenticatedRequest, re trialDurationDays: settings?.trialDurationDays || 7, helpText: settings?.helpText || '', enableBoleto: settings?.enableBoleto !== false, + enableInstallmentBoleto: settings?.enableInstallmentBoleto === true, + maxBoletoInstallments: settings?.maxBoletoInstallments || 3, brandName: settings?.brandName || 'MICROTEC', brandSlogan: settings?.brandSlogan || 'Acelere seus estudos em informática e pacote Office no estilo Netflix.', cnpj: settings?.cnpj || '', @@ -2214,12 +2216,14 @@ async function startServer() { console.log(`DevFlix Server running on port ${PORT}`); }); - // Background job to clean up expired PIX payments (older than 5 minutes) + // Background job to clean up expired PIX payments (older than 5 minutes) and Boleto payments (older than 2 days) setInterval(async () => { try { const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); + const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000); - const expiredPayments = await prisma.payment.findMany({ + // Clean PIX + const expiredPix = await prisma.payment.findMany({ where: { billingType: 'PIX', status: 'PENDING', @@ -2227,21 +2231,40 @@ async function startServer() { } }); - for (const payment of expiredPayments) { - console.log(`[PIX Expire Job] Expirando e deletando pagamento ${payment.id}...`); - + for (const payment of expiredPix) { + console.log(`[PIX Expire Job] Expirando e deletando PIX ${payment.id}...`); const deletedInAsaas = await AsaasService.deletePayment(payment.id); - if (deletedInAsaas) { await prisma.payment.update({ where: { id: payment.id }, data: { status: 'CANCELED' } }); - console.log(`[PIX Expire Job] Pagamento ${payment.id} cancelado com sucesso.`); + console.log(`[PIX Expire Job] PIX ${payment.id} cancelado com sucesso.`); + } + } + + // Clean BOLETO + const expiredBoleto = await prisma.payment.findMany({ + where: { + billingType: 'BOLETO', + status: 'PENDING', + createdAt: { lt: twoDaysAgo } + } + }); + + for (const payment of expiredBoleto) { + console.log(`[Boleto Expire Job] Expirando e deletando Boleto ${payment.id}...`); + const deletedInAsaas = await AsaasService.deletePayment(payment.id); + if (deletedInAsaas) { + await prisma.payment.update({ + where: { id: payment.id }, + data: { status: 'CANCELED' } + }); + console.log(`[Boleto Expire Job] Boleto ${payment.id} cancelado com sucesso.`); } } } catch (err: any) { - console.error('[PIX Expire Job] Erro ao limpar pagamentos expirados:', err.message); + console.error('[Expire Job] Erro ao limpar pagamentos expirados:', err.message); } }, 60 * 1000); // Check every 60 seconds (1 minute) } diff --git a/src/components/AdminDashboard.tsx b/src/components/AdminDashboard.tsx index 45d5d9b..1289409 100644 --- a/src/components/AdminDashboard.tsx +++ b/src/components/AdminDashboard.tsx @@ -980,10 +980,40 @@ export default function AdminDashboard({ token, adminUser, onLogout }: AdminDash />
Boleto Bancário
-- O boleto será gerado no valor de R$ {currentPrice.toFixed(2)}. O prazo de compensação é de 1 a 2 dias úteis. -
+ + {!paymentData ? ( ++ O boleto será gerado no valor de R$ {currentPrice.toFixed(2)}. O prazo de compensação é de 1 a 2 dias úteis. +
+ ) : ( ++ Boleto gerado com sucesso no valor de R$ {currentPrice.toFixed(2)} {paymentData.payment?.installmentCount > 1 ? `parcelado em ${paymentData.payment.installmentCount}x` : ''}. +
+ )} + + {!paymentData && enableInstallmentBoleto && (!selectedPlanObj || selectedPlanObj.cycle === 'LIFETIME') && ( +