UnknownSec Bypass
403
:
/
mnt
/
lmsestudio-instance-vol002
/
lms_3fa2e970a29f
/
app
/
Console
/
Commands
/ [
drwxr-xr-x
]
Menu
Upload
Mass depes
Mass delete
Terminal
Info server
About
name :
RecurringExpiredBoleto.php
<?php namespace EstudioLMS\Console\Commands; use Carbon\Carbon; use EstudioLMS\Cart\Cart; use EstudioLMS\Events\RecurringNotification; use EstudioLMS\Repositories\Financial\RecurringInterface; use EstudioLMS\Repositories\Subscription\PeriodicityInterface; use EstudioLMS\Services\PagarMeService; use Illuminate\Console\Command; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Event; /** * Class RecurringExpiredBoleto * @package EstudioLMS\Console\Commands */ class RecurringExpiredBoleto extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'recurring:expired-boleto'; /** * The console command description. * * @var string */ protected $description = 'Processa todos os boletos vencidos e não pagos.'; /** * @var RecurringInterface */ private $recurring; /** * @var PeriodicityInterface */ private $periodicity; /** * @var PagarMeService */ private $pagarMeService; /** * Create a new command instance. * * @param RecurringInterface $recurring * @param PeriodicityInterface $periodicity * @param PagarMeService $pagarMeService */ public function __construct( RecurringInterface $recurring, PeriodicityInterface $periodicity, PagarMeService $pagarMeService ) { parent::__construct(); $this->recurring = $recurring; $this->periodicity = $periodicity; $this->pagarMeService = $pagarMeService; } /** * Execute the console command. * * Os seguintes status serão considerados, para o processamento das recorrências. * 0 - Registro sem processamento, deve ser feita a cobrança; * 1 - Registro processado; * 2 - Houve falha na cobrança - Cartão de Crédito - Será cobrado novamente em X dias; * 3 - Boleto emitido e ainda não pago; * 4 - Cancelamento solicitado. Ao invés de cobrar, deve marcar a assinatura como cancelada; * 5 - Registro de cancelamento processado; * 6 - Cancelado por falta de pagamento; * * @return void */ public function handle() { $today = Carbon::now()->format('Y-m-d'); $tomorow = Carbon::now()->addDay()->format('Y-m-d'); $recurrings = $this->recurring->getExpiredBoletos(); //Busca boletos com status 3 (emitidos e não pagos) e data de vencimento menor ou igual a data de hoje //dd($recurrings); Log::info('Processando boletos vencidos', ['count' => count($recurrings), 'date' => $today]); foreach ($recurrings as $key => $recurring) { try { $attempt = $recurring->attempts + 1; $periodicity = $this->periodicity->find($recurring->hire_subscription->periodicity_id); $boleto = ''; $needsNewBoleto = false; if (!empty($recurring->payment_code)) { // API v5: Buscar boleto através do order_id try { $boletoData = $this->pagarMeService->getBoletoDataFromOrder($recurring->payment_code); if ($boletoData) { // Criar objeto mock compatível com o sistema existente $boleto = new class($boletoData, $recurring) { private $data; private $recurring; public function __construct($data, $recurring) { $this->data = $data; $this->recurring = $recurring; } public function getId() { return $this->data['charge_id']; } public function getBoletoUrl() { return $this->data['boleto_url']; } public function getStatus() { return $this->data['status']; } public function getAmount() { return $this->data['amount']; } public function getPaidAmount() { return $this->data['paid_amount']; } public function getBarcode() { return $this->data['barcode']; } public function getDueAt() { return $this->data['due_at']; } public function getPaidAt() { return $this->data['paid_at']; } public function getCreatedAt() { return $this->data['created_at']; } public function getUpdatedAt() { return $this->data['updated_at']; } public function getPaymentMethod() { return $this->data['payment_method']; } public function getData() { return $this->data; } // CRÍTICO: Método getMetadata() esperado pelo evento RecurringNotification public function getMetadata() { return [ 'subscription_hash' => $this->recurring->subscription_hash, 'user_email' => $this->recurring->hire_subscription->user->email ?? null, 'user_id' => $this->recurring->user_id, 'product_id' => $this->recurring->hire_subscription->subscription_id ?? null, 'plan_id' => $this->recurring->hire_subscription->subscription_id ?? null ]; } }; Log::info('Dados do boleto obtidos com sucesso', [ 'recurring_id' => $recurring->id, 'payment_code' => $recurring->payment_code, 'boleto_status' => $boletoData['status'], 'boleto_url' => $boletoData['boleto_url'] ]); } else { Log::warning('Boleto não encontrado no pedido', [ 'recurring_id' => $recurring->id, 'payment_code' => $recurring->payment_code ]); $boleto = null; $needsNewBoleto = true; } } catch (\Exception $e) { Log::error('Erro ao obter dados do boleto via API v5', [ 'recurring_id' => $recurring->id, 'payment_code' => $recurring->payment_code, 'error' => $e->getMessage() ]); $boleto = null; $needsNewBoleto = true; // Se não conseguiu obter o boleto, gerar novo } } else { Log::info('Payment_code null - gerando novo boleto', ['recurring_id' => $recurring->id]); $needsNewBoleto = true; } // NOVO: Gerar boleto se necessário if ($needsNewBoleto) { try { $newBoleto = $this->generateNewBoleto($recurring, $periodicity); if ($newBoleto) { $boleto = $newBoleto; // CORREÇÃO: Usar order_id em vez de charge_id para payment_code $orderId = method_exists($newBoleto, 'getOrderId') ? $newBoleto->getOrderId() : $newBoleto->getId(); $recurring->payment_code = $orderId; $recurring->save(); // Atualizar também na hire_subscription $recurring->hire_subscription->payment_code = $orderId; $recurring->hire_subscription->save(); Log::info('Novo boleto gerado com sucesso', [ 'recurring_id' => $recurring->id, 'new_payment_code' => $orderId, 'charge_id' => method_exists($newBoleto, 'getId') ? $newBoleto->getId() : 'N/A' ]); } else { Log::error('Falha ao gerar novo boleto', ['recurring_id' => $recurring->id]); continue; // Pula para próxima recorrência se não conseguiu gerar boleto } } catch (\Exception $e) { Log::error('Erro ao gerar novo boleto', [ 'recurring_id' => $recurring->id, 'error' => $e->getMessage() ]); continue; } } //dd($boleto); // Garantir que $boleto seja um objeto válido ou null para as notificações $boletoIsInvalid = false; if (!is_object($boleto)) { $boletoIsInvalid = true; } elseif (!method_exists($boleto, 'getBoletoUrl')) { $boletoIsInvalid = true; } elseif (is_array($boleto) && isset($boleto['message']) && $boleto['message'] == 'Charge not found.') { $boletoIsInvalid = true; } if ($boletoIsInvalid) { Log::error('Boleto não encontrado ou inválido', [ 'recurring_id' => $recurring->id, 'boleto_type' => gettype($boleto), 'boleto_data' => is_array($boleto) ? $boleto : 'object' ]); // Permanece status 3 (emitido e não pago) e próxima tentativa $recurring->attempts = $attempt; $recurring->next_attempt_date = $tomorow; $recurring->payment_code = null; $recurring->save(); // Para eventos, usar subscription_hash em vez de null $boleto = $recurring->subscription_hash; continue; } if ($attempt < 10) { $recurring->status = 3; $recurring->attempts = $attempt; $recurring->next_attempt_date = $tomorow; $recurring->save(); //dd($boleto); Event::fire(new RecurringNotification('boleto-pending', $boleto)); // Agora sempre terá payment_code após gerar novo boleto se necessário if (!empty($recurring->payment_code) && !empty($recurring->hire_subscription->user->email)) { $this->pagarMeService->collectPayment($recurring->hire_subscription->user->email, $recurring->payment_code); Log::info('Boleto enviado com sucesso', [ 'recurring_id' => $recurring->id, 'payment_code' => $recurring->payment_code, 'user_email' => $recurring->hire_subscription->user->email ]); } else { Log::warning('Ainda não foi possível enviar boleto - dados insuficientes', [ 'recurring_id' => $recurring->id, 'payment_code' => $recurring->payment_code, 'user_email' => $recurring->hire_subscription->user->email ?? 'N/A' ]); } } elseif ($attempt >= 10 && $attempt < 15) { $recurring->status = 3; $recurring->attempts = $attempt; $recurring->next_attempt_date = $tomorow; $recurring->save(); $recurring->hire_subscription->status = 3; $recurring->hire_subscription->save(); Event::fire(new RecurringNotification('boleto-suspended', $boleto)); // Agora sempre terá payment_code após gerar novo boleto se necessário if (!empty($recurring->payment_code) && !empty($recurring->hire_subscription->user->email)) { $this->pagarMeService->collectPayment($recurring->hire_subscription->user->email, $recurring->payment_code); Log::info('Boleto suspenso enviado com sucesso', [ 'recurring_id' => $recurring->id, 'payment_code' => $recurring->payment_code, 'user_email' => $recurring->hire_subscription->user->email ]); } else { Log::warning('Ainda não foi possível enviar boleto suspenso - dados insuficientes', [ 'recurring_id' => $recurring->id, 'payment_code' => $recurring->payment_code, 'user_email' => $recurring->hire_subscription->user->email ?? 'N/A' ]); } } else { $recurring->status = 6; $recurring->attempts = $attempt; $recurring->save(); $recurring->hire_subscription->status = 4; $recurring->hire_subscription->save(); Event::fire(new RecurringNotification('boleto-canceled', $boleto)); } Log::info('Recorrência de boleto processada com sucesso', [ 'recurring_id' => $recurring->id, 'attempt' => $attempt, 'new_status' => $recurring->status, 'payment_code' => $recurring->payment_code ]); } catch (\Exception $e) { Log::error('Erro ao processar recorrência de boleto', [ 'recurring_id' => $recurring->id ?? 'N/A', 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); // Continue processando outras recorrências mesmo se uma falhar continue; } } Log::useDailyFiles(storage_path() . '/logs/command.log'); Log::alert('recurring:expired-boleto - Executado - ' . date('Y-m-d H:i:s') . ' - Processadas: ' . count($recurrings) . ' recorrências'); } /** * Gera um novo boleto para a recorrência * * @param mixed $recurring * @param mixed $periodicity * @return object|null */ private function generateNewBoleto($recurring, $periodicity) { try { // Validar se os objetos necessários existem if (!$recurring || !$periodicity || !$recurring->hire_subscription) { Log::error('Dados insuficientes para gerar boleto', [ 'has_recurring' => !is_null($recurring), 'has_periodicity' => !is_null($periodicity), 'has_hire_subscription' => !is_null($recurring->hire_subscription ?? null) ]); return null; } // Criar Cart baseado nos dados da recorrência $cart = new Cart(); $cart->addItem( $recurring->hire_subscription->subscription_id, // course_id $recurring->hire_subscription->subscription->title, $recurring->hire_subscription->subscription_id, // plan_id $periodicity, $recurring->gross_amount, // price null, // image 0.00, // discount 0.00, // extra_amount 0, // shipping_code 0.00, // shipping_price true // subscription flag ); Log::info('Gerando novo boleto para recorrência', [ 'recurring_id' => $recurring->id, 'subscription_hash' => $recurring->subscription_hash, 'gross_amount' => $recurring->gross_amount, 'user_id' => $recurring->user_id ]); // Gerar boleto usando API v5 $boleto = $this->pagarMeService->boletoSubscriptionTransaction( $cart, $recurring->subscription_hash, $recurring->user_id ); if ($boleto && is_object($boleto) && method_exists($boleto, 'getId')) { Log::info('Novo boleto gerado com sucesso', [ 'recurring_id' => $recurring->id, 'boleto_id' => $boleto->getId(), 'boleto_url' => method_exists($boleto, 'getBoletoUrl') ? $boleto->getBoletoUrl() : 'N/A' ]); return $boleto; } else { Log::error('Boleto retornado sem ID válido', [ 'recurring_id' => $recurring->id, 'boleto_type' => gettype($boleto) ]); return null; } } catch (\Exception $e) { Log::error('Erro na geração de novo boleto', [ 'recurring_id' => $recurring->id, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return null; } } }
Copyright © 2026 - UnknownSec