'Comercial', 'purchasing'=>'Compras', 'stock'=>'Stock', 'workshop'=>'Oficinas', 'finance'=>'Financeiro', 'accounting'=>'Contabilidade']; private const RIGHTS = [ 'commercial'=>['clients.', 'services.', 'service_drafts.', 'billing_drafts.', 'issuer_documents.', 'client_documents.', 'draft_documents.', 'service_invoices.'], 'purchasing'=>['purchasing_budget.', 'purchasing_requisitions.', 'purchasing_receipts.', 'purchasing_orders.', 'purchasing_sourcing.', 'purchasing_suppliers.', 'purchasing_requests.', 'purchasing_invoices.', 'purchasing_obligations.', 'supplier_payables.'], 'stock'=>['stock.'], 'workshop'=>['workshop.', 'workshop_billing.', 'workshop_corrections.'], 'finance'=>['direct_costs.', 'industrial_costs.', 'industrial_budgets.', 'industrial_budget_comparisons.', 'service_receivables.'], 'accounting'=>['catalogue_accounting.', 'service_fiscal.', 'general_ledger.'], ]; public function available(CompanyContext $context): array { $s = $context->identifiers(); $grants = DB::table('permission_grants')->where($s)->where('user_id', $context->userId()) ->where(fn($q) => $q->whereNull('unit_id')->orWhere('unit_id', $context->unitId()))->pluck('permission')->all(); $development = app()->environment(['local','testing','browser-testing']) && in_array($context->userId().':'.$s['tenant_id'].':'.$s['company_id'], config('modules.development_profiles', []), true); if ($development) { // A local environment name alone must never turn client accounts into // development profiles. Discovery also requires the isolated DB guard. try { \App\Shared\Testing\TestingDatabaseGuard::assertSafe(); } catch (\RuntimeException) { $development=false; } } $policy = config('modules.companies.'.$s['tenant_id'].':'.$s['company_id'], []); $contracted = $policy['contracted'] ?? config('modules.contracted', []); $enabled = $policy['enabled'] ?? $contracted; $out = []; foreach (self::LABELS as $id => $label) { $authorized = false; foreach ($grants as $permission) { foreach (self::RIGHTS[$id] as $prefix) { if (str_starts_with($permission, $prefix) && str_ends_with($permission, '.view')) { $authorized = true; } } } if ($development || ($authorized && in_array($id,$contracted,true) && in_array($id,$enabled,true))) { $out[] = ['id'=>$id, 'label'=>$label, 'development'=>$development, 'operations_authorized'=>$authorized]; } } return $out; } // Ownership of existing endpoints, not an attribution of legacy rows to a new module. // Company, unit and access configuration are explicitly general. public static function owner(string $path): ?string { if (preg_match('~^(geography|geography/segments|api/geography/entities|api/geography/segments)/client(/|$)~', $path)) return 'commercial'; if (preg_match('~^(geography|geography/segments|api/geography/entities|api/geography/segments)/supplier(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/dossiers|api/purchasing-dossiers)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^purchasing/workspace(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/obligations|api/purchasing-obligations)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/invoices|api/purchasing-invoices)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/requests|api/purchasing-requests)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/suppliers|api/purchasing-suppliers)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/sourcing|api/purchasing-sourcing)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/orders|api/purchasing-orders)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(purchasing/receipts|api/purchasing-receipts)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^api/stock-valuation-read(/|$)~', $path)) return 'accounting'; if (preg_match('~^(purchasing/internal-requisitions|api/internal-requisitions)(/|$)~', $path)) return 'purchasing'; if (preg_match('~^(general-ledger|api/general-ledger)(/|$)~', $path)) return 'accounting'; if (preg_match('~^api/stock-read(/|$)~', $path)) return 'stock'; if (preg_match('~^(supplier-payables|supplier-payments|api/(supplier-payables|supplier-payments|purchasing-budget))(/|$)~', $path)) return 'purchasing'; if (preg_match('~^api/(workshop|workshop-stock|workshop-billing|workshop-corrections)(/|$)~', $path)) return 'workshop'; if (preg_match('~^api/(direct-costs|industrial-costs|industrial-budgets|service-receivables)(/|$)~', $path)) return 'finance'; if (preg_match('~^api/(catalogue-accounting|service-fiscal)(/|$)~', $path)) return 'accounting'; if (preg_match('~^api/(a|b1|service-invoices|service-calculations|document-preview|document-preparation)(/|$)~', $path)) return 'commercial'; return null; } }