| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- <?php
- namespace App\Services;
- use App\Exceptions\AsaasException;
- use App\Models\UnitPaymentAccount;
- use App\Services\Integrations\Asaas\AsaasWebhookService;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Validation\ValidationException;
- class UnitPaymentAccountService
- {
- public function __construct(
- protected AsaasWebhookService $webhookService,
- ) {}
- public function getByUnitId(int $unitId): ?UnitPaymentAccount
- {
- return UnitPaymentAccount::where('unit_id', $unitId)->first();
- }
- /**
- * Cria/atualiza a conta de pagamento da unidade.
- *
- * Ao informar uma chave: valida na Asaas e garante um webhook. Uma MESMA chave
- * pode ser compartilhada por várias unidades (mesmo dono) — nesse caso o webhook
- * é registrado uma única vez e reaproveitado (dedupe por hash da chave). As
- * finanças seguem separadas por unidade (externalReference STU_/TBR_).
- */
- public function upsertAsaasApiKey(int $unitId, ?string $apiKey): UnitPaymentAccount
- {
- $apiKey = $apiKey !== null ? trim($apiKey) : null;
- $hasKey = $apiKey !== null && $apiKey !== '';
- $model = UnitPaymentAccount::firstOrNew(['unit_id' => $unitId]);
- if (!$hasKey) {
- $this->releaseWebhook($model);
- $model->asaas_api_key = null;
- $model->asaas_api_key_hash = null;
- $model->asaas_webhook_id = null;
- $model->status = UnitPaymentAccount::STATUS_PENDING;
- $model->onboarded_at = null;
- $model->save();
- return $model->fresh();
- }
- $hash = hash('sha256', $apiKey);
- // Reenvio da mesma chave já configurada: mantém como está.
- if ($model->exists && $model->asaas_api_key === $apiKey && $model->asaas_webhook_id) {
- return $model->fresh();
- }
- try {
- $this->webhookService->validateKey($apiKey);
- } catch (AsaasException $e) {
- throw ValidationException::withMessages([
- 'asaas_api_key' => 'Chave Asaas inválida ou sem permissão. Verifique e tente novamente.',
- ]);
- }
- // Troca de chave: libera o webhook antigo (só remove se ninguém mais usa).
- $this->releaseWebhook($model);
- $webhookId = $this->resolveWebhookId($unitId, $apiKey, $hash);
- $model->asaas_api_key = $apiKey;
- $model->asaas_api_key_hash = $hash;
- $model->asaas_webhook_id = $webhookId;
- $model->status = UnitPaymentAccount::STATUS_ACTIVE;
- $model->onboarded_at = $model->onboarded_at ?? now();
- $model->save();
- return $model->fresh();
- }
- /**
- * Reaproveita o webhook de outra unidade que usa a MESMA chave; senão, registra.
- */
- private function resolveWebhookId(int $unitId, string $apiKey, string $hash): string
- {
- $sibling = UnitPaymentAccount::where('asaas_api_key_hash', $hash)
- ->where('unit_id', '!=', $unitId)
- ->whereNotNull('asaas_webhook_id')
- ->first();
- if ($sibling) {
- return $sibling->asaas_webhook_id;
- }
- try {
- return $this->webhookService->register($apiKey);
- } catch (AsaasException $e) {
- Log::error("Falha ao registrar webhook Asaas da unidade {$unitId}: " . $e->getMessage());
- throw ValidationException::withMessages([
- 'asaas_api_key' => 'Não foi possível registrar o webhook na Asaas. Tente novamente.',
- ]);
- }
- }
- /**
- * Remove o webhook atual — a menos que outra unidade ainda o utilize (chave
- * compartilhada). Best-effort: erros são apenas logados.
- */
- private function releaseWebhook(UnitPaymentAccount $model): void
- {
- if (!$model->asaas_api_key || !$model->asaas_webhook_id) {
- return;
- }
- $stillShared = UnitPaymentAccount::where('asaas_webhook_id', $model->asaas_webhook_id)
- ->where('unit_id', '!=', $model->unit_id)
- ->exists();
- if ($stillShared) {
- return;
- }
- try {
- $this->webhookService->delete($model->asaas_api_key, $model->asaas_webhook_id);
- } catch (\Throwable $e) {
- Log::warning("Não foi possível remover webhook Asaas da unidade {$model->unit_id}: " . $e->getMessage());
- }
- }
- }
|