Files
boursecu_server/app/Services/PriceSyncLogService.php
T
2026-07-06 13:39:05 +03:30

123 lines
4.0 KiB
PHP

<?php
namespace App\Services;
use App\Models\PriceSyncLog;
use App\Models\PriceSyncLogItem;
use Illuminate\Support\Facades\Schema;
class PriceSyncLogService
{
public function isAvailable(): bool
{
return Schema::hasTable('price_sync_logs') && Schema::hasTable('price_sync_log_items');
}
/**
* @param array<int, array<string, mixed>> $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 || $source === 'database_last') {
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(),
]);
}
}