ycyxc
All checks were successful
Deploy / deploy-production (push) Has been skipped
Deploy / deploy-staging (push) Successful in 5s

This commit is contained in:
2026-05-20 00:38:05 +02:00
parent 81d1e486e8
commit 813dd86811

View File

@@ -1189,44 +1189,116 @@ final class AnalyticsService
} }
$dogePerDayPerMh = $dogePerDay / $currentHashrateMh; $dogePerDayPerMh = $dogePerDay / $currentHashrateMh;
$cumulativeRevenue = 0.0;
$maxDays = 3650; $maxDays = 3650;
$horizonTs = $baseTs + ($maxDays * 86400);
$entries = [];
for ($day = 0; $day <= $maxDays; $day++) { foreach ($costPlans as $plan) {
$dayHashrate = 0.0; if (empty($plan['is_active'])) {
$dayTs = $baseTs + ($day * 86400);
foreach ($costPlans as $plan) {
if (!empty($plan['is_active']) && $this->entryIsCovered($plan, $dayTs)) {
$dayHashrate += $this->normalizeHashrateMh($plan['mining_speed_value'] ?? null, $plan['mining_speed_unit'] ?? null);
$dayHashrate += $this->normalizeHashrateMh($plan['bonus_speed_value'] ?? null, $plan['bonus_speed_unit'] ?? null);
}
}
foreach ($purchasedMiners as $miner) {
if ((array_key_exists('is_active', $miner) && empty($miner['is_active'])) || !$this->entryIsCovered($miner, $dayTs, 'purchased_at')) {
continue;
}
$dayHashrate += $this->normalizeHashrateMh($miner['mining_speed_value'] ?? null, $miner['mining_speed_unit'] ?? null);
$dayHashrate += $this->normalizeHashrateMh($miner['bonus_speed_value'] ?? null, $miner['bonus_speed_unit'] ?? null);
}
if ($dayHashrate <= 0) {
continue; continue;
} }
$entries[] = ['data' => $plan, 'start_field' => 'starts_at'];
}
$dayRevenue = $dayHashrate * $dogePerDayPerMh * $pricePerCoin; foreach ($purchasedMiners as $miner) {
$cumulativeRevenue += $dayRevenue; if (array_key_exists('is_active', $miner) && empty($miner['is_active'])) {
if ($cumulativeRevenue >= $remainingAmount) { continue;
$etaTs = (int) round($baseTs + ($day * 86400)); }
return [ $entries[] = ['data' => $miner, 'start_field' => 'purchased_at'];
'days' => (float) $day, }
'eta' => $this->formatUtcTimestamp($etaTs),
]; $events = [$baseTs, $horizonTs];
foreach ($entries as $entryMeta) {
$entry = $entryMeta['data'];
$startField = $entryMeta['start_field'];
$startTs = $this->utcTimestamp((string) ($entry[$startField] ?? ''));
if ($startTs > $baseTs && $startTs < $horizonTs) {
$events[] = $startTs;
}
$endTs = $this->entryCoverageEndTimestamp($entry, $startField);
if ($endTs !== null) {
$afterEndTs = $endTs + 1;
if ($afterEndTs > $baseTs && $afterEndTs < $horizonTs) {
$events[] = $afterEndTs;
}
} }
} }
$events = array_values(array_unique(array_map('intval', $events)));
sort($events, SORT_NUMERIC);
$cumulativeRevenue = 0.0;
for ($index = 0, $maxIndex = count($events) - 1; $index < $maxIndex; $index++) {
$segmentStartTs = $events[$index];
$segmentEndTs = $events[$index + 1];
if ($segmentEndTs <= $segmentStartTs) {
continue;
}
$segmentHashrate = 0.0;
foreach ($entries as $entryMeta) {
$entry = $entryMeta['data'];
$startField = $entryMeta['start_field'];
if (!$this->entryIsCovered($entry, $segmentStartTs, $startField)) {
continue;
}
$segmentHashrate += $this->normalizeHashrateMh($entry['mining_speed_value'] ?? null, $entry['mining_speed_unit'] ?? null);
$segmentHashrate += $this->normalizeHashrateMh($entry['bonus_speed_value'] ?? null, $entry['bonus_speed_unit'] ?? null);
}
if ($segmentHashrate <= 0) {
continue;
}
$segmentDays = ($segmentEndTs - $segmentStartTs) / 86400;
if ($segmentDays <= 0) {
continue;
}
$segmentRevenuePerDay = $segmentHashrate * $dogePerDayPerMh * $pricePerCoin;
if ($segmentRevenuePerDay <= 0) {
continue;
}
$segmentRevenue = $segmentRevenuePerDay * $segmentDays;
if ($cumulativeRevenue + $segmentRevenue >= $remainingAmount) {
$remainingSegmentAmount = $remainingAmount - $cumulativeRevenue;
$segmentOffsetDays = $remainingSegmentAmount / $segmentRevenuePerDay;
$etaTs = (int) round($segmentStartTs + ($segmentOffsetDays * 86400));
return [
'days' => round(($etaTs - $baseTs) / 86400, 4),
'eta' => $this->formatUtcTimestamp($etaTs),
];
}
$cumulativeRevenue += $segmentRevenue;
}
return ['days' => null, 'eta' => null]; return ['days' => null, 'eta' => null];
} }
private function entryCoverageEndTimestamp(array $entry, string $startField = 'starts_at'): ?int
{
if (!empty($entry['auto_renew'])) {
return null;
}
$runtimeMonths = (int) ($entry['runtime_months'] ?? 0);
if ($runtimeMonths <= 0) {
return null;
}
$startTs = $this->utcTimestamp((string) ($entry[$startField] ?? ''));
if ($startTs <= 0) {
return null;
}
$runtimeDays = $runtimeMonths * 30.4375;
return (int) round($startTs + ($runtimeDays * 86400));
}
private function utcTimestamp(?string $value): int private function utcTimestamp(?string $value): int
{ {
$normalized = trim((string) $value); $normalized = trim((string) $value);