feat: Add event association to purchases; implement event relationship in models, update migration, and enhance tests
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Domains\Event\Models;
|
namespace App\Domains\Event\Models;
|
||||||
|
|
||||||
use App\Domains\Catalog\Models\CatalogItem;
|
use App\Domains\Catalog\Models\CatalogItem;
|
||||||
|
use App\Domains\Purchase\Models\Purchase;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
@@ -38,4 +39,10 @@ class Event extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany(CatalogItem::class);
|
return $this->hasMany(CatalogItem::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return HasMany<Purchase, $this> */
|
||||||
|
public function purchases(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Purchase::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Domains\Purchase\Models;
|
|||||||
|
|
||||||
use App\Domains\Auth\Models\User;
|
use App\Domains\Auth\Models\User;
|
||||||
use App\Domains\Cart\Models\Cart;
|
use App\Domains\Cart\Models\Cart;
|
||||||
|
use App\Domains\Event\Models\Event;
|
||||||
use App\Domains\Logging\Models\Concerns\LogsValueChanges;
|
use App\Domains\Logging\Models\Concerns\LogsValueChanges;
|
||||||
use App\Domains\Purchase\Events\PurchasePaid;
|
use App\Domains\Purchase\Events\PurchasePaid;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
@@ -19,6 +20,7 @@ use Illuminate\Support\Facades\DB;
|
|||||||
#[Fillable([
|
#[Fillable([
|
||||||
'cart_id',
|
'cart_id',
|
||||||
'tenant_codigo',
|
'tenant_codigo',
|
||||||
|
'event_id',
|
||||||
'user_id',
|
'user_id',
|
||||||
'status',
|
'status',
|
||||||
'payment_method',
|
'payment_method',
|
||||||
@@ -70,6 +72,7 @@ class Purchase extends Model
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'cart_id' => 'integer',
|
'cart_id' => 'integer',
|
||||||
|
'event_id' => 'integer',
|
||||||
'user_id' => 'integer',
|
'user_id' => 'integer',
|
||||||
'expires_at' => 'datetime',
|
'expires_at' => 'datetime',
|
||||||
'total' => 'decimal:2',
|
'total' => 'decimal:2',
|
||||||
@@ -84,6 +87,12 @@ class Purchase extends Model
|
|||||||
return $this->belongsTo(Tenant::class, 'tenant_codigo', 'codigo');
|
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>
|
* @return BelongsTo<User, $this>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class PurchaseResource extends JsonResource
|
|||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'cart_id' => $this->cart_id,
|
'cart_id' => $this->cart_id,
|
||||||
'tenant_codigo' => $this->tenant_codigo,
|
'tenant_codigo' => $this->tenant_codigo,
|
||||||
|
'event_id' => $this->event_id,
|
||||||
'user_id' => $this->user_id,
|
'user_id' => $this->user_id,
|
||||||
'created_at' => $this->created_at,
|
'created_at' => $this->created_at,
|
||||||
'status' => $this->status,
|
'status' => $this->status,
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ class CheckoutService
|
|||||||
public function startCheckout(Tenant $tenant, int $userId, array $purchaseData): Purchase
|
public function startCheckout(Tenant $tenant, int $userId, array $purchaseData): Purchase
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($tenant, $userId, $purchaseData): Purchase {
|
return DB::transaction(function () use ($tenant, $userId, $purchaseData): Purchase {
|
||||||
|
/** @var Tenant $tenant */
|
||||||
|
$tenant = Tenant::query()
|
||||||
|
->lockForUpdate()
|
||||||
|
->findOrFail($tenant->getKey());
|
||||||
|
|
||||||
$directItem = $purchaseData['direct_item'] ?? null;
|
$directItem = $purchaseData['direct_item'] ?? null;
|
||||||
$cartId = isset($purchaseData['cart_id']) ? (int) $purchaseData['cart_id'] : null;
|
$cartId = isset($purchaseData['cart_id']) ? (int) $purchaseData['cart_id'] : null;
|
||||||
unset($purchaseData['direct_item'], $purchaseData['cart_id']);
|
unset($purchaseData['direct_item'], $purchaseData['cart_id']);
|
||||||
@@ -615,6 +620,7 @@ class CheckoutService
|
|||||||
...$purchaseData,
|
...$purchaseData,
|
||||||
'cart_id' => $cartId,
|
'cart_id' => $cartId,
|
||||||
'tenant_codigo' => $tenant->codigo,
|
'tenant_codigo' => $tenant->codigo,
|
||||||
|
'event_id' => $tenant->active_event_id,
|
||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
'status' => Purchase::STATUS_CREATED,
|
'status' => Purchase::STATUS_CREATED,
|
||||||
'payment_method' => null,
|
'payment_method' => null,
|
||||||
|
|||||||
@@ -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('compras', function (Blueprint $table): void {
|
||||||
|
$table->foreignId('event_id')
|
||||||
|
->nullable()
|
||||||
|
->after('tenant_codigo')
|
||||||
|
->constrained('events')
|
||||||
|
->nullOnDelete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('compras', function (Blueprint $table): void {
|
||||||
|
$table->dropConstrainedForeignId('event_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -11,6 +11,7 @@ use App\Domains\Catalog\Models\CatalogItem;
|
|||||||
use App\Domains\Catalog\Models\Category;
|
use App\Domains\Catalog\Models\Category;
|
||||||
use App\Domains\Catalog\Models\Inventory;
|
use App\Domains\Catalog\Models\Inventory;
|
||||||
use App\Domains\Catalog\Models\Variant;
|
use App\Domains\Catalog\Models\Variant;
|
||||||
|
use App\Domains\Event\Models\Event;
|
||||||
use App\Domains\Purchase\Models\Purchase;
|
use App\Domains\Purchase\Models\Purchase;
|
||||||
use App\Domains\Purchase\Services\CheckoutService;
|
use App\Domains\Purchase\Services\CheckoutService;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
@@ -33,6 +34,12 @@ class StorePurchaseTest extends TestCase
|
|||||||
public function test_it_creates_an_independent_purchase_snapshot_from_cart(): void
|
public function test_it_creates_an_independent_purchase_snapshot_from_cart(): void
|
||||||
{
|
{
|
||||||
$tenant = $this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
$tenant = $this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
|
$event = Event::query()->create([
|
||||||
|
'tenant_code' => $tenant->codigo,
|
||||||
|
'name' => 'Sonder Fest',
|
||||||
|
'address' => 'Test address',
|
||||||
|
]);
|
||||||
|
$tenant->update(['active_event_id' => $event->id]);
|
||||||
$user = User::factory()->create([
|
$user = User::factory()->create([
|
||||||
'email' => 'buyer@example.com',
|
'email' => 'buyer@example.com',
|
||||||
]);
|
]);
|
||||||
@@ -85,6 +92,7 @@ class StorePurchaseTest extends TestCase
|
|||||||
$response->assertJsonPath('data.nombre_apellido', null);
|
$response->assertJsonPath('data.nombre_apellido', null);
|
||||||
$response->assertJsonPath('data.email', null);
|
$response->assertJsonPath('data.email', null);
|
||||||
$response->assertJsonPath('data.tenant_codigo', 'sonder');
|
$response->assertJsonPath('data.tenant_codigo', 'sonder');
|
||||||
|
$response->assertJsonPath('data.event_id', $event->id);
|
||||||
$response->assertJsonPath('data.status', Purchase::STATUS_CREATED);
|
$response->assertJsonPath('data.status', Purchase::STATUS_CREATED);
|
||||||
$response->assertJsonPath('data.items_source', 'purchase');
|
$response->assertJsonPath('data.items_source', 'purchase');
|
||||||
$response->assertJsonCount(1, 'data.items');
|
$response->assertJsonCount(1, 'data.items');
|
||||||
@@ -97,6 +105,7 @@ class StorePurchaseTest extends TestCase
|
|||||||
'id' => $purchaseId,
|
'id' => $purchaseId,
|
||||||
'cart_id' => $cartId,
|
'cart_id' => $cartId,
|
||||||
'tenant_codigo' => 'sonder',
|
'tenant_codigo' => 'sonder',
|
||||||
|
'event_id' => $event->id,
|
||||||
'user_id' => $user->id,
|
'user_id' => $user->id,
|
||||||
'dni' => null,
|
'dni' => null,
|
||||||
'telefono' => null,
|
'telefono' => null,
|
||||||
|
|||||||
25
tests/Unit/Forms/SaleFormServiceTest.php
Normal file
25
tests/Unit/Forms/SaleFormServiceTest.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit\Forms;
|
||||||
|
|
||||||
|
use App\Domains\Forms\Services\SaleFormService;
|
||||||
|
use App\Domains\Purchase\Models\Purchase;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class SaleFormServiceTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_it_returns_every_purchase_status_as_a_form_option(): void
|
||||||
|
{
|
||||||
|
$form = (new SaleFormService)->get();
|
||||||
|
|
||||||
|
$this->assertSame(Purchase::statuses(), array_column($form['statuses'], 'code'));
|
||||||
|
$this->assertSame([
|
||||||
|
'Creada',
|
||||||
|
'Esperando pago',
|
||||||
|
'Confirmada',
|
||||||
|
'Cancelada',
|
||||||
|
'Rechazada',
|
||||||
|
'Vencida',
|
||||||
|
], array_column($form['statuses'], 'name'));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user