121 lines
4.5 KiB
PHP
121 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Manage;
|
|
|
|
use App\Enums\PriceType;
|
|
use App\Models\CuttingResultPrice;
|
|
use App\Models\ProductPrice;
|
|
use App\Services\Concerns\CachesQuery;
|
|
use Illuminate\Support\Collection;
|
|
|
|
class CuttingResultPriceResolver
|
|
{
|
|
use CachesQuery;
|
|
|
|
public function resolve(int $productVariantId, PriceType $priceType): ?CuttingResultPrice
|
|
{
|
|
$price = CuttingResultPrice::query()
|
|
->where('product_variant_id', $productVariantId)
|
|
->where('price_type', $priceType)
|
|
->whereHas('cutting', fn ($query) => $query->verified())
|
|
->join('cuttings', 'cutting_result_prices.cutting_id', '=', 'cuttings.id')
|
|
->orderByDesc('cuttings.created_at')
|
|
->select('cutting_result_prices.*')
|
|
->first();
|
|
|
|
if ($price !== null) {
|
|
return $price;
|
|
}
|
|
|
|
$productPrice = ProductPrice::query()
|
|
->where('variant_id', $productVariantId)
|
|
->where('type', $priceType)
|
|
->first();
|
|
|
|
if ($productPrice !== null) {
|
|
$cp = new CuttingResultPrice;
|
|
$cp->product_variant_id = $productVariantId;
|
|
$cp->price_type = $priceType;
|
|
$cp->price = $productPrice->price;
|
|
|
|
return $cp;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function latestPricesForVariant(int $productVariantId): array
|
|
{
|
|
return $this->cacheRemember("prices:variant:{$productVariantId}", 900, function () use ($productVariantId) {
|
|
$prices = [];
|
|
|
|
foreach (PriceType::cases() as $priceType) {
|
|
$price = $this->resolve($productVariantId, $priceType);
|
|
|
|
if ($price !== null) {
|
|
$prices[] = [
|
|
'price_type' => $price->price_type->value,
|
|
'price' => (int) $price->price,
|
|
'price_formatted' => $price->price_formatted,
|
|
];
|
|
}
|
|
}
|
|
|
|
return $prices;
|
|
});
|
|
}
|
|
|
|
public function latestPricesForVariants(array $variantIds): Collection
|
|
{
|
|
$cached = $this->cacheRemember('prices:variants:'.md5(implode(',', $variantIds)), 900, function () use ($variantIds) {
|
|
if (empty($variantIds)) {
|
|
return [];
|
|
}
|
|
|
|
$cuttingPrices = CuttingResultPrice::query()
|
|
->whereIn('product_variant_id', $variantIds)
|
|
->whereHas('cutting', fn ($query) => $query->verified())
|
|
->join('cuttings', 'cutting_result_prices.cutting_id', '=', 'cuttings.id')
|
|
->orderByDesc('cuttings.created_at')
|
|
->select('cutting_result_prices.*')
|
|
->get()
|
|
->groupBy(fn (CuttingResultPrice $price) => $price->product_variant_id.'-'.$price->price_type->value)
|
|
->map(fn (Collection $group) => $group->first());
|
|
|
|
$productPrices = ProductPrice::query()
|
|
->whereIn('variant_id', $variantIds)
|
|
->get()
|
|
->groupBy(fn (ProductPrice $price) => $price->variant_id.'-'.$price->type->value);
|
|
|
|
// Store only plain arrays — never Eloquent models — to avoid
|
|
// __PHP_Incomplete_Class when Redis deserializes across requests.
|
|
$results = [];
|
|
foreach ($variantIds as $variantId) {
|
|
foreach (PriceType::cases() as $priceType) {
|
|
$key = $variantId.'-'.$priceType->value;
|
|
if ($cuttingPrices->has($key)) {
|
|
$cp = $cuttingPrices->get($key);
|
|
$results[$variantId][] = [
|
|
'price_type' => $cp->price_type->value,
|
|
'price' => (int) $cp->price,
|
|
'price_formatted' => $cp->price_formatted,
|
|
];
|
|
} elseif ($productPrices->has($key)) {
|
|
$pp = $productPrices->get($key)->first();
|
|
$results[$variantId][] = [
|
|
'price_type' => $priceType->value,
|
|
'price' => (int) $pp->price,
|
|
'price_formatted' => 'Rp '.number_format((int) $pp->price, 0, ',', '.'),
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $results;
|
|
});
|
|
|
|
// Rebuild as a Collection keyed by variant ID (matching original contract)
|
|
return collect(is_array($cached) ? $cached : [])->map(fn ($prices) => collect($prices));
|
|
}
|
|
}
|