feat: enhance purchase detail handling to support cart items and improve resource structure
This commit is contained in:
@@ -7,6 +7,7 @@ use App\Domains\Cart\Models\Cart;
|
||||
use App\Domains\Catalog\Models\Product;
|
||||
use App\Domains\Catalog\Models\ProductVariant;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use App\Domains\Purchase\Services\CheckoutService;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
@@ -76,6 +77,7 @@ class StorePurchaseTest extends TestCase
|
||||
$response->assertJsonPath('data.email', 'juan.perez@example.com');
|
||||
$response->assertJsonPath('data.tenant_codigo', 'sonder');
|
||||
$response->assertJsonPath('data.status', Purchase::STATUS_CREATED);
|
||||
$response->assertJsonPath('data.items_source', null);
|
||||
$response->assertJsonPath('data.items', []);
|
||||
$response->assertJsonPath('data.subtotal', '100.00');
|
||||
$response->assertJsonPath('data.total', '100.00');
|
||||
@@ -159,6 +161,150 @@ class StorePurchaseTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_purchase_detail_uses_cart_items_for_created_purchase(): void
|
||||
{
|
||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||
$user = User::factory()->create([
|
||||
'email' => 'buyer@example.com',
|
||||
]);
|
||||
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||
$purchase = $this->createCheckoutPurchase($user, 'sonder', $variant, 2);
|
||||
|
||||
$this->actingAs($user, 'sanctum')
|
||||
->getJson("/api/tenants/sonder/compras/{$purchase->id}")
|
||||
->assertOk()
|
||||
->assertJsonPath('data.status', Purchase::STATUS_CREATED)
|
||||
->assertJsonPath('data.items_source', 'cart')
|
||||
->assertJsonCount(1, 'data.items')
|
||||
->assertJsonPath('data.items.0.quantity', 2)
|
||||
->assertJsonPath('data.items.0.unit_price', '50.00')
|
||||
->assertJsonPath('data.items.0.line_total', '100.00')
|
||||
->assertJsonPath('data.items.0.product.id', $variant->product->id)
|
||||
->assertJsonPath('data.items.0.product.nombre', $variant->product->nombre)
|
||||
->assertJsonPath('data.items.0.product.slug', $variant->product->slug)
|
||||
->assertJsonPath('data.items.0.product.imagen', null)
|
||||
->assertJsonPath('data.items.0.variant.id', $variant->id)
|
||||
->assertJsonPath('data.items.0.variant.attributes', [])
|
||||
->assertJsonPath('data.subtotal', '100.00')
|
||||
->assertJsonPath('data.total', '100.00');
|
||||
}
|
||||
|
||||
public function test_purchase_detail_uses_cart_items_for_pending_payment_purchase(): void
|
||||
{
|
||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||
$user = User::factory()->create([
|
||||
'email' => 'buyer@example.com',
|
||||
]);
|
||||
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||
$purchase = $this->createCheckoutPurchase($user, 'sonder', $variant, 2);
|
||||
|
||||
$purchase->update([
|
||||
'payment_method' => 'transfer',
|
||||
]);
|
||||
|
||||
app(CheckoutService::class)->completePurchase($purchase);
|
||||
|
||||
$this->actingAs($user, 'sanctum')
|
||||
->getJson("/api/tenants/sonder/compras/{$purchase->id}")
|
||||
->assertOk()
|
||||
->assertJsonPath('data.status', Purchase::STATUS_PENDING_PAYMENT)
|
||||
->assertJsonPath('data.items_source', 'cart')
|
||||
->assertJsonCount(1, 'data.items')
|
||||
->assertJsonPath('data.items.0.quantity', 2)
|
||||
->assertJsonPath('data.items.0.unit_price', '50.00')
|
||||
->assertJsonPath('data.items.0.line_total', '100.00')
|
||||
->assertJsonPath('data.items.0.product.imagen', null)
|
||||
->assertJsonPath('data.items.0.variant.attributes', [])
|
||||
->assertJsonPath('data.subtotal', '100.00')
|
||||
->assertJsonPath('data.total', '100.00');
|
||||
}
|
||||
|
||||
public function test_purchase_detail_uses_purchase_items_for_paid_purchase_even_without_cart(): void
|
||||
{
|
||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||
$user = User::factory()->create([
|
||||
'email' => 'buyer@example.com',
|
||||
]);
|
||||
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||
$purchase = $this->createCheckoutPurchase($user, 'sonder', $variant, 2);
|
||||
|
||||
$purchase->update([
|
||||
'payment_method' => 'transfer',
|
||||
]);
|
||||
|
||||
$checkoutService = app(CheckoutService::class);
|
||||
$purchase = $checkoutService->completePurchase($purchase);
|
||||
$checkoutService->confirmPurchase($purchase);
|
||||
$purchase->refresh()->markAsPaid();
|
||||
|
||||
$this->assertSoftDeleted('carritos', [
|
||||
'id' => $purchase->cart_id,
|
||||
]);
|
||||
|
||||
$this->actingAs($user, 'sanctum')
|
||||
->getJson("/api/tenants/sonder/compras/{$purchase->id}")
|
||||
->assertOk()
|
||||
->assertJsonPath('data.status', Purchase::STATUS_PAID)
|
||||
->assertJsonPath('data.items_source', 'purchase')
|
||||
->assertJsonCount(1, 'data.items')
|
||||
->assertJsonPath('data.items.0.quantity', 2)
|
||||
->assertJsonPath('data.items.0.unit_price', '50.00')
|
||||
->assertJsonPath('data.items.0.line_total', '100.00')
|
||||
->assertJsonPath('data.items.0.product.id', $variant->product->id)
|
||||
->assertJsonPath('data.items.0.product.imagen', null)
|
||||
->assertJsonPath('data.items.0.variant.id', $variant->id)
|
||||
->assertJsonPath('data.items.0.variant.attributes', [])
|
||||
->assertJsonPath('data.subtotal', '100.00')
|
||||
->assertJsonPath('data.total', '100.00');
|
||||
}
|
||||
|
||||
public function test_purchase_detail_prefers_purchase_items_when_both_sources_exist(): void
|
||||
{
|
||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||
$user = User::factory()->create([
|
||||
'email' => 'buyer@example.com',
|
||||
]);
|
||||
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||
$purchase = $this->createCheckoutPurchase($user, 'sonder', $variant, 2);
|
||||
|
||||
$purchase->items()->create([
|
||||
'producto_variante_id' => $variant->id,
|
||||
'cantidad' => 1,
|
||||
'precio_unitario' => '50.00',
|
||||
'discount_total' => null,
|
||||
'tax_total' => null,
|
||||
'total' => '50.00',
|
||||
]);
|
||||
|
||||
$this->actingAs($user, 'sanctum')
|
||||
->getJson("/api/tenants/sonder/compras/{$purchase->id}")
|
||||
->assertOk()
|
||||
->assertJsonPath('data.items_source', 'purchase')
|
||||
->assertJsonCount(1, 'data.items')
|
||||
->assertJsonPath('data.items.0.quantity', 1)
|
||||
->assertJsonPath('data.items.0.line_total', '50.00')
|
||||
->assertJsonPath('data.subtotal', '50.00')
|
||||
->assertJsonPath('data.total', '50.00');
|
||||
}
|
||||
|
||||
public function test_purchase_index_returns_empty_items_without_loaded_relations(): void
|
||||
{
|
||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||
$user = User::factory()->create([
|
||||
'email' => 'buyer@example.com',
|
||||
]);
|
||||
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||
$this->createCheckoutPurchase($user, 'sonder', $variant, 2);
|
||||
|
||||
$this->actingAs($user, 'sanctum')
|
||||
->getJson('/api/tenants/sonder/compras?status=created')
|
||||
->assertOk()
|
||||
->assertJsonCount(1, 'data')
|
||||
->assertJsonPath('data.0.items_source', null)
|
||||
->assertJsonPath('data.0.items', [])
|
||||
->assertJsonPath('data.0.total', '100.00');
|
||||
}
|
||||
|
||||
public function test_it_rejects_a_cart_from_another_user(): void
|
||||
{
|
||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||
@@ -290,6 +436,30 @@ class StorePurchaseTest extends TestCase
|
||||
])->load('product');
|
||||
}
|
||||
|
||||
protected function createCheckoutPurchase(
|
||||
User $user,
|
||||
string $tenantCode,
|
||||
ProductVariant $variant,
|
||||
int $quantity,
|
||||
): Purchase {
|
||||
$tenant = Tenant::query()->where('codigo', $tenantCode)->firstOrFail();
|
||||
$cart = Cart::query()->create([
|
||||
'tenant_codigo' => $tenantCode,
|
||||
'user_id' => $user->id,
|
||||
'status' => 'active',
|
||||
]);
|
||||
|
||||
$cart->addItem($variant->id, $quantity);
|
||||
|
||||
return app(CheckoutService::class)->startCheckout($tenant, $user->id, [
|
||||
'cart_id' => $cart->id,
|
||||
'dni' => '987654321',
|
||||
'telefono' => '+54 9 341 555-4321',
|
||||
'nombre_apellido' => 'Juan Perez',
|
||||
'email' => 'juan.perez@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function createTenant(string $codigo, string $nombre, string $dominio): Tenant
|
||||
{
|
||||
$hdrKey = (string) \Illuminate\Support\Str::uuid();
|
||||
|
||||
Reference in New Issue
Block a user