refactor(integration): resolver credenciales mediante instancias

Resuelve primero la instancia del cliente y luego la del tipo de sitio cuando existe contexto de tenant. Adapta SMTP y Telepagos, con tokens identificados por instancia y version de credenciales.

Separa la edicion de instancias de sus asociaciones y conserva el guardado por cliente creando una instancia nueva. Impide eliminar instancias en uso y adapta las pruebas existentes, incluida la herencia SMTP.
This commit is contained in:
2026-09-04 12:47:47 -03:00
parent e4146288f1
commit c0057c237a
12 changed files with 190 additions and 54 deletions

View File

@@ -0,0 +1,21 @@
<?php
namespace Tests\Concerns;
use App\Domains\Integration\Models\ClientIntegration;
use App\Domains\Integration\Models\IntegrationInstance;
trait CreatesIntegrationInstances
{
private function createClientIntegration(array $attributes): ClientIntegration
{
$instance = IntegrationInstance::create([
'integration_code' => $attributes['integration_code'],
'name' => 'Test instance',
'integration_data' => $attributes['integration_data'],
]);
unset($attributes['integration_data']);
return ClientIntegration::create($attributes + ['integration_instance_id' => $instance->id]);
}
}

View File

@@ -4,7 +4,6 @@ namespace Tests\Feature\Integration;
use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Integration\Models\ClientIntegration;
use App\Domains\Integration\Models\Integration;
use App\Domains\Integration\Services\TelepagosIntegrationService;
use App\Domains\Tenant\Models\Tenant;
@@ -15,10 +14,12 @@ use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Tests\Concerns\CreatesIntegrationInstances;
use Tests\TestCase;
class IntegrationServiceTest extends TestCase
{
use CreatesIntegrationInstances;
use RefreshDatabase;
private Tenant $tenant;
@@ -110,7 +111,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -139,7 +140,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -198,7 +199,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -242,7 +243,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -272,7 +273,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -323,7 +324,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -375,7 +376,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -427,7 +428,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -480,7 +481,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -541,7 +542,7 @@ class IntegrationServiceTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $this->tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [
@@ -566,7 +567,7 @@ class IntegrationServiceTest extends TestCase
Log::shouldReceive('error')
->once()
->with('Telepagos get cash-in details failed: Cashin no encontrado', \Mockery::on(function ($context) {
return $context['cashin_id'] === 6351
return $context['cashin_id'] === '6351'
&& $context['response_status'] === 404
&& $context['response_body'] === ['status' => 'error', 'message' => 'Cashin no encontrado'];
}));

View File

@@ -4,28 +4,32 @@ namespace Tests\Feature\Integration;
use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Integration\Models\ClientIntegration;
use App\Domains\Integration\Models\Integration;
use App\Domains\Integration\Models\IntegrationInstance;
use App\Domains\Integration\Services\ClientIntegrationService;
use App\Domains\Integration\Services\IntegrationAssociationService;
use App\Domains\Integration\Services\MailService;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Models\WebsiteType;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailer;
use Illuminate\Mail\MailManager;
use Illuminate\Support\Facades\Mail;
use Mockery;
use Tests\Concerns\CreatesIntegrationInstances;
use Tests\TestCase;
class MailServiceTest extends TestCase
{
use CreatesIntegrationInstances;
use RefreshDatabase;
public function test_it_builds_an_isolated_smtp_mailer_from_the_client_integration(): void
{
$tenant = $this->createTenant();
$this->createEmailIntegration();
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $tenant->client_id,
'integration_code' => 'email',
'integration_data' => $this->emailData(),
@@ -40,7 +44,7 @@ class MailServiceTest extends TestCase
$manager->shouldReceive('build')
->once()
->with(Mockery::on(fn (array $config): bool => $config === [
'name' => 'client-smtp-'.$tenant->client_id,
'name' => 'integration-smtp-'.IntegrationInstance::firstOrFail()->id,
'transport' => 'smtp',
'scheme' => 'smtp',
'host' => 'smtp.example.com',
@@ -54,7 +58,7 @@ class MailServiceTest extends TestCase
$service = (new MailService($manager))->forTenant($tenant->codigo);
$this->assertSame('client-smtp', $service->mailerName());
$this->assertSame('integration-smtp', $service->mailerName());
}
public function test_it_uses_the_default_mailer_when_client_configuration_is_not_required(): void
@@ -84,7 +88,7 @@ class MailServiceTest extends TestCase
Mail::fake();
$tenant = $this->createTenant();
$this->createEmailIntegration();
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $tenant->client_id,
'integration_code' => 'email',
'integration_data' => $this->emailData(),
@@ -118,6 +122,24 @@ class MailServiceTest extends TestCase
Mail::assertSent(Mailable::class, 1);
}
public function test_it_uses_the_website_type_smtp_instance_without_a_client_association(): void
{
Mail::fake();
$tenant = $this->createTenant();
$this->createEmailIntegration();
$type = WebsiteType::create(['codigo' => 'mail-brand', 'nombre' => 'Mail Brand']);
$tenant->update(['website_type_code' => $type->codigo]);
$instance = IntegrationInstance::create([
'integration_code' => 'email', 'name' => 'Brand SMTP', 'integration_data' => $this->emailData(),
]);
(new IntegrationAssociationService)->associate($type, 'email', $instance);
$service = (new MailService)->forTenant($tenant->codigo);
self::assertSame('integration-smtp', $service->mailerName());
$service->send('customer@example.com', 'Brand mail', '<p>Brand SMTP</p>');
Mail::assertSent(Mailable::class, 1);
}
private function createTenant(): Tenant
{
$logo = Attachment::create([

View File

@@ -11,7 +11,6 @@ use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\Variant;
use App\Domains\Integration\Models\ClientIntegration;
use App\Domains\Integration\Models\Integration;
use App\Domains\Purchase\Models\Purchase;
use App\Domains\Purchase\Models\TelepagosPayment;
@@ -22,10 +21,12 @@ use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;
use Tests\Concerns\CreatesIntegrationInstances;
use Tests\TestCase;
class TelepagosWebhookTest extends TestCase
{
use CreatesIntegrationInstances;
use RefreshDatabase;
protected function setUp(): void
@@ -633,7 +634,7 @@ class TelepagosWebhookTest extends TestCase
],
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $tenant->client_id,
'integration_code' => 'telepagos_homo',
'integration_data' => [

View File

@@ -4,17 +4,18 @@ namespace Tests\Feature\MailTest;
use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Integration\Models\ClientIntegration;
use App\Domains\Integration\Models\Integration;
use App\Domains\MailTest\Mailables\TestMail;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Mail\Mailable;
use Illuminate\Support\Facades\Mail;
use Tests\Concerns\CreatesIntegrationInstances;
use Tests\TestCase;
class MailTestControllerTest extends TestCase
{
use CreatesIntegrationInstances;
use RefreshDatabase;
public function test_it_sends_a_test_email(): void
@@ -22,7 +23,7 @@ class MailTestControllerTest extends TestCase
Mail::fake();
$tenant = $this->createTenant();
$response = $this->postJson('/api/acme/mail-test/send', [
$response = $this->withHeader('Accept-Language', 'es')->postJson('/api/acme/mail-test/send', [
'to' => 'recipient@example.com',
'subject' => 'SMTP test',
'message' => 'Test message',
@@ -32,7 +33,7 @@ class MailTestControllerTest extends TestCase
->assertJsonPath('message', 'Correo de prueba enviado correctamente.')
->assertJsonPath('recipient', 'recipient@example.com')
->assertJsonPath('tenant_code', 'acme')
->assertJsonPath('mailer', 'tenant-smtp')
->assertJsonPath('mailer', 'integration-smtp')
->assertJsonStructure(['sent_at']);
Mail::assertSent(Mailable::class, function (Mailable $mail) use ($tenant): bool {
@@ -48,7 +49,7 @@ class MailTestControllerTest extends TestCase
Mail::fake();
$this->createTenant();
$this->postJson('/api/acme/mail-test/send', [
$this->withHeader('Accept-Language', 'es')->postJson('/api/acme/mail-test/send', [
'to' => 'recipient@example.com',
])->assertOk();
@@ -63,7 +64,7 @@ class MailTestControllerTest extends TestCase
Mail::fake();
$this->createTenant();
$this->postJson('/api/acme/mail-test/send', [
$this->withHeader('Accept-Language', 'es')->postJson('/api/acme/mail-test/send', [
'to' => 'invalid-email',
])->assertUnprocessable()
->assertJsonValidationErrors(['to']);
@@ -117,7 +118,7 @@ class MailTestControllerTest extends TestCase
{
Mail::fake();
$this->postJson('/api/unknown/mail-test/send', [
$this->withHeader('Accept-Language', 'es')->postJson('/api/unknown/mail-test/send', [
'to' => 'recipient@example.com',
])->assertNotFound();
@@ -129,7 +130,7 @@ class MailTestControllerTest extends TestCase
Mail::fake();
$tenant = $this->createTenant();
$this->postJson("/api/{$tenant->id}/mail-test/send", [
$this->withHeader('Accept-Language', 'es')->postJson("/api/{$tenant->id}/mail-test/send", [
'to' => 'recipient@example.com',
])->assertNotFound();
@@ -171,7 +172,7 @@ class MailTestControllerTest extends TestCase
'integration_code' => 'email',
'name' => 'Email',
]);
ClientIntegration::create([
$this->createClientIntegration([
'client_id' => $tenant->client_id,
'integration_code' => 'email',
'integration_data' => [