diff --git a/app/Domains/Purchase/Resources/PurchaseResource.php b/app/Domains/Purchase/Resources/PurchaseResource.php index 090b52f..5ccfa9b 100644 --- a/app/Domains/Purchase/Resources/PurchaseResource.php +++ b/app/Domains/Purchase/Resources/PurchaseResource.php @@ -21,15 +21,18 @@ class PurchaseResource extends JsonResource $purchaseItems = $this->resource->relationLoaded('items') ? $this->resource->getRelation('items') : collect(); - $cartItems = $purchaseItems->isEmpty() - && $this->resource->relationLoaded('cart') + $cartItems = $this->resource->relationLoaded('cart') && $this->resource->getRelation('cart')?->relationLoaded('items') ? $this->resource->getRelation('cart')->getRelation('items') - : collect(); - $items = $purchaseItems->isNotEmpty() ? $purchaseItems : $cartItems; - $itemsSource = $purchaseItems->isNotEmpty() - ? 'purchase' - : ($cartItems->isNotEmpty() ? 'cart' : null); + : null; + $usesCartItems = in_array($this->status, [ + Purchase::STATUS_CREATED, + Purchase::STATUS_PENDING_PAYMENT, + ], true) && $cartItems !== null; + $items = $usesCartItems ? $cartItems : $purchaseItems; + $itemsSource = $usesCartItems + ? 'cart' + : ($purchaseItems->isNotEmpty() ? 'purchase' : null); $ticketsCount = array_key_exists('tickets_count', $this->resource->getAttributes()) ? (int) $this->resource->getAttribute('tickets_count') : null; diff --git a/app/Domains/Purchase/Services/Checkout/PurchaseResponseLoader.php b/app/Domains/Purchase/Services/Checkout/PurchaseResponseLoader.php index 7739899..4e549a5 100644 --- a/app/Domains/Purchase/Services/Checkout/PurchaseResponseLoader.php +++ b/app/Domains/Purchase/Services/Checkout/PurchaseResponseLoader.php @@ -10,7 +10,16 @@ class PurchaseResponseLoader { $purchase->load(['tenant', 'items.imageAttachment']); - if ($purchase->items->isEmpty() && $purchase->cart_id !== null) { + if ( + $purchase->cart_id !== null + && ( + in_array($purchase->status, [ + Purchase::STATUS_CREATED, + Purchase::STATUS_PENDING_PAYMENT, + ], true) + || $purchase->items->isEmpty() + ) + ) { $purchase->load([ 'cart.items.catalogItem.inventory', 'cart.items.catalogItem.attachments', diff --git a/app/Domains/Sale/Services/AdminAppSaleService.php b/app/Domains/Sale/Services/AdminAppSaleService.php index 95fec11..e3c4de5 100644 --- a/app/Domains/Sale/Services/AdminAppSaleService.php +++ b/app/Domains/Sale/Services/AdminAppSaleService.php @@ -151,7 +151,18 @@ class AdminAppSaleService $filters['status'] ?? null, fn (Builder $query, string $status): Builder => $query->where('status', $status) ) - ->withSum('items as quantity', 'cantidad') + ->select('compras.*') + ->selectRaw( + 'CASE WHEN compras.status IN (?, ?) ' + .'THEN (SELECT COALESCE(SUM(cart_items.cantidad), 0) FROM carrito_items AS cart_items ' + .'WHERE cart_items.cart_id = compras.cart_id) ' + .'ELSE (SELECT COALESCE(SUM(purchase_items.cantidad), 0) FROM compra_items AS purchase_items ' + .'WHERE purchase_items.compra_id = compras.id) END AS quantity', + [ + Purchase::STATUS_CREATED, + Purchase::STATUS_PENDING_PAYMENT, + ], + ) ->withCount('tickets') ->orderBy($sortColumns[$sortBy], $sortDirection) ->when($sortBy !== 'id', fn (Builder $query): Builder => $query->orderByDesc('id')); diff --git a/tests/Feature/Purchase/StorePurchaseTest.php b/tests/Feature/Purchase/StorePurchaseTest.php index ac61311..1be38f0 100644 --- a/tests/Feature/Purchase/StorePurchaseTest.php +++ b/tests/Feature/Purchase/StorePurchaseTest.php @@ -1244,6 +1244,42 @@ class StorePurchaseTest extends TestCase ->assertJsonPath('data.total', '100.00'); } + public function test_created_and_pending_payment_purchase_details_use_the_current_cart_quantity(): void + { + $this->createTenant('sonder', 'Sonder', 'sonder.com.ar'); + $user = User::factory()->create([ + 'email' => 'buyer@example.com', + ]); + $variant = $this->createVariantForTenant('sonder', 10, '50.00'); + + foreach ([Purchase::STATUS_CREATED, Purchase::STATUS_PENDING_PAYMENT] as $status) { + $purchase = $this->createCheckoutPurchase($user, 'sonder', $variant, 2); + $purchase->items()->create([ + 'source_catalog_item_id' => $variant->catalog_item_id, + 'source_variant_id' => $variant->id, + 'item_nombre' => $variant->catalogItem->nombre, + 'descripcion' => $variant->catalogItem->descripcion, + 'slug' => $variant->catalogItem->slug, + 'variant_attributes' => [], + 'cantidad' => 1, + 'precio_unitario' => '50.00', + 'total' => '50.00', + ]); + $purchase->cart->items()->update(['cantidad' => 3]); + $purchase->update(['status' => $status]); + + $this->actingAs($user, 'sanctum') + ->getJson("/api/tenants/sonder/compras/{$purchase->id}") + ->assertOk() + ->assertJsonPath('data.status', $status) + ->assertJsonPath('data.items_source', 'cart') + ->assertJsonPath('data.items.0.quantity', 3) + ->assertJsonPath('data.items.0.line_total', '150.00') + ->assertJsonPath('data.subtotal', '150.00') + ->assertJsonPath('data.total', '150.00'); + } + } + public function test_purchase_detail_uses_purchase_items_for_paid_purchase_even_without_cart(): void { $this->createTenant('sonder', 'Sonder', 'sonder.com.ar'); diff --git a/tests/Feature/Sale/AdminAppSaleControllerTest.php b/tests/Feature/Sale/AdminAppSaleControllerTest.php index 5235e38..696ac80 100644 --- a/tests/Feature/Sale/AdminAppSaleControllerTest.php +++ b/tests/Feature/Sale/AdminAppSaleControllerTest.php @@ -31,6 +31,83 @@ class AdminAppSaleControllerTest extends TestCase WebsiteType::query()->create(['codigo' => 'onticket', 'nombre' => 'OnTicket']); } + public function test_sales_list_uses_cart_quantity_for_created_and_pending_payment_sales(): void + { + $tenant = $this->createTenant('acme'); + Sanctum::actingAs($this->createAdminAppUser($tenant)); + + $catalogItem = CatalogItem::query()->create([ + 'tenant_code' => $tenant->codigo, + 'slug' => 'entrada-general', + 'nombre' => 'Entrada general', + 'precio' => '10000.00', + ]); + + $createdCart = Cart::query()->create([ + 'tenant_codigo' => $tenant->codigo, + 'status' => 'checkout', + ]); + CartItem::query()->create([ + 'cart_id' => $createdCart->id, + 'catalog_item_id' => $catalogItem->id, + 'cantidad' => 3, + ]); + $createdPurchase = Purchase::query()->create([ + 'cart_id' => $createdCart->id, + 'tenant_codigo' => $tenant->codigo, + 'status' => Purchase::STATUS_CREATED, + 'total' => '30000.00', + ]); + PurchaseItem::query()->create([ + 'compra_id' => $createdPurchase->id, + 'source_catalog_item_id' => $catalogItem->id, + 'item_nombre' => $catalogItem->nombre, + 'cantidad' => 1, + 'precio_unitario' => '10000.00', + 'total' => '10000.00', + ]); + + $pendingCart = Cart::query()->create([ + 'tenant_codigo' => $tenant->codigo, + 'status' => 'checkout', + ]); + CartItem::query()->create([ + 'cart_id' => $pendingCart->id, + 'catalog_item_id' => $catalogItem->id, + 'cantidad' => 4, + ]); + $pendingPurchase = Purchase::query()->create([ + 'cart_id' => $pendingCart->id, + 'tenant_codigo' => $tenant->codigo, + 'status' => Purchase::STATUS_PENDING_PAYMENT, + 'total' => '40000.00', + ]); + + $paidPurchase = Purchase::query()->create([ + 'tenant_codigo' => $tenant->codigo, + 'status' => Purchase::STATUS_PAID, + 'total' => '20000.00', + ]); + PurchaseItem::query()->create([ + 'compra_id' => $paidPurchase->id, + 'source_catalog_item_id' => $catalogItem->id, + 'item_nombre' => $catalogItem->nombre, + 'cantidad' => 2, + 'precio_unitario' => '10000.00', + 'total' => '20000.00', + ]); + + $this->getJson('/api/v1/adminapp/tenant/sales?sort_by=id&sort_direction=asc') + ->assertOk() + ->assertJsonCount(3, 'data') + ->assertJsonPath('data.0.id', $createdPurchase->id) + ->assertJsonPath('data.0.quantity', 3) + ->assertJsonPath('data.1.id', $pendingPurchase->id) + ->assertJsonPath('data.1.quantity', 4) + ->assertJsonPath('data.2.id', $paidPurchase->id) + ->assertJsonPath('data.2.quantity', 2); + } + public function test_authentication_is_required_to_read_a_sale_detail(): void { $this->getJson('/api/v1/adminapp/tenant/sales/1')->assertUnauthorized();