'Comercial', 'purchasing'=>'Compras', 'stock'=>'Stock', 'workshop'=>'Oficinas', 'finance'=>'Financeiro', 'accounting'=>'Contabilidade', 'human_resources'=>'Recursos Humanos']; private const RIGHTS = [ 'human_resources'=>['human_resources.remunerations.','human_resources.contracts.','human_resources.attendance.','human_resources.leave.'], 'commercial'=>['commercial_quotes.','service_documents.','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'=>['financial_analysis.','bank_reconciliation.','cash.', 'direct_costs.', 'industrial_costs.', 'industrial_budgets.', 'industrial_budget_comparisons.', 'service_receivables.'], 'accounting'=>['fiscal_obligations.','fiscal_rules.','fiscal_assessments.','fiscal_forms.','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('~^(stock/catalogue|api/stock-catalogue)(/|$)~',$path))return 'stock'; if(preg_match('~^(finance/cash|api/cash)(/|$)~',$path))return 'finance'; if(preg_match('~^api/(remunerations|hr-personnel)(/|$)~',$path))return 'human_resources'; if(preg_match('~^api/fiscal-obligations(/|$)~',$path))return 'accounting'; if(preg_match('~^api/finance/payable-positions(/|$)~',$path))return 'finance'; if(preg_match('~^api/finance/payable-due(/|$)~',$path))return 'finance'; if(preg_match('~^(finance/payables|api/finance/payables)(/|$)~',$path))return 'finance'; if (preg_match('~^api/v1/integration/sgc/invoices(?:/orders/[1-9][0-9]*)?$~D', $path)) return 'purchasing'; 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('~^(commercial/documents|api/service-documents)(/|$)~', $path)) return 'commercial'; if(preg_match('~^(finance/indicators|api/financial-indicators)(/|$)~',$path))return 'finance'; if(preg_match('~^(finance/bank|api/bank-reconciliation)(/|$)~',$path))return 'finance'; if(preg_match('~^(fiscal/rules|api/fiscal-rules)(/|$)~',$path))return 'accounting'; if(preg_match('~^(fiscal/iva|api/fiscal-assessments)(/|$)~',$path))return 'accounting'; if (preg_match('~^(general-ledger|api/general-ledger)(/|$)~', $path)) return 'accounting'; if(preg_match('~^(api/commercial-quotes|commercial-quotes)(/|$)~',$path))return 'commercial'; if (preg_match('~^api/stock-read(/|$)~', $path)) return 'stock'; if (preg_match('~^(stock/(operations|final|completion)|api/(stock-operations|stock-final|stock-completion))(/|$)~', $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-schedule|workshop-equipment|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; } }