feat(catalog): expose product unavailability messages
This commit is contained in:
@@ -20,7 +20,6 @@ class CatalogFeaturedItemResource extends JsonResource
|
|||||||
$catalogItem = $this->resource;
|
$catalogItem = $this->resource;
|
||||||
/** @var FeaturedGroup $featuredGroup */
|
/** @var FeaturedGroup $featuredGroup */
|
||||||
$featuredGroup = $catalogItem->getRelation('featuredGroup');
|
$featuredGroup = $catalogItem->getRelation('featuredGroup');
|
||||||
$remainingUserQuota = $catalogItem->getAttribute('remaining_user_quota');
|
|
||||||
|
|
||||||
if ($featuredGroup->product_layout === ProductLayout::ColumnWithImage) {
|
if ($featuredGroup->product_layout === ProductLayout::ColumnWithImage) {
|
||||||
return $this->columnWithImageData($catalogItem);
|
return $this->columnWithImageData($catalogItem);
|
||||||
@@ -30,6 +29,9 @@ class CatalogFeaturedItemResource extends JsonResource
|
|||||||
return $this->ticketSelectorData($catalogItem);
|
return $this->ticketSelectorData($catalogItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$remainingUserQuota = $catalogItem->getAttribute('remaining_user_quota');
|
||||||
|
$availableStock = $catalogItem->availableStock();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'id' => $catalogItem->id,
|
'id' => $catalogItem->id,
|
||||||
'type' => $catalogItem->type->value,
|
'type' => $catalogItem->type->value,
|
||||||
@@ -37,26 +39,38 @@ class CatalogFeaturedItemResource extends JsonResource
|
|||||||
'descripcion' => $catalogItem->descripcion,
|
'descripcion' => $catalogItem->descripcion,
|
||||||
'precio' => $catalogItem->precio,
|
'precio' => $catalogItem->precio,
|
||||||
'maximum_addable_quantity' => $this->maximumAddable(
|
'maximum_addable_quantity' => $this->maximumAddable(
|
||||||
$catalogItem->availableStock(),
|
$availableStock,
|
||||||
$remainingUserQuota,
|
$remainingUserQuota,
|
||||||
),
|
),
|
||||||
'variants' => $catalogItem->visibleVariants()
|
'unavailable_message' => $this->unavailableMessage(
|
||||||
->map(fn (Variant $variant): array => [
|
$availableStock,
|
||||||
'id' => $variant->id,
|
$remainingUserQuota,
|
||||||
'event_date_id' => $variant->event_date_id,
|
),
|
||||||
'event_date' => $variant->eventDate?->date?->format('Y-m-d'),
|
'variants' => $catalogItem->variants
|
||||||
'event_date_ids' => $variant->selectedEventDates()->pluck('id')->values(),
|
->map(function (Variant $variant) use ($catalogItem, $remainingUserQuota): array {
|
||||||
'event_dates' => $variant->selectedEventDates()->map(fn ($eventDate): string => $eventDate->date->format('Y-m-d'))->values(),
|
$variantStock = $catalogItem->inventory_policy === InventoryPolicy::Unlimited
|
||||||
'descripcion' => $variant->getDescription(),
|
? null
|
||||||
'precio' => number_format($variant->getPrice(), 2, '.', ''),
|
: $variant->inventory->availableStock();
|
||||||
'maximum_addable_quantity' => $this->maximumAddable(
|
|
||||||
$catalogItem->inventory_policy === InventoryPolicy::Unlimited
|
return [
|
||||||
? null
|
'id' => $variant->id,
|
||||||
: $variant->inventory->availableStock(),
|
'event_date_id' => $variant->event_date_id,
|
||||||
$remainingUserQuota,
|
'event_date' => $variant->eventDate?->date?->format('Y-m-d'),
|
||||||
),
|
'event_date_ids' => $variant->selectedEventDates()->pluck('id')->values(),
|
||||||
'values' => $variant->selectorOptions($catalogItem->itemAttributes),
|
'event_dates' => $variant->selectedEventDates()->map(fn ($eventDate): string => $eventDate->date->format('Y-m-d'))->values(),
|
||||||
])
|
'descripcion' => $variant->getDescription(),
|
||||||
|
'precio' => number_format($variant->getPrice(), 2, '.', ''),
|
||||||
|
'maximum_addable_quantity' => $this->maximumAddable(
|
||||||
|
$variantStock,
|
||||||
|
$remainingUserQuota,
|
||||||
|
),
|
||||||
|
'unavailable_message' => $this->unavailableMessage(
|
||||||
|
$variantStock,
|
||||||
|
$remainingUserQuota,
|
||||||
|
),
|
||||||
|
'values' => $variant->selectorOptions($catalogItem->itemAttributes),
|
||||||
|
];
|
||||||
|
})
|
||||||
->values(),
|
->values(),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -66,6 +80,9 @@ class CatalogFeaturedItemResource extends JsonResource
|
|||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
private function ticketSelectorData(CatalogItem $catalogItem): array
|
private function ticketSelectorData(CatalogItem $catalogItem): array
|
||||||
{
|
{
|
||||||
|
$availableStock = $catalogItem->availableStock();
|
||||||
|
$remainingUserQuota = $catalogItem->getAttribute('remaining_user_quota');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $catalogItem->id,
|
'id' => $catalogItem->id,
|
||||||
'type' => $catalogItem->type->value,
|
'type' => $catalogItem->type->value,
|
||||||
@@ -73,18 +90,25 @@ class CatalogFeaturedItemResource extends JsonResource
|
|||||||
'descripcion' => $catalogItem->descripcion,
|
'descripcion' => $catalogItem->descripcion,
|
||||||
'precio' => $catalogItem->precio,
|
'precio' => $catalogItem->precio,
|
||||||
'image' => $this->firstImageUrl($catalogItem),
|
'image' => $this->firstImageUrl($catalogItem),
|
||||||
|
'maximum_addable_quantity' => $this->maximumAddable($availableStock, $remainingUserQuota),
|
||||||
|
'unavailable_message' => $this->unavailableMessage($availableStock, $remainingUserQuota),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
private function columnWithImageData(CatalogItem $catalogItem): array
|
private function columnWithImageData(CatalogItem $catalogItem): array
|
||||||
{
|
{
|
||||||
|
$availableStock = $catalogItem->availableStock();
|
||||||
|
$remainingUserQuota = $catalogItem->getAttribute('remaining_user_quota');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $catalogItem->id,
|
'id' => $catalogItem->id,
|
||||||
'type' => $catalogItem->type->value,
|
'type' => $catalogItem->type->value,
|
||||||
'nombre' => $catalogItem->nombre,
|
'nombre' => $catalogItem->nombre,
|
||||||
'precio' => $catalogItem->precio,
|
'precio' => $catalogItem->precio,
|
||||||
'image' => $this->firstImageUrl($catalogItem),
|
'image' => $this->firstImageUrl($catalogItem),
|
||||||
|
'maximum_addable_quantity' => $this->maximumAddable($availableStock, $remainingUserQuota),
|
||||||
|
'unavailable_message' => $this->unavailableMessage($availableStock, $remainingUserQuota),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,4 +127,10 @@ class CatalogFeaturedItemResource extends JsonResource
|
|||||||
return app(CatalogItemAllowanceService::class)
|
return app(CatalogItemAllowanceService::class)
|
||||||
->maximumAddableQuantity($stock, $remainingUserQuota);
|
->maximumAddableQuantity($stock, $remainingUserQuota);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function unavailableMessage(?int $stock, ?int $remainingUserQuota): ?string
|
||||||
|
{
|
||||||
|
return app(CatalogItemAllowanceService::class)
|
||||||
|
->unavailableMessage($stock, $remainingUserQuota);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,11 +42,15 @@ class CatalogItemDetailResource extends JsonResource
|
|||||||
$selectedVariant === null,
|
$selectedVariant === null,
|
||||||
fn () => $this->maximumAddable($this->availableStock()),
|
fn () => $this->maximumAddable($this->availableStock()),
|
||||||
),
|
),
|
||||||
|
'unavailable_message' => $this->when(
|
||||||
|
$selectedVariant === null,
|
||||||
|
fn () => $this->unavailableMessage($this->availableStock()),
|
||||||
|
),
|
||||||
'images' => $this->when(
|
'images' => $this->when(
|
||||||
$selectedVariant === null,
|
$selectedVariant === null,
|
||||||
fn () => $this->imageUrls($this->attachments),
|
fn () => $this->imageUrls($this->attachments),
|
||||||
),
|
),
|
||||||
'variants' => $this->visibleVariants()
|
'variants' => $this->variants
|
||||||
->map(fn (Variant $variant): array => $this->variantData($variant))
|
->map(fn (Variant $variant): array => $this->variantData($variant))
|
||||||
->values(),
|
->values(),
|
||||||
'selected_variant' => $this->when(
|
'selected_variant' => $this->when(
|
||||||
@@ -159,6 +163,7 @@ class CatalogItemDetailResource extends JsonResource
|
|||||||
{
|
{
|
||||||
$values = $variant->selectionOptions($this->itemAttributes);
|
$values = $variant->selectionOptions($this->itemAttributes);
|
||||||
$eventDates = $variant->selectedEventDates();
|
$eventDates = $variant->selectedEventDates();
|
||||||
|
$variantStock = $this->variantStock($variant);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $variant->id,
|
'id' => $variant->id,
|
||||||
@@ -168,7 +173,8 @@ class CatalogItemDetailResource extends JsonResource
|
|||||||
'event_dates' => $eventDates->map(fn ($eventDate): string => $eventDate->date->format('Y-m-d'))->values(),
|
'event_dates' => $eventDates->map(fn ($eventDate): string => $eventDate->date->format('Y-m-d'))->values(),
|
||||||
'descripcion' => $variant->getDescription(),
|
'descripcion' => $variant->getDescription(),
|
||||||
'precio' => number_format($variant->getPrice(), 2, '.', ''),
|
'precio' => number_format($variant->getPrice(), 2, '.', ''),
|
||||||
'maximum_addable_quantity' => $this->maximumAddable($this->variantStock($variant)),
|
'maximum_addable_quantity' => $this->maximumAddable($variantStock),
|
||||||
|
'unavailable_message' => $this->unavailableMessage($variantStock),
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -195,4 +201,12 @@ class CatalogItemDetailResource extends JsonResource
|
|||||||
$this->getAttribute('remaining_user_quota'),
|
$this->getAttribute('remaining_user_quota'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function unavailableMessage(?int $stock): ?string
|
||||||
|
{
|
||||||
|
return app(CatalogItemAllowanceService::class)->unavailableMessage(
|
||||||
|
$stock,
|
||||||
|
$this->getAttribute('remaining_user_quota'),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class CatalogSearchItemResource extends JsonResource
|
|||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
|
$availableStock = $this->availableStock();
|
||||||
$attachment = $this->attachments->first()
|
$attachment = $this->attachments->first()
|
||||||
?? $this->variants
|
?? $this->variants
|
||||||
->flatMap(fn (Variant $variant) => $variant->attachments)
|
->flatMap(fn (Variant $variant) => $variant->attachments)
|
||||||
@@ -27,23 +28,27 @@ class CatalogSearchItemResource extends JsonResource
|
|||||||
'descripcion' => $this->descripcion,
|
'descripcion' => $this->descripcion,
|
||||||
'precio' => $this->precio,
|
'precio' => $this->precio,
|
||||||
'image' => $attachment?->getTemporaryUrl(1440),
|
'image' => $attachment?->getTemporaryUrl(1440),
|
||||||
'maximum_addable_quantity' => $this->maximumAddable($this->availableStock()),
|
'maximum_addable_quantity' => $this->maximumAddable($availableStock),
|
||||||
'variants' => $this->visibleVariants()
|
'unavailable_message' => $this->unavailableMessage($availableStock),
|
||||||
->map(fn (Variant $variant): array => [
|
'variants' => $this->variants
|
||||||
'id' => $variant->id,
|
->map(function (Variant $variant): array {
|
||||||
'event_date_id' => $variant->event_date_id,
|
$variantStock = $this->inventory_policy === InventoryPolicy::Unlimited
|
||||||
'event_date' => $variant->eventDate?->date?->format('Y-m-d'),
|
? null
|
||||||
'event_date_ids' => $variant->selectedEventDates()->pluck('id')->values(),
|
: $variant->inventory?->availableStock();
|
||||||
'event_dates' => $variant->selectedEventDates()->map(fn ($eventDate): string => $eventDate->date->format('Y-m-d'))->values(),
|
|
||||||
'descripcion' => $variant->getDescription(),
|
return [
|
||||||
'precio' => number_format($variant->getPrice(), 2, '.', ''),
|
'id' => $variant->id,
|
||||||
'maximum_addable_quantity' => $this->maximumAddable(
|
'event_date_id' => $variant->event_date_id,
|
||||||
$this->inventory_policy === InventoryPolicy::Unlimited
|
'event_date' => $variant->eventDate?->date?->format('Y-m-d'),
|
||||||
? null
|
'event_date_ids' => $variant->selectedEventDates()->pluck('id')->values(),
|
||||||
: $variant->inventory?->availableStock(),
|
'event_dates' => $variant->selectedEventDates()->map(fn ($eventDate): string => $eventDate->date->format('Y-m-d'))->values(),
|
||||||
),
|
'descripcion' => $variant->getDescription(),
|
||||||
'values' => $variant->selectorOptions($this->itemAttributes),
|
'precio' => number_format($variant->getPrice(), 2, '.', ''),
|
||||||
])
|
'maximum_addable_quantity' => $this->maximumAddable($variantStock),
|
||||||
|
'unavailable_message' => $this->unavailableMessage($variantStock),
|
||||||
|
'values' => $variant->selectorOptions($this->itemAttributes),
|
||||||
|
];
|
||||||
|
})
|
||||||
->values(),
|
->values(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -55,4 +60,12 @@ class CatalogSearchItemResource extends JsonResource
|
|||||||
$this->getAttribute('remaining_user_quota'),
|
$this->getAttribute('remaining_user_quota'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function unavailableMessage(?int $stock): ?string
|
||||||
|
{
|
||||||
|
return app(CatalogItemAllowanceService::class)->unavailableMessage(
|
||||||
|
$stock,
|
||||||
|
$this->getAttribute('remaining_user_quota'),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ use Illuminate\Support\Collection;
|
|||||||
|
|
||||||
class CatalogItemAllowanceService
|
class CatalogItemAllowanceService
|
||||||
{
|
{
|
||||||
|
private const USER_QUOTA_REACHED_MESSAGE = 'Alcanzaste el cupo máximo permitido para este producto.';
|
||||||
|
|
||||||
|
private const OUT_OF_STOCK_MESSAGE = 'Este producto no tiene stock disponible.';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly UserPurchaseLimitService $purchaseLimits,
|
private readonly UserPurchaseLimitService $purchaseLimits,
|
||||||
) {}
|
) {}
|
||||||
@@ -37,4 +41,17 @@ class CatalogItemAllowanceService
|
|||||||
|
|
||||||
return min($availableStock, $remainingUserQuota);
|
return min($availableStock, $remainingUserQuota);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function unavailableMessage(?int $availableStock, ?int $remainingUserQuota): ?string
|
||||||
|
{
|
||||||
|
if ($remainingUserQuota !== null && $remainingUserQuota <= 0) {
|
||||||
|
return self::USER_QUOTA_REACHED_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($availableStock !== null && $availableStock <= 0) {
|
||||||
|
return self::OUT_OF_STOCK_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,7 +231,6 @@ class CatalogService
|
|||||||
|
|
||||||
$paginator = CatalogItem::query()
|
$paginator = CatalogItem::query()
|
||||||
->where('tenant_code', $tenant->codigo)
|
->where('tenant_code', $tenant->codigo)
|
||||||
->whereVariantsAvailable()
|
|
||||||
->where(function (Builder $query) use ($containsPattern): void {
|
->where(function (Builder $query) use ($containsPattern): void {
|
||||||
$query
|
$query
|
||||||
->whereRaw('LOWER(nombre) LIKE ?', [$containsPattern])
|
->whereRaw('LOWER(nombre) LIKE ?', [$containsPattern])
|
||||||
@@ -281,7 +280,6 @@ class CatalogService
|
|||||||
return CatalogItem::query()
|
return CatalogItem::query()
|
||||||
->where('tenant_code', $tenant->codigo)
|
->where('tenant_code', $tenant->codigo)
|
||||||
->where('category_id', $category->id)
|
->where('category_id', $category->id)
|
||||||
->whereVariantsAvailable()
|
|
||||||
->with([
|
->with([
|
||||||
'attachments',
|
'attachments',
|
||||||
'inventory',
|
'inventory',
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ class FeaturedGroupService
|
|||||||
{
|
{
|
||||||
$query = CatalogItem::query()
|
$query = CatalogItem::query()
|
||||||
->where('catalog_items.tenant_code', $featuredGroup->tenant_code)
|
->where('catalog_items.tenant_code', $featuredGroup->tenant_code)
|
||||||
->whereVariantsAvailable()
|
|
||||||
->with([
|
->with([
|
||||||
'inventory',
|
'inventory',
|
||||||
'attachments',
|
'attachments',
|
||||||
|
|||||||
@@ -73,10 +73,15 @@ class CatalogControllerTest extends TestCase
|
|||||||
->assertJsonPath('0.items.0.descripcion', 'Variants description')
|
->assertJsonPath('0.items.0.descripcion', 'Variants description')
|
||||||
->assertJsonPath('0.items.0.precio', '100.00')
|
->assertJsonPath('0.items.0.precio', '100.00')
|
||||||
->assertJsonPath('0.items.0.maximum_addable_quantity', 7)
|
->assertJsonPath('0.items.0.maximum_addable_quantity', 7)
|
||||||
->assertJsonCount(2, '0.items.0.variants')
|
->assertJsonCount(3, '0.items.0.variants')
|
||||||
->assertJsonPath('0.items.0.variants.0.maximum_addable_quantity', 4)
|
->assertJsonPath('0.items.0.variants.0.maximum_addable_quantity', 4)
|
||||||
->assertJsonPath('0.items.0.variants.1.maximum_addable_quantity', 3)
|
->assertJsonPath('0.items.0.variants.1.maximum_addable_quantity', 3)
|
||||||
->assertJsonMissing(['id' => $unavailableVariant->id])
|
->assertJsonPath('0.items.0.variants.2.id', $unavailableVariant->id)
|
||||||
|
->assertJsonPath('0.items.0.variants.2.maximum_addable_quantity', 0)
|
||||||
|
->assertJsonPath(
|
||||||
|
'0.items.0.variants.2.unavailable_message',
|
||||||
|
'Este producto no tiene stock disponible.',
|
||||||
|
)
|
||||||
->assertJsonPath('1.title', 'Row')
|
->assertJsonPath('1.title', 'Row')
|
||||||
->assertJsonPath('1.items.data.0.maximum_addable_quantity', 8)
|
->assertJsonPath('1.items.data.0.maximum_addable_quantity', 8)
|
||||||
->assertJsonMissingPath('1.items.data.0.stock_tecnico')
|
->assertJsonMissingPath('1.items.data.0.stock_tecnico')
|
||||||
@@ -94,7 +99,7 @@ class CatalogControllerTest extends TestCase
|
|||||||
);
|
);
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$item = $this->createItem($tenant, 'Limited variants');
|
$item = $this->createItem($tenant, 'Limited variants');
|
||||||
$item->update(['max_units_per_user' => 5]);
|
$item->update(['max_units_per_user' => 3]);
|
||||||
$firstVariant = $item->variants()->create([
|
$firstVariant = $item->variants()->create([
|
||||||
'inventory_id' => Inventory::query()->create(['real_stock' => 10])->id,
|
'inventory_id' => Inventory::query()->create(['real_stock' => 10])->id,
|
||||||
]);
|
]);
|
||||||
@@ -114,13 +119,21 @@ class CatalogControllerTest extends TestCase
|
|||||||
$this->actingAs($user, 'sanctum')
|
$this->actingAs($user, 'sanctum')
|
||||||
->getJson("/api/tenants/{$tenant->codigo}/catalog")
|
->getJson("/api/tenants/{$tenant->codigo}/catalog")
|
||||||
->assertOk()
|
->assertOk()
|
||||||
->assertJsonPath('0.items.0.variants.0.maximum_addable_quantity', 2)
|
->assertJsonPath('0.items.0.variants.0.maximum_addable_quantity', 0)
|
||||||
->assertJsonPath('0.items.0.variants.1.maximum_addable_quantity', 2)
|
->assertJsonPath('0.items.0.variants.1.maximum_addable_quantity', 0)
|
||||||
|
->assertJsonPath(
|
||||||
|
'0.items.0.variants.0.unavailable_message',
|
||||||
|
'Alcanzaste el cupo máximo permitido para este producto.',
|
||||||
|
)
|
||||||
|
->assertJsonPath(
|
||||||
|
'0.items.0.variants.1.unavailable_message',
|
||||||
|
'Alcanzaste el cupo máximo permitido para este producto.',
|
||||||
|
)
|
||||||
->assertJsonMissingPath('0.items.0.variants.0.stock_tecnico')
|
->assertJsonMissingPath('0.items.0.variants.0.stock_tecnico')
|
||||||
->assertJsonMissingPath('0.items.0.variants.1.stock_tecnico');
|
->assertJsonMissingPath('0.items.0.variants.1.stock_tecnico');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_it_excludes_items_when_all_of_their_variants_are_out_of_stock(): void
|
public function test_it_includes_out_of_stock_items_with_an_unavailable_message(): void
|
||||||
{
|
{
|
||||||
$tenant = $this->createTenant('catalog-available-variants');
|
$tenant = $this->createTenant('catalog-available-variants');
|
||||||
$group = $this->createGroup(
|
$group = $this->createGroup(
|
||||||
@@ -148,9 +161,15 @@ class CatalogControllerTest extends TestCase
|
|||||||
|
|
||||||
$this->getJson("/api/tenants/{$tenant->codigo}/catalog")
|
$this->getJson("/api/tenants/{$tenant->codigo}/catalog")
|
||||||
->assertOk()
|
->assertOk()
|
||||||
->assertJsonCount(1, '0.items')
|
->assertJsonCount(2, '0.items')
|
||||||
->assertJsonPath('0.items.0.nombre', 'Available')
|
->assertJsonPath('0.items.0.nombre', 'Unavailable')
|
||||||
->assertJsonMissing(['nombre' => 'Unavailable']);
|
->assertJsonPath('0.items.0.maximum_addable_quantity', 0)
|
||||||
|
->assertJsonPath(
|
||||||
|
'0.items.0.unavailable_message',
|
||||||
|
'Este producto no tiene stock disponible.',
|
||||||
|
)
|
||||||
|
->assertJsonPath('0.items.1.nombre', 'Available')
|
||||||
|
->assertJsonPath('0.items.1.unavailable_message', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_column_with_image_uses_item_image_then_variant_image_then_null(): void
|
public function test_column_with_image_uses_item_image_then_variant_image_then_null(): void
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class CatalogItemDetailControllerTest extends TestCase
|
|||||||
$this->assertStringContainsString($itemImage->path, $response->json('data.images.0'));
|
$this->assertStringContainsString($itemImage->path, $response->json('data.images.0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_it_filters_unavailable_variants_and_selects_the_first_available_one(): void
|
public function test_it_lists_unavailable_variants_and_selects_the_first_available_one(): void
|
||||||
{
|
{
|
||||||
Storage::fake('s3');
|
Storage::fake('s3');
|
||||||
$tenant = $this->createTenant('detail-default');
|
$tenant = $this->createTenant('detail-default');
|
||||||
@@ -69,8 +69,14 @@ class CatalogItemDetailControllerTest extends TestCase
|
|||||||
|
|
||||||
$response
|
$response
|
||||||
->assertOk()
|
->assertOk()
|
||||||
->assertJsonCount(1, 'data.variants')
|
->assertJsonCount(2, 'data.variants')
|
||||||
->assertJsonPath('data.variants.0.id', $secondVariant->id)
|
->assertJsonPath('data.variants.0.id', $firstVariant->id)
|
||||||
|
->assertJsonPath('data.variants.0.maximum_addable_quantity', 0)
|
||||||
|
->assertJsonPath(
|
||||||
|
'data.variants.0.unavailable_message',
|
||||||
|
'Este producto no tiene stock disponible.',
|
||||||
|
)
|
||||||
|
->assertJsonPath('data.variants.1.id', $secondVariant->id)
|
||||||
->assertJsonPath('data.selected_variant.id', $secondVariant->id)
|
->assertJsonPath('data.selected_variant.id', $secondVariant->id)
|
||||||
->assertJsonPath('data.selected_variant.maximum_addable_quantity', 6)
|
->assertJsonPath('data.selected_variant.maximum_addable_quantity', 6)
|
||||||
->assertJsonMissingPath('data.selected_variant.stock_tecnico')
|
->assertJsonMissingPath('data.selected_variant.stock_tecnico')
|
||||||
|
|||||||
43
tests/Unit/Catalog/CatalogItemAllowanceServiceTest.php
Normal file
43
tests/Unit/Catalog/CatalogItemAllowanceServiceTest.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit\Catalog;
|
||||||
|
|
||||||
|
use App\Domains\Catalog\Services\CatalogItemAllowanceService;
|
||||||
|
use ReflectionClass;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class CatalogItemAllowanceServiceTest extends TestCase
|
||||||
|
{
|
||||||
|
private CatalogItemAllowanceService $service;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->service = (new ReflectionClass(CatalogItemAllowanceService::class))
|
||||||
|
->newInstanceWithoutConstructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_it_returns_the_user_quota_message_with_priority_over_stock(): void
|
||||||
|
{
|
||||||
|
$this->assertSame(
|
||||||
|
'Alcanzaste el cupo máximo permitido para este producto.',
|
||||||
|
$this->service->unavailableMessage(0, 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_it_returns_the_out_of_stock_message(): void
|
||||||
|
{
|
||||||
|
$this->assertSame(
|
||||||
|
'Este producto no tiene stock disponible.',
|
||||||
|
$this->service->unavailableMessage(0, null),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_it_returns_no_message_when_the_item_is_available(): void
|
||||||
|
{
|
||||||
|
$this->assertNull($this->service->unavailableMessage(1, null));
|
||||||
|
$this->assertNull($this->service->unavailableMessage(null, 1));
|
||||||
|
$this->assertNull($this->service->unavailableMessage(null, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user