| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- <?php
- namespace Models;
- use Libs\Database;
- use Libs\Hmac;
- use Libs\Logger;
- /**
- * Provisionamento de empresas (tenants).
- *
- * Cria a empresa e o seu primeiro usuário (admin) de forma ATÔMICA: ou os dois
- * são criados, ou nenhum. Já gera o segredo HMAC da empresa (usado nos webhooks
- * de CRM) no momento da criação.
- */
- class CompanyModel
- {
- private \PDO $pdo;
- public function __construct()
- {
- $this->pdo = Database::pdo();
- }
- /**
- * Cria a empresa + usuário admin numa única transação.
- *
- * @param array $company ['name', 'cnpj', 'logo']
- * @param array $admin ['name', 'email', 'phone', 'password']
- * @return array{status:string, company?:array, user?:array}
- * status: 'created' | 'cnpj_exists' | 'email_exists' | 'error'
- */
- public function createCompanyWithAdmin(array $company, array $admin): array
- {
- $companyName = trim((string) ($company['name'] ?? ''));
- $cnpj = preg_replace('/\D/', '', (string) ($company['cnpj'] ?? ''));
- $logo = trim((string) ($company['logo'] ?? ''));
- $userName = trim((string) ($admin['name'] ?? ''));
- $email = mb_strtolower(trim((string) ($admin['email'] ?? '')));
- $phone = trim((string) ($admin['phone'] ?? ''));
- $password = (string) ($admin['password'] ?? '');
- if ($this->cnpjExists($cnpj)) {
- return ['status' => 'cnpj_exists'];
- }
- if ($this->emailExists($email)) {
- return ['status' => 'email_exists'];
- }
- $secret = Hmac::generateSecret();
- $passwordHash = password_hash($password, PASSWORD_DEFAULT);
- $this->pdo->beginTransaction();
- try {
- $companyStmt = $this->pdo->prepare(
- "INSERT INTO company (company_name, company_cnpj, company_logo, company_hmac_secret)
- VALUES (:name, :cnpj, :logo, :secret)
- RETURNING company_id, company_name, company_cnpj, company_logo,
- company_hmac_secret, company_created_at"
- );
- $companyStmt->execute([
- 'name' => $companyName,
- 'cnpj' => $cnpj,
- 'logo' => $logo,
- 'secret' => $secret,
- ]);
- $createdCompany = $companyStmt->fetch(\PDO::FETCH_ASSOC);
- $companyId = (int) $createdCompany['company_id'];
- $userStmt = $this->pdo->prepare(
- "INSERT INTO \"user\" (company_id, user_name, user_phone, user_email, user_role, user_password)
- VALUES (:company_id, :user_name, :user_phone, :user_email, 'admin', :user_password)
- RETURNING user_id, company_id, user_name, user_phone, user_email, user_role, user_created_at"
- );
- $userStmt->execute([
- 'company_id' => $companyId,
- 'user_name' => $userName,
- 'user_phone' => $phone,
- 'user_email' => $email,
- 'user_password' => $passwordHash,
- ]);
- $createdUser = $userStmt->fetch(\PDO::FETCH_ASSOC);
- $this->pdo->commit();
- } catch (\Throwable $e) {
- $this->pdo->rollBack();
- Logger::error('Failed to create company with admin', [
- 'cnpj' => $cnpj,
- 'email' => $email,
- 'error' => $e->getMessage(),
- ]);
- return ['status' => 'error'];
- }
- return [
- 'status' => 'created',
- 'company' => [
- 'company_id' => $companyId,
- 'company_name' => $createdCompany['company_name'],
- 'company_cnpj' => $createdCompany['company_cnpj'],
- 'company_logo' => $createdCompany['company_logo'],
- 'company_hmac_secret' => $createdCompany['company_hmac_secret'],
- 'company_created_at' => $createdCompany['company_created_at'],
- ],
- 'user' => [
- 'user_id' => (int) $createdUser['user_id'],
- 'company_id' => (int) $createdUser['company_id'],
- 'user_name' => $createdUser['user_name'],
- 'user_phone' => $createdUser['user_phone'],
- 'user_email' => $createdUser['user_email'],
- 'user_role' => $createdUser['user_role'],
- 'user_created_at' => $createdUser['user_created_at'],
- ],
- ];
- }
- private function cnpjExists(string $cnpj): bool
- {
- $stmt = $this->pdo->prepare(
- "SELECT 1 FROM company
- WHERE company_cnpj = :cnpj AND company_deleted_at = 'infinity'
- LIMIT 1"
- );
- $stmt->execute(['cnpj' => $cnpj]);
- return $stmt->fetchColumn() !== false;
- }
- private function emailExists(string $email): bool
- {
- // user_email é UNIQUE global (não filtra por empresa).
- $stmt = $this->pdo->prepare('SELECT 1 FROM "user" WHERE user_email = :email LIMIT 1');
- $stmt->execute(['email' => $email]);
- return $stmt->fetchColumn() !== false;
- }
- }
|