Feat: Updating Product Indexer, and Product Sort
This commit is contained in:
@@ -14,6 +14,7 @@ enum ProductSort: string
|
|||||||
case PriceAsc = 'price_asc';
|
case PriceAsc = 'price_asc';
|
||||||
case PriceDesc = 'price_desc';
|
case PriceDesc = 'price_desc';
|
||||||
case Newest = 'newest';
|
case Newest = 'newest';
|
||||||
|
case Popularity = 'popularity';
|
||||||
|
|
||||||
public function toMeilisearchSort(): string
|
public function toMeilisearchSort(): string
|
||||||
{
|
{
|
||||||
@@ -21,6 +22,12 @@ enum ProductSort: string
|
|||||||
self::PriceAsc => 'price:asc',
|
self::PriceAsc => 'price:asc',
|
||||||
self::PriceDesc => 'price:desc',
|
self::PriceDesc => 'price:desc',
|
||||||
self::Newest => 'created_at:desc',
|
self::Newest => 'created_at:desc',
|
||||||
|
// order_count — see Modules\Core\Catalog\Services\
|
||||||
|
// ProductIndexer::toSearchableArray()'s own docblock: the same
|
||||||
|
// trailing-year, physical-order-line-count definition Lunar's
|
||||||
|
// own admin dashboard "Popular Products" widget already uses,
|
||||||
|
// aggregated per product rather than per variant.
|
||||||
|
self::Popularity => 'order_count:desc',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace Modules\Core\Catalog\Services;
|
|||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Lunar\Models\Currency;
|
use Lunar\Models\Currency;
|
||||||
|
use Lunar\Models\OrderLine;
|
||||||
use Lunar\Models\Price;
|
use Lunar\Models\Price;
|
||||||
use Lunar\Models\Product;
|
use Lunar\Models\Product;
|
||||||
use Lunar\Models\ProductVariant;
|
use Lunar\Models\ProductVariant;
|
||||||
@@ -103,6 +104,7 @@ class ProductIndexer extends BaseProductIndexer
|
|||||||
return [
|
return [
|
||||||
...parent::getSortableFields(),
|
...parent::getSortableFields(),
|
||||||
'price',
|
'price',
|
||||||
|
'order_count',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +163,24 @@ class ProductIndexer extends BaseProductIndexer
|
|||||||
$data['in_stock'] = $model->variants->contains(
|
$data['in_stock'] = $model->variants->contains(
|
||||||
fn (ProductVariant $variant) => $variant->canBeFulfilledAtQuantity(1)
|
fn (ProductVariant $variant) => $variant->canBeFulfilledAtQuantity(1)
|
||||||
);
|
);
|
||||||
|
// Same "popular" definition as Lunar's own admin dashboard widget
|
||||||
|
// (Lunar\Admin\Filament\Widgets\Dashboard\Orders\
|
||||||
|
// PopularProductsTable) — order-line COUNT, not summed quantity,
|
||||||
|
// over the trailing year, physical lines only — just aggregated
|
||||||
|
// per PRODUCT here (across all its variants) rather than per
|
||||||
|
// variant/identifier, since a storefront "sort by popularity"
|
||||||
|
// ranks products, not individual variant SKUs. Necessarily as
|
||||||
|
// stale as any other reindex-time field here (in_stock, price) —
|
||||||
|
// there's no live equivalent without a query per page load.
|
||||||
|
$data['order_count'] = OrderLine::query()
|
||||||
|
->whereIn('purchasable_id', $model->variants->pluck('id'))
|
||||||
|
->where('purchasable_type', 'product_variant')
|
||||||
|
->where('type', 'physical')
|
||||||
|
->whereHas('order', fn ($query) => $query->whereBetween('placed_at', [
|
||||||
|
now()->subYear()->startOfDay(),
|
||||||
|
now()->endOfDay(),
|
||||||
|
]))
|
||||||
|
->count();
|
||||||
$data['recommendations'] = app(RecommendationService::class)
|
$data['recommendations'] = app(RecommendationService::class)
|
||||||
->recommend($model)
|
->recommend($model)
|
||||||
->load(['media', 'variants.prices'])
|
->load(['media', 'variants.prices'])
|
||||||
|
|||||||
Reference in New Issue
Block a user