$unitId, 'tbr_calculation_id' => null, 'financial_plan_account_id' => $data['financial_plan_account_id'] ?? null, 'origin' => $unitId ? 'manual_unit' : 'manual_internal', 'history' => $data['history'], 'value' => $data['value'], 'paid_value' => 0, 'due_date' => $data['due_date'], 'discount' => 0, 'fees' => 0, 'obs' => $data['obs'] ?? null, 'status' => 'pending', ]); if ($unitId) { UnitAccountPayable::create([ 'unit_id' => $unitId, 'franchisee_account_receive_id' => $receivable->id, 'origin' => UnitAccountPayable::ORIGIN_MANUAL, 'history' => $receivable->history, 'value' => $receivable->value, 'paid_value' => 0, 'discount' => 0, 'fine' => 0, 'due_date' => $receivable->due_date, 'status' => 'pending', 'obs' => $receivable->obs, ]); $this->notifications->dispatch([ 'origin_table' => 'franchisee_account_receives', 'origin_id' => $receivable->id, 'unit_id' => $unitId, 'type' => NotificationType::ACCOUNT_PAYABLE_CREATED->value, 'title' => 'Nova conta a pagar', 'message' => "Uma nova conta a pagar foi criada: {$receivable->history}.", 'url' => '/financial/accounts-payable', 'action_text' => 'Ver Contas a Pagar', 'priority' => 'normal', 'recipient_user_ids' => $this->notifications->unitUserIds($unitId), ]); } return $receivable->load(['unit', 'details', 'planAccount']); }); } public function settle(FranchiseeAccountReceive $receivable, array $data): FranchiseeAccountReceive { if ($receivable->status->value === 'paid') { throw ValidationException::withMessages(['status' => 'Esta conta já está paga.']); } return DB::transaction(function () use ($receivable, $data) { $receivable->update([ 'status' => 'paid', 'paid_value' => $receivable->value, 'payment_date' => $data['payment_date'] ?? Carbon::today()->format('Y-m-d'), ]); UnitAccountPayable::where('franchisee_account_receive_id', $receivable->id) ->update([ 'status' => 'paid', 'paid_value' => $receivable->value, 'payment_date' => $data['payment_date'] ?? Carbon::today()->format('Y-m-d'), ]); if ($receivable->unit_id) { $this->notifications->dispatch([ 'origin_table' => 'franchisee_account_receives', 'origin_id' => $receivable->id, 'unit_id' => $receivable->unit_id, 'type' => NotificationType::PAYMENT_CREDITED->value, 'title' => 'Pagamento confirmado', 'message' => "Sua cobrança {$receivable->history} foi devidamente creditada e consta como paga.", 'url' => '/financial/accounts-payable', 'action_text' => 'Ver Contas a Pagar', 'priority' => 'normal', 'recipient_user_ids' => $this->notifications->unitUserIds($receivable->unit_id), ]); } return $receivable->fresh(['unit', 'details', 'planAccount']); }); } public function generateCharge(FranchiseeAccountReceive $receivable): FranchiseeAccountReceive { if (! $receivable->unit_id) { throw ValidationException::withMessages([ 'unit' => 'Cobranças Asaas só podem ser geradas para contas vinculadas a uma unidade.', ]); } if (in_array($receivable->status->value, ['paid', 'cancelled'], true)) { throw ValidationException::withMessages([ 'status' => 'Contas pagas ou canceladas não podem gerar cobrança.', ]); } if ($receivable->asaas_id) { throw ValidationException::withMessages([ 'asaas' => 'Esta conta já possui cobrança gerada.', ]); } if (empty(CompanyPaymentAccount::resolveApiKey())) { throw ValidationException::withMessages([ 'asaas' => 'A franqueadora não possui chave Asaas configurada.', ]); } try { SyncFranchiseeChargeJob::dispatchSync($receivable); } catch (Exception) { throw ValidationException::withMessages([ 'asaas' => 'Não foi possível gerar a cobrança na Asaas. Tente novamente.', ]); } return $receivable->fresh(['unit', 'details', 'planAccount']); } public function reopen(FranchiseeAccountReceive $receivable): FranchiseeAccountReceive { throw ValidationException::withMessages([ 'status' => 'Uma conta paga não pode voltar para um status anterior.', ]); } }