fix/events_integrations #11
@@ -2,13 +2,14 @@
|
||||
|
||||
namespace App\Domains\Commerce\Purchase\Models;
|
||||
|
||||
use App\Domains\Core\Auth\Models\User;
|
||||
use App\Domains\Commerce\Cart\Models\Cart;
|
||||
use App\Domains\Commerce\Catalog\Models\StockReservation;
|
||||
use App\Shared\Logging\Models\Concerns\LogsValueChanges;
|
||||
use App\Domains\Commerce\Purchase\Events\PurchasePaid;
|
||||
use App\Domains\Core\Auth\Models\User;
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Event\Models\Event;
|
||||
use App\Domains\Ticketing\Ticket\Models\Ticket;
|
||||
use App\Shared\Logging\Models\Concerns\LogsValueChanges;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -21,6 +22,7 @@ use Illuminate\Support\Facades\DB;
|
||||
#[Fillable([
|
||||
'cart_id',
|
||||
'stock_reservation_id',
|
||||
'event_id',
|
||||
'tenant_codigo',
|
||||
'user_id',
|
||||
'status',
|
||||
@@ -149,6 +151,7 @@ class Purchase extends Model
|
||||
return [
|
||||
'cart_id' => 'integer',
|
||||
'stock_reservation_id' => 'integer',
|
||||
'event_id' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
'total' => 'decimal:2',
|
||||
];
|
||||
@@ -162,6 +165,12 @@ class Purchase extends Model
|
||||
return $this->belongsTo(Tenant::class, 'tenant_codigo', 'codigo');
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Event, $this> */
|
||||
public function event(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Event::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<User, $this>
|
||||
*/
|
||||
|
||||
@@ -36,11 +36,11 @@ class PurchaseResource extends JsonResource
|
||||
=== StorefrontWebsiteType::CHECKOUT_SUMMARY_EVENT;
|
||||
/** @var Event|null $checkoutEvent */
|
||||
$checkoutEvent = $usesEventSummary
|
||||
? $items
|
||||
? ($this->event ?? $items
|
||||
->map(fn (PurchaseItem $item) => $item->sourceCatalogItem?->event)
|
||||
->filter()
|
||||
->unique('id')
|
||||
->first()
|
||||
->first())
|
||||
: null;
|
||||
|
||||
$subtotal = $items->isNotEmpty()
|
||||
@@ -62,6 +62,7 @@ class PurchaseResource extends JsonResource
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'cart_id' => $this->cart_id,
|
||||
'event_id' => $this->event_id,
|
||||
'tenant_codigo' => $this->tenant_codigo,
|
||||
'user_id' => $this->user_id,
|
||||
'created_at' => $this->created_at,
|
||||
|
||||
@@ -14,6 +14,7 @@ class PurchaseResponseLoader
|
||||
=== StorefrontWebsiteType::CHECKOUT_SUMMARY_EVENT;
|
||||
$relations = [
|
||||
'tenant',
|
||||
'event.attachment',
|
||||
'items.sourceCatalogItem.event.attachment',
|
||||
'stockReservation',
|
||||
];
|
||||
|
||||
@@ -206,6 +206,7 @@ class StartCheckoutService
|
||||
fn (array $line): float => $line['selection']->getPrice() * $line['quantity'],
|
||||
),
|
||||
$cart->getKey(),
|
||||
$cartItems->first()?->catalogItem?->event_id,
|
||||
);
|
||||
$cart->update(['current_purchase_id' => $purchase->getKey()]);
|
||||
$this->reservations->attachToPurchase($cart, $purchase, $this->checkoutExpiration());
|
||||
@@ -273,6 +274,7 @@ class StartCheckoutService
|
||||
$purchaseData,
|
||||
$cart->getTotalAmount(),
|
||||
$cart->getKey(),
|
||||
$cartItems->first()?->catalogItem?->event_id,
|
||||
);
|
||||
$cart->update(['current_purchase_id' => $purchase->getKey()]);
|
||||
$this->reservations->attachToPurchase($cart, $purchase, $this->checkoutExpiration());
|
||||
@@ -410,10 +412,12 @@ class StartCheckoutService
|
||||
array $purchaseData,
|
||||
float $total,
|
||||
?int $cartId,
|
||||
?int $eventId,
|
||||
): Purchase {
|
||||
return Purchase::query()->create([
|
||||
...$purchaseData,
|
||||
'cart_id' => $cartId,
|
||||
'event_id' => $eventId,
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
'user_id' => $userId,
|
||||
'status' => Purchase::STATUS_CREATED,
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace App\Domains\Core\Client\Models;
|
||||
|
||||
use App\Shared\Integration\Models\ClientIntegration;
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Event\Models\Event;
|
||||
use App\Shared\Integration\Models\ClientIntegration;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -22,6 +23,12 @@ class Client extends Model
|
||||
return $this->hasMany(Tenant::class);
|
||||
}
|
||||
|
||||
/** @return HasMany<Event, $this> */
|
||||
public function events(): HasMany
|
||||
{
|
||||
return $this->hasMany(Event::class);
|
||||
}
|
||||
|
||||
/** @return HasMany<ClientIntegration, $this> */
|
||||
public function integrations(): HasMany
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Domains\Ticketing\Event\Models;
|
||||
|
||||
use App\Domains\Commerce\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Core\Client\Models\Client;
|
||||
use App\Domains\Core\Tenant\Models\SocialMedia;
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Ticket\Models\Ticket;
|
||||
@@ -14,14 +15,14 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Fillable(['tenant_code', 'slug', 'event_category_id', 'title', 'subtitle', 'description', 'location', 'exact_location', 'date_text', 'published_at', 'attachment_id'])]
|
||||
#[Fillable(['client_id', 'tenant_code', 'slug', 'event_category_id', 'title', 'subtitle', 'description', 'location', 'exact_location', 'date_text', 'published_at', 'attachment_id'])]
|
||||
class Event extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return ['published_at' => 'datetime', 'exact_location' => 'array'];
|
||||
return ['client_id' => 'integer', 'published_at' => 'datetime', 'exact_location' => 'array'];
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Tenant, $this> */
|
||||
@@ -30,6 +31,17 @@ class Event extends Model
|
||||
return $this->belongsTo(Tenant::class, 'tenant_code', 'codigo');
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Client, $this> */
|
||||
public function client(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Client::class);
|
||||
}
|
||||
|
||||
public function effectiveClient(): Client
|
||||
{
|
||||
return $this->client ?? $this->tenant->client;
|
||||
}
|
||||
|
||||
/** @return BelongsTo<EventCategory, $this> */
|
||||
public function eventCategory(): BelongsTo
|
||||
{
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table): void {
|
||||
$table->foreignId('client_id')
|
||||
->nullable()
|
||||
->after('id')
|
||||
->constrained('clients')
|
||||
->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('client_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('compras', function (Blueprint $table): void {
|
||||
$table->foreignId('event_id')
|
||||
->nullable()
|
||||
->after('tenant_codigo')
|
||||
->constrained('events')
|
||||
->nullOnDelete();
|
||||
});
|
||||
|
||||
DB::table('compras')
|
||||
->orderBy('id')
|
||||
->each(function (object $purchase): void {
|
||||
$eventIds = DB::table('compra_items')
|
||||
->join('catalog_items', 'catalog_items.id', '=', 'compra_items.source_catalog_item_id')
|
||||
->where('compra_items.compra_id', $purchase->id)
|
||||
->whereNotNull('catalog_items.event_id')
|
||||
->distinct()
|
||||
->pluck('catalog_items.event_id');
|
||||
|
||||
if ($eventIds->count() === 1) {
|
||||
DB::table('compras')
|
||||
->where('id', $purchase->id)
|
||||
->update(['event_id' => $eventIds->first()]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('compras', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('event_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
private const EVENT_TITLE = '26.º Fiesta de la Tradición y 4.º Encuentro de Agrupaciones Gauchas';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$clientId = DB::table('clients')
|
||||
->where('code', 'pyme_rural')
|
||||
->value('id');
|
||||
|
||||
if ($clientId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('events')
|
||||
->where('tenant_code', 'onticket')
|
||||
->where('title', self::EVENT_TITLE)
|
||||
->update(['client_id' => $clientId]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$clientId = DB::table('clients')
|
||||
->where('code', 'pyme_rural')
|
||||
->value('id');
|
||||
|
||||
if ($clientId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('events')
|
||||
->where('tenant_code', 'onticket')
|
||||
->where('title', self::EVENT_TITLE)
|
||||
->where('client_id', $clientId)
|
||||
->update(['client_id' => null]);
|
||||
}
|
||||
};
|
||||
@@ -6,6 +6,7 @@ use App\Domains\Commerce\Catalog\Enums\InventoryPolicy;
|
||||
use App\Domains\Commerce\Catalog\Models\Attribute;
|
||||
use App\Domains\Commerce\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Commerce\Catalog\Services\CatalogService;
|
||||
use App\Domains\Core\Client\Models\Client;
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Event\Models\Event;
|
||||
use App\Shared\Attachable\Services\AttachmentService;
|
||||
@@ -35,6 +36,12 @@ class FiestaTradicionArrufoSeeder extends Seeder
|
||||
throw new RuntimeException("Tenant 'onticket' no encontrado.");
|
||||
}
|
||||
|
||||
$client = Client::query()->where('code', 'pyme_rural')->first();
|
||||
|
||||
if ($client === null) {
|
||||
throw new RuntimeException("Client 'pyme_rural' no encontrado.");
|
||||
}
|
||||
|
||||
Attribute::query()->firstOrCreate(
|
||||
['tenant_codigo' => $tenant->codigo, 'codigo' => 'event_date'],
|
||||
['nombre' => 'Fecha', 'type' => FieldType::EventDate, 'is_required' => true],
|
||||
@@ -45,6 +52,7 @@ class FiestaTradicionArrufoSeeder extends Seeder
|
||||
['published_at' => now()],
|
||||
);
|
||||
$event->update([
|
||||
'client_id' => $client->id,
|
||||
'subtitle' => 'Una noche para celebrar nuestras raíces y mantener viva la tradición gaucha.',
|
||||
'description' => 'La 26.º Fiesta de la Tradición y 4.º Encuentro de Agrupaciones Gauchas reunirá a agrupaciones, artesanos, pilcheros y público en general para compartir una jornada dedicada a nuestras costumbres y cultura.'
|
||||
."\n\n".'Un encuentro para disfrutar de la tradición, la identidad gaucha y el espíritu de camaradería, en el Predio de Doma del Club Unión Deportiva Arrufó.'
|
||||
|
||||
57
tests/Feature/Migrations/AddClientIdToEventsTest.php
Normal file
57
tests/Feature/Migrations/AddClientIdToEventsTest.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Migrations;
|
||||
|
||||
use App\Domains\Core\Client\Models\Client;
|
||||
use App\Domains\Ticketing\Event\Models\Event;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AddClientIdToEventsTest extends TestCase
|
||||
{
|
||||
public function test_event_client_overrides_the_tenant_client_when_configured(): void
|
||||
{
|
||||
Schema::create('clients', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('code');
|
||||
$table->string('name');
|
||||
});
|
||||
Schema::create('tenants', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('client_id');
|
||||
$table->string('codigo');
|
||||
});
|
||||
Schema::create('events', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('tenant_code');
|
||||
$table->string('title');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
DB::table('clients')->insert([
|
||||
['id' => 10, 'code' => 'tenant-client', 'name' => 'Tenant Client'],
|
||||
['id' => 11, 'code' => 'event-client', 'name' => 'Event Client'],
|
||||
]);
|
||||
DB::table('tenants')->insert(['id' => 20, 'client_id' => 10, 'codigo' => 'tenant']);
|
||||
DB::table('events')->insert([
|
||||
'id' => 30,
|
||||
'tenant_code' => 'tenant',
|
||||
'title' => 'Event',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$migration = require database_path('migrations/2026_09_28_000000_add_client_id_to_events.php');
|
||||
$migration->up();
|
||||
|
||||
$event = Event::query()->findOrFail(30);
|
||||
$this->assertSame(10, $event->effectiveClient()->id);
|
||||
|
||||
$event->update(['client_id' => 11]);
|
||||
|
||||
$this->assertSame(11, $event->fresh()->effectiveClient()->id);
|
||||
$this->assertTrue(Client::query()->findOrFail(11)->events()->whereKey(30)->exists());
|
||||
}
|
||||
}
|
||||
44
tests/Feature/Migrations/AddEventIdToPurchasesTest.php
Normal file
44
tests/Feature/Migrations/AddEventIdToPurchasesTest.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Migrations;
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AddEventIdToPurchasesTest extends TestCase
|
||||
{
|
||||
public function test_it_backfills_the_event_from_purchase_items(): void
|
||||
{
|
||||
Schema::create('events', fn (Blueprint $table) => $table->id());
|
||||
Schema::create('compras', fn (Blueprint $table) => $table->id());
|
||||
Schema::create('catalog_items', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('event_id')->nullable();
|
||||
});
|
||||
Schema::create('compra_items', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('compra_id');
|
||||
$table->foreignId('source_catalog_item_id');
|
||||
});
|
||||
|
||||
DB::table('events')->insert([['id' => 10], ['id' => 11]]);
|
||||
DB::table('compras')->insert([['id' => 20], ['id' => 21]]);
|
||||
DB::table('catalog_items')->insert([
|
||||
['id' => 30, 'event_id' => 10],
|
||||
['id' => 31, 'event_id' => 11],
|
||||
]);
|
||||
DB::table('compra_items')->insert([
|
||||
['compra_id' => 20, 'source_catalog_item_id' => 30],
|
||||
['compra_id' => 21, 'source_catalog_item_id' => 30],
|
||||
['compra_id' => 21, 'source_catalog_item_id' => 31],
|
||||
]);
|
||||
|
||||
$migration = require database_path('migrations/2026_09_28_000100_add_event_id_to_compras.php');
|
||||
$migration->up();
|
||||
|
||||
$this->assertDatabaseHas('compras', ['id' => 20, 'event_id' => 10]);
|
||||
$this->assertDatabaseHas('compras', ['id' => 21, 'event_id' => null]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Migrations;
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssignArrufoEventToPymeRuralClientTest extends TestCase
|
||||
{
|
||||
public function test_it_assigns_only_the_arrufo_event_to_pyme_rural(): void
|
||||
{
|
||||
Schema::create('clients', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('code');
|
||||
});
|
||||
Schema::create('events', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('client_id')->nullable();
|
||||
$table->string('tenant_code');
|
||||
$table->string('title');
|
||||
});
|
||||
|
||||
DB::table('clients')->insert([
|
||||
['id' => 10, 'code' => 'pyme_rural'],
|
||||
['id' => 11, 'code' => 'onticket'],
|
||||
]);
|
||||
DB::table('events')->insert([
|
||||
[
|
||||
'id' => 20,
|
||||
'client_id' => null,
|
||||
'tenant_code' => 'onticket',
|
||||
'title' => '26.º Fiesta de la Tradición y 4.º Encuentro de Agrupaciones Gauchas',
|
||||
],
|
||||
[
|
||||
'id' => 21,
|
||||
'client_id' => 11,
|
||||
'tenant_code' => 'onticket',
|
||||
'title' => 'Otro evento',
|
||||
],
|
||||
]);
|
||||
|
||||
$migration = require database_path('migrations/2026_09_28_000200_assign_arrufo_event_to_pyme_rural_client.php');
|
||||
$migration->up();
|
||||
|
||||
$this->assertDatabaseHas('events', ['id' => 20, 'client_id' => 10]);
|
||||
$this->assertDatabaseHas('events', ['id' => 21, 'client_id' => 11]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user