> $items */ public function record(string $source, ?string $sourceUrl, int $liquidGoldPrice, array $items): ?PriceSyncLog { if (! $this->isAvailable() || $items === []) { return null; } $changedItems = array_values(array_filter( $items, static fn (array $item) => (bool) ($item['changed'] ?? false) )); if ($changedItems === []) { return null; } $log = PriceSyncLog::create([ 'source' => $source, 'source_url' => $sourceUrl, 'liquid_gold_price' => $liquidGoldPrice, 'products_updated' => count($changedItems), 'created_at' => now(), ]); foreach ($changedItems as $item) { PriceSyncLogItem::create([ 'log_id' => $log->id, 'product_id' => $item['product_id'] ?? null, 'product_title' => $item['product_title'] ?? null, 'reading_method' => $item['reading_method'] ?? null, 'source_name' => $item['source_name'] ?? null, 'base_price' => (int) ($item['base_price'] ?? 0), 'base_profit' => (int) ($item['base_profit'] ?? 0), 'offset_percent' => (float) ($item['offset_percent'] ?? 0), 'stored_price' => (int) ($item['new_price'] ?? 0), 'previous_price' => (int) ($item['old_price'] ?? 0), ]); } return $log->load('items'); } /** * نمونه دوره‌ای قیمت (مثلاً هر ۳۰ دقیقه) — حتی اگر قیمت نسبت به رکورد قبلی عوض نشده باشد. */ public function recordSnapshot(string $source, ?string $sourceUrl, int $referencePrice): ?PriceSyncLog { if (! $this->isAvailable() || $referencePrice <= 0) { return null; } return PriceSyncLog::create([ 'source' => $source, 'source_url' => $sourceUrl, 'liquid_gold_price' => $referencePrice, 'products_updated' => 0, 'created_at' => now(), ]); } /** * ثبت در تاریخچه ادمین — حداکثر هر ۳۰ دقیقه (مستقل از تغییر قیمت). */ public function recordSnapshotIfDue( string $source, ?string $sourceUrl, int $referencePrice, int $intervalMinutes = 30 ): ?PriceSyncLog { if (! $this->isAvailable() || $referencePrice <= 0) { return null; } $loggedRecently = PriceSyncLog::query() ->where('created_at', '>=', now()->subMinutes($intervalMinutes)) ->exists(); if ($loggedRecently) { return null; } return $this->recordSnapshot($source, $sourceUrl, $referencePrice); } /** فقط وقتی قیمت مرجع آبشده نسبت به آخرین رکورد عوض شده باشد */ public function recordTick(string $source, ?string $sourceUrl, int $liquidGoldPrice, int $productsSynced): ?PriceSyncLog { if (! $this->isAvailable() || $liquidGoldPrice <= 0) { return null; } $last = PriceSyncLog::query()->orderByDesc('id')->first(); if ($last && (int) $last->liquid_gold_price === $liquidGoldPrice) { return null; } return PriceSyncLog::create([ 'source' => $source, 'source_url' => $sourceUrl, 'liquid_gold_price' => $liquidGoldPrice, 'products_updated' => $productsSynced, 'created_at' => now(), ]); } }