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)); } }