feat: add display_cart_item_images feature to tenants and update related resources
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Domains\Cart\Resources;
|
|||||||
|
|
||||||
use App\Domains\Cart\Models\CartItem;
|
use App\Domains\Cart\Models\CartItem;
|
||||||
use App\Domains\Catalog\Enums\InventoryPolicy;
|
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||||
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
@@ -19,12 +20,14 @@ class CartItemResource extends JsonResource
|
|||||||
{
|
{
|
||||||
$selectedItem = $this->selectedItem();
|
$selectedItem = $this->selectedItem();
|
||||||
$imageUrl = null;
|
$imageUrl = null;
|
||||||
|
$tenant = $request->route('tenant');
|
||||||
|
$displayImage = ! $tenant instanceof Tenant || $tenant->display_cart_item_images;
|
||||||
|
|
||||||
if ($selectedItem?->relationLoaded('attachments')) {
|
if ($displayImage && $selectedItem?->relationLoaded('attachments')) {
|
||||||
$imageUrl = $selectedItem->attachments->first()?->getTemporaryUrl(1440);
|
$imageUrl = $selectedItem->attachments->first()?->getTemporaryUrl(1440);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($imageUrl === null && $this->catalogItem?->relationLoaded('attachments')) {
|
if ($displayImage && $imageUrl === null && $this->catalogItem?->relationLoaded('attachments')) {
|
||||||
$imageUrl = $this->catalogItem->attachments->first()?->getTemporaryUrl(1440);
|
$imageUrl = $this->catalogItem->attachments->first()?->getTemporaryUrl(1440);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Domains\Cart\Models\CartItem;
|
|||||||
use App\Domains\Catalog\Models\CatalogItem;
|
use App\Domains\Catalog\Models\CatalogItem;
|
||||||
use App\Domains\Catalog\Models\Variant;
|
use App\Domains\Catalog\Models\Variant;
|
||||||
use App\Domains\Purchase\Models\PurchaseItem;
|
use App\Domains\Purchase\Models\PurchaseItem;
|
||||||
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
@@ -15,8 +16,13 @@ class PurchaseItemResource extends JsonResource
|
|||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
|
$tenant = $request->route('tenant');
|
||||||
|
$displayImage = ! $tenant instanceof Tenant || $tenant->display_cart_item_images;
|
||||||
|
|
||||||
if ($this->resource instanceof PurchaseItem) {
|
if ($this->resource instanceof PurchaseItem) {
|
||||||
$imageUrl = $this->imageAttachment?->getTemporaryUrl(1440);
|
$imageUrl = $displayImage
|
||||||
|
? $this->imageAttachment?->getTemporaryUrl(1440)
|
||||||
|
: null;
|
||||||
$attributes = $this->variant_attributes ?? [];
|
$attributes = $this->variant_attributes ?? [];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -42,7 +48,9 @@ class PurchaseItemResource extends JsonResource
|
|||||||
$quantity = (int) ($this->cantidad ?? 0);
|
$quantity = (int) ($this->cantidad ?? 0);
|
||||||
$unitPrice = $this->resolveUnitPrice($selectedItem);
|
$unitPrice = $this->resolveUnitPrice($selectedItem);
|
||||||
$lineTotal = $unitPrice * $quantity;
|
$lineTotal = $unitPrice * $quantity;
|
||||||
$imageUrl = $this->resolveImageUrl($selectedItem, $catalogItem);
|
$imageUrl = $displayImage
|
||||||
|
? $this->resolveImageUrl($selectedItem, $catalogItem)
|
||||||
|
: null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ use Illuminate\Support\Facades\Schema;
|
|||||||
'display_seach_bar',
|
'display_seach_bar',
|
||||||
'display_cart',
|
'display_cart',
|
||||||
'cart_editing_enabled',
|
'cart_editing_enabled',
|
||||||
|
'display_cart_item_images',
|
||||||
'scanner_category_validation_enabled',
|
'scanner_category_validation_enabled',
|
||||||
'event_title',
|
'event_title',
|
||||||
'event_location',
|
'event_location',
|
||||||
@@ -61,6 +62,7 @@ class Tenant extends Model
|
|||||||
'display_seach_bar' => true,
|
'display_seach_bar' => true,
|
||||||
'display_cart' => true,
|
'display_cart' => true,
|
||||||
'cart_editing_enabled' => true,
|
'cart_editing_enabled' => true,
|
||||||
|
'display_cart_item_images' => true,
|
||||||
'scanner_category_validation_enabled' => true,
|
'scanner_category_validation_enabled' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -111,6 +113,7 @@ class Tenant extends Model
|
|||||||
'display_seach_bar' => 'boolean',
|
'display_seach_bar' => 'boolean',
|
||||||
'display_cart' => 'boolean',
|
'display_cart' => 'boolean',
|
||||||
'cart_editing_enabled' => 'boolean',
|
'cart_editing_enabled' => 'boolean',
|
||||||
|
'display_cart_item_images' => 'boolean',
|
||||||
'scanner_category_validation_enabled' => 'boolean',
|
'scanner_category_validation_enabled' => 'boolean',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ class StoreTenantRequest extends FormRequest
|
|||||||
'display_seach_bar' => ['sometimes', 'boolean'],
|
'display_seach_bar' => ['sometimes', 'boolean'],
|
||||||
'display_cart' => ['sometimes', 'boolean'],
|
'display_cart' => ['sometimes', 'boolean'],
|
||||||
'cart_editing_enabled' => ['sometimes', 'boolean'],
|
'cart_editing_enabled' => ['sometimes', 'boolean'],
|
||||||
|
'display_cart_item_images' => ['sometimes', 'boolean'],
|
||||||
'scanner_category_validation_enabled' => ['sometimes', 'boolean'],
|
'scanner_category_validation_enabled' => ['sometimes', 'boolean'],
|
||||||
'website_type_code' => [
|
'website_type_code' => [
|
||||||
'required_with:extras',
|
'required_with:extras',
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ class UpdateTenantRequest extends FormRequest
|
|||||||
'display_seach_bar' => ['sometimes', 'boolean'],
|
'display_seach_bar' => ['sometimes', 'boolean'],
|
||||||
'display_cart' => ['sometimes', 'boolean'],
|
'display_cart' => ['sometimes', 'boolean'],
|
||||||
'cart_editing_enabled' => ['sometimes', 'boolean'],
|
'cart_editing_enabled' => ['sometimes', 'boolean'],
|
||||||
|
'display_cart_item_images' => ['sometimes', 'boolean'],
|
||||||
'scanner_category_validation_enabled' => ['sometimes', 'boolean'],
|
'scanner_category_validation_enabled' => ['sometimes', 'boolean'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class TenantResource extends JsonResource
|
|||||||
'display_seach_bar' => $this->display_seach_bar,
|
'display_seach_bar' => $this->display_seach_bar,
|
||||||
'display_cart' => $this->display_cart,
|
'display_cart' => $this->display_cart,
|
||||||
'cart_editing_enabled' => $this->cart_editing_enabled,
|
'cart_editing_enabled' => $this->cart_editing_enabled,
|
||||||
|
'display_cart_item_images' => $this->display_cart_item_images,
|
||||||
'scanner_category_validation_enabled' => $this->scanner_category_validation_enabled,
|
'scanner_category_validation_enabled' => $this->scanner_category_validation_enabled,
|
||||||
'social_media' => $this->whenLoaded(
|
'social_media' => $this->whenLoaded(
|
||||||
'socialMedia',
|
'socialMedia',
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
private const DESFILE_TENANT_CODE = 'desfile_pura_tendencia';
|
||||||
|
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('tenants', function (Blueprint $table): void {
|
||||||
|
$table->boolean('display_cart_item_images')->default(true)->after('cart_editing_enabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::table('tenants')
|
||||||
|
->where('codigo', self::DESFILE_TENANT_CODE)
|
||||||
|
->update(['display_cart_item_images' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('tenants', function (Blueprint $table): void {
|
||||||
|
$table->dropColumn('display_cart_item_images');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -43,6 +43,7 @@ class DesfilePuraTendenciaSeeder extends Seeder
|
|||||||
$tenant->update([
|
$tenant->update([
|
||||||
'client_id' => $client->id,
|
'client_id' => $client->id,
|
||||||
'cart_editing_enabled' => false,
|
'cart_editing_enabled' => false,
|
||||||
|
'display_cart_item_images' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -76,6 +77,7 @@ class DesfilePuraTendenciaSeeder extends Seeder
|
|||||||
'display_seach_bar' => false,
|
'display_seach_bar' => false,
|
||||||
'display_cart' => true,
|
'display_cart' => true,
|
||||||
'cart_editing_enabled' => false,
|
'cart_editing_enabled' => false,
|
||||||
|
'display_cart_item_images' => false,
|
||||||
'scanner_category_validation_enabled' => false,
|
'scanner_category_validation_enabled' => false,
|
||||||
'website_type_code' => 'onticket',
|
'website_type_code' => 'onticket',
|
||||||
'header_logo' => $this->uploadedImage(
|
'header_logo' => $this->uploadedImage(
|
||||||
|
|||||||
@@ -75,6 +75,21 @@ class CartControllerTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_it_filters_item_images_when_the_tenant_disables_them(): void
|
||||||
|
{
|
||||||
|
$tenant = $this->createTenant('acme');
|
||||||
|
$tenant->update(['display_cart_item_images' => false]);
|
||||||
|
$item = $this->createDirectItem($tenant, 10, '49.90');
|
||||||
|
$item->attachments()->attach($this->createAttachment('cart-item'), ['orden' => 0]);
|
||||||
|
|
||||||
|
$this->postJson('/api/tenants/acme/cart/items', [
|
||||||
|
'catalog_item_id' => $item->id,
|
||||||
|
'cantidad' => 1,
|
||||||
|
])
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('data.items.0.imagen', null);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_it_adds_a_specific_variant_and_merges_repeated_additions(): void
|
public function test_it_adds_a_specific_variant_and_merges_repeated_additions(): void
|
||||||
{
|
{
|
||||||
$tenant = $this->createTenant('acme');
|
$tenant = $this->createTenant('acme');
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature\Migrations;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class AddDisplayCartItemImagesToTenantsTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
public function test_it_hides_cart_item_images_only_for_desfile(): void
|
||||||
|
{
|
||||||
|
$migration = require database_path(
|
||||||
|
'migrations/2026_08_18_061000_add_display_cart_item_images_to_tenants_table.php'
|
||||||
|
);
|
||||||
|
|
||||||
|
$migration->down();
|
||||||
|
$migration->up();
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('tenants', [
|
||||||
|
'codigo' => 'desfile_pura_tendencia',
|
||||||
|
'display_cart_item_images' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::table('tenants')->insert([
|
||||||
|
'codigo' => 'cart-images-default',
|
||||||
|
'nombre' => 'Cart images default',
|
||||||
|
'dominio' => 'cart-images-default.test',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('tenants', [
|
||||||
|
'codigo' => 'cart-images-default',
|
||||||
|
'display_cart_item_images' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -847,6 +847,30 @@ class StorePurchaseTest extends TestCase
|
|||||||
->assertJsonPath('data.total', '100.00');
|
->assertJsonPath('data.total', '100.00');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_purchase_detail_filters_item_images_when_the_tenant_disables_them(): void
|
||||||
|
{
|
||||||
|
$tenant = $this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
|
$tenant->update(['display_cart_item_images' => false]);
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'buyer@example.com',
|
||||||
|
]);
|
||||||
|
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||||
|
$purchase = $this->createCheckoutPurchase($user, 'sonder', $variant, 2);
|
||||||
|
$image = Attachment::create([
|
||||||
|
'key' => (string) Str::uuid(),
|
||||||
|
'path' => 'catalog/purchase-item.png',
|
||||||
|
'filename' => 'purchase-item.png',
|
||||||
|
'type' => AttachmentType::Image,
|
||||||
|
'mime_type' => 'image/png',
|
||||||
|
]);
|
||||||
|
$purchase->items()->firstOrFail()->update(['image_attachment_id' => $image->id]);
|
||||||
|
|
||||||
|
$this->actingAs($user, 'sanctum')
|
||||||
|
->getJson("/api/tenants/sonder/compras/{$purchase->id}")
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('data.items.0.item_details.imagen', null);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_purchase_detail_uses_purchase_items_for_pending_payment_purchase(): void
|
public function test_purchase_detail_uses_purchase_items_for_pending_payment_purchase(): void
|
||||||
{
|
{
|
||||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class DesfilePuraTendenciaSeederTest extends TestCase
|
|||||||
'display_categories' => false,
|
'display_categories' => false,
|
||||||
'display_seach_bar' => false,
|
'display_seach_bar' => false,
|
||||||
'cart_editing_enabled' => false,
|
'cart_editing_enabled' => false,
|
||||||
|
'display_cart_item_images' => false,
|
||||||
'site_title' => 'Desfile Pura Tendencia',
|
'site_title' => 'Desfile Pura Tendencia',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class BootstrapTenantControllerTest extends TestCase
|
|||||||
'display_seach_bar' => false,
|
'display_seach_bar' => false,
|
||||||
'display_cart' => false,
|
'display_cart' => false,
|
||||||
'cart_editing_enabled' => false,
|
'cart_editing_enabled' => false,
|
||||||
|
'display_cart_item_images' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->getJson('/api/tenants/bootstrap?dominio=acme.com&path=%2F');
|
$response = $this->getJson('/api/tenants/bootstrap?dominio=acme.com&path=%2F');
|
||||||
@@ -91,6 +92,7 @@ class BootstrapTenantControllerTest extends TestCase
|
|||||||
->assertJsonPath('data.display_seach_bar', false)
|
->assertJsonPath('data.display_seach_bar', false)
|
||||||
->assertJsonPath('data.display_cart', false)
|
->assertJsonPath('data.display_cart', false)
|
||||||
->assertJsonPath('data.cart_editing_enabled', false)
|
->assertJsonPath('data.cart_editing_enabled', false)
|
||||||
|
->assertJsonPath('data.display_cart_item_images', false)
|
||||||
->assertJsonPath('data.header_bg_color', '#ffffff')->assertJsonPath('data.footer_bg_color', '#ffffff');
|
->assertJsonPath('data.header_bg_color', '#ffffff')->assertJsonPath('data.footer_bg_color', '#ffffff');
|
||||||
|
|
||||||
$headerUrl = $response->json('data.header_logo');
|
$headerUrl = $response->json('data.header_logo');
|
||||||
@@ -748,6 +750,7 @@ class BootstrapTenantControllerTest extends TestCase
|
|||||||
$response = $this->putJson("/api/tenants/{$tenant->codigo}", [
|
$response = $this->putJson("/api/tenants/{$tenant->codigo}", [
|
||||||
'primary_color' => '#000000',
|
'primary_color' => '#000000',
|
||||||
'cart_editing_enabled' => false,
|
'cart_editing_enabled' => false,
|
||||||
|
'display_cart_item_images' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response
|
$response
|
||||||
@@ -755,7 +758,8 @@ class BootstrapTenantControllerTest extends TestCase
|
|||||||
->assertJsonPath('data.codigo', 'acme')
|
->assertJsonPath('data.codigo', 'acme')
|
||||||
->assertJsonPath('data.nombre', 'Acme')
|
->assertJsonPath('data.nombre', 'Acme')
|
||||||
->assertJsonPath('data.primary_color', '#000000')
|
->assertJsonPath('data.primary_color', '#000000')
|
||||||
->assertJsonPath('data.cart_editing_enabled', false);
|
->assertJsonPath('data.cart_editing_enabled', false)
|
||||||
|
->assertJsonPath('data.display_cart_item_images', false);
|
||||||
|
|
||||||
$this->assertDatabaseHas('tenants', [
|
$this->assertDatabaseHas('tenants', [
|
||||||
'id' => $tenant->id,
|
'id' => $tenant->id,
|
||||||
@@ -763,6 +767,7 @@ class BootstrapTenantControllerTest extends TestCase
|
|||||||
'nombre' => 'Acme',
|
'nombre' => 'Acme',
|
||||||
'primary_color' => '#000000',
|
'primary_color' => '#000000',
|
||||||
'cart_editing_enabled' => false,
|
'cart_editing_enabled' => false,
|
||||||
|
'display_cart_item_images' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user