Przeglądaj źródła

feat(asaas-account): enhance subaccount creation with error handling and logging

ebagabee 1 miesiąc temu
rodzic
commit
409787f288

+ 46 - 1
app/Services/Integrations/Asaas/AsaasAccountService.php

@@ -2,9 +2,11 @@
 
 namespace App\Services\Integrations\Asaas;
 
+use App\Exceptions\AsaasException;
 use App\Models\Unit;
 use App\Models\UnitPaymentAccount;
 use Exception;
+use Illuminate\Support\Facades\Log;
 
 class AsaasAccountService
 {
@@ -27,6 +29,13 @@ public function ensureSubaccount(Unit $unit): UnitPaymentAccount
             throw new Exception("A unidade {$unit->fantasy_name} não possui um CNPJ cadastrado. O CNPJ é obrigatório para criar a subconta.");
         }
 
+        // Garante a chave de criptografia ANTES de chamar o Asaas. Sem APP_KEY, o
+        // POST cria a subconta lá, mas o save local falha ao encriptar a apiKey
+        // (cast 'encrypted') -> subconta órfã: apiKey perdida e e-mail/CNPJ travados.
+        if (empty(config('app.key'))) {
+            throw new Exception("APP_KEY não configurada. Abortando antes de criar a subconta no Asaas para evitar conta órfã (Unidade {$unit->id}).");
+        }
+
         $payload = [
             'name' => $unit->fantasy_name ?? $unit->social_reason ?? 'Unidade Ginástica do Cérebro',
             'email' => $unit->email,
@@ -40,17 +49,53 @@ public function ensureSubaccount(Unit $unit): UnitPaymentAccount
             'incomeValue' => 10000.00, // Renda/Faturamento exigido pelo Asaas
         ];
 
-        $response = $this->client->post('/accounts', $payload);
+        try {
+            $response = $this->client->post('/accounts', $payload);
+        } catch (AsaasException $e) {
+            // Colisão de e-mail (400): diagnostica se a conta é SUA (órfã, recuperável
+            // só pelo painel) ou EXTERNA (e-mail em uso fora do seu parent -> trocar e-mail).
+            if ($e->getCode() === 400 && str_contains($e->getMessage(), 'já está em uso')) {
+                $this->logEmailCollision($unit);
+            }
+            throw $e;
+        }
 
         return UnitPaymentAccount::updateOrCreate(
             ['unit_id' => $unit->id],
             [
                 'asaas_account_id' => $response['id'],
                 'asaas_wallet_id' => $response['walletId'],
+                // Cast 'encrypted' do model encripta no save; e SyncStudentChargeJob
+                // espera mais uma camada manual. Mantém o encryptString para casar.
                 'asaas_api_key' => \Illuminate\Support\Facades\Crypt::encryptString($response['apiKey']),
                 'status' => 'ACTIVE',
                 'onboarded_at' => now(),
             ]
         );
     }
+
+    /**
+     * Loga, no erro de e-mail em uso, se a conta colidente pertence ao seu parent
+     * (subconta órfã) ou é externa — para acelerar o diagnóstico.
+     */
+    private function logEmailCollision(Unit $unit): void
+    {
+        try {
+            $accounts = $this->client->get('/accounts', ['email' => $unit->email])['data'] ?? [];
+
+            if (count($accounts) > 0) {
+                Log::warning("Asaas: e-mail {$unit->email} já é uma SUBCONTA SUA (órfã). Recuperável só pelo painel/encerramento.", [
+                    'unit_id' => $unit->id,
+                    'asaas_account_id' => $accounts[0]['id'] ?? null,
+                    'wallet_id' => $accounts[0]['walletId'] ?? null,
+                ]);
+            } else {
+                Log::warning("Asaas: e-mail {$unit->email} está em uso em conta EXTERNA (fora do seu parent). Cadastre a unidade com outro e-mail.", [
+                    'unit_id' => $unit->id,
+                ]);
+            }
+        } catch (\Throwable $t) {
+            // Diagnóstico é best-effort: nunca mascara o erro original do POST.
+        }
+    }
 }