Files
shopit-back/app/Domains/Integration/Services/BaseIntegrationService.php
ncoronel d73b4d1daf feat: Introduce client management and integration updates
- Added client_id field to StoreTenantRequest and UpdateTenantRequest for tenant management.
- Updated TenantResource to include client_id in the response.
- Created migration to establish clients table and link tenants to clients.
- Migrated existing tenant integrations to client_integrations table.
- Grouped specific tenants under a shared client (OnTicket) in a new migration.
- Updated seeders to reflect new client structure and relationships.
- Adjusted integration configurations to require client instead of tenant.
- Added tests for client integration functionality and ensured existing tests reflect the new client structure.
2026-08-18 16:18:34 -03:00

171 lines
4.5 KiB
PHP

<?php
namespace App\Domains\Integration\Services;
use App\Domains\Client\Models\Client;
use App\Domains\Integration\Models\ClientIntegration;
use App\Domains\Integration\Models\Integration;
use App\Domains\Tenant\Models\Tenant;
use Exception;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
abstract class BaseIntegrationService
{
/**
* The unique code of the integration.
*/
protected string $integrationCode;
/**
* The current tenant code.
*/
protected string $tenantCode;
protected ?Tenant $tenant = null;
protected ?Client $clientContext = null;
/**
* The integration model instance.
*/
protected ?Integration $integration = null;
/**
* The client-owned integration configuration.
*/
protected ?ClientIntegration $clientIntegration = null;
/**
* Set the integration code.
*
* @return $this
*/
public function setIntegrationCode(string $integrationCode): self
{
$this->integrationCode = $integrationCode;
return $this;
}
/**
* Get the integration code.
*/
public function getIntegrationCode(): string
{
return $this->integrationCode;
}
/**
* Set the tenant code and load the integration models.
*
* @return $this
*
* @throws Exception
*/
public function forTenant(string $tenantCode): self
{
$this->tenantCode = $tenantCode;
$this->tenant = Tenant::query()->with('client')->where('codigo', $tenantCode)->firstOrFail();
$this->clientContext = $this->tenant->client;
$this->loadIntegration();
return $this;
}
public function forClient(Client|string $client): self
{
$this->clientContext = $client instanceof Client
? $client
: Client::query()->where('code', $client)->firstOrFail();
$this->tenant = null;
$this->loadIntegration();
return $this;
}
/**
* Load the integration definition and its client-owned configuration.
*
* @throws Exception
*/
protected function loadIntegration(): void
{
if (empty($this->integrationCode)) {
throw new Exception('Integration code is not set.');
}
$this->integration = Integration::where('integration_code', $this->integrationCode)->first();
if (! $this->integration) {
throw new Exception("Integration with code '{$this->integrationCode}' not found.");
}
if (! $this->clientContext) {
throw new Exception('Client context is not set.');
}
$this->clientIntegration = ClientIntegration::where('client_id', $this->clientContext->id)
->where('integration_code', $this->integrationCode)
->first();
if (! $this->clientIntegration && $this->integration->requires_client_configuration) {
throw new Exception("Client '{$this->clientContext->code}' does not have integration '{$this->integrationCode}' configured.");
}
}
/**
* Build the request URL.
*
* @throws Exception
*/
public function getUrl(string $path = ''): string
{
if (! $this->integration) {
throw new Exception('Integration is not loaded. Call forTenant() or forClient() first.');
}
$baseUrl = rtrim($this->integration->url, '/');
$path = ltrim($path, '/');
return $path !== '' ? "{$baseUrl}/{$path}" : $baseUrl;
}
/**
* Get an integration setting from the client-owned configuration.
*/
protected function getIntegrationSetting(string $key, mixed $default = null): mixed
{
if (! $this->clientIntegration || ! $this->clientIntegration->integration_data) {
return $default;
}
return $this->clientIntegration->integration_data[$key] ?? $default;
}
/**
* Get a pre-configured HTTP client builder.
*
* @throws Exception
*/
public function client(): PendingRequest
{
return Http::baseUrl($this->getUrl())
->withHeaders($this->getHeaders());
}
/**
* Get the headers for the integration.
*/
abstract public function getHeaders(): array;
/**
* Hook called after the integration is configured for the client.
* Can be used to validate credentials or perform initial setups.
* Throw an Exception on failure.
*/
public function onSetup(): void
{
// Override in child classes if needed
}
}