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

This commit is contained in:
2026-08-14 01:51:48 +02:00
parent 6de12f164d
commit 3d2b566bf2
8 changed files with 391 additions and 69 deletions

View File

@@ -209,7 +209,7 @@ final class AnalyticsService
}
}
$effectiveDailyCost = $includeFullDetail ? $this->effectiveDailyCost($costPlans, $measuredTs, $priceCurrency, $row) : null;
$effectiveDailyCost = $includeFullDetail ? $this->effectiveDailyCost($costPlans, $measuredTs, $priceCurrency, $row, $purchasedMiners) : null;
$currentValue = ($includeFullDetail && $price !== null) ? $visibleCoinsTotal * $price : null;
$currentValueEffective = ($includeFullDetail && $price !== null) ? $effectiveCoinsTotal * $price : null;
$theoreticalDailyRevenue = ($includeFullDetail && $price !== null && $perDayInterval !== null) ? $perDayInterval * $price : null;
@@ -636,7 +636,7 @@ final class AnalyticsService
return $value === null ? null : round($value, $precision);
}
private function effectiveDailyCost(array $costPlans, int $measurementTs, ?string $currency, ?array $fxContext = null): ?float
private function effectiveDailyCost(array $costPlans, int $measurementTs, ?string $currency, ?array $fxContext = null, array $purchasedMiners = []): ?float
{
if ($currency === null) {
return null;
@@ -644,31 +644,56 @@ final class AnalyticsService
$dailyTotal = 0.0;
$matched = false;
$entries = [];
foreach ($costPlans as $plan) {
if (empty($plan['is_active'])) {
$entries[] = [
'entry' => $plan,
'start_field' => 'starts_at',
];
}
foreach ($purchasedMiners as $miner) {
$entries[] = [
'entry' => $miner,
'start_field' => 'purchased_at',
];
}
foreach ($entries as $wrappedEntry) {
$entry = is_array($wrappedEntry['entry'] ?? null) ? $wrappedEntry['entry'] : [];
$startField = (string) ($wrappedEntry['start_field'] ?? 'starts_at');
if (empty($entry['is_active'])) {
continue;
}
$startTs = $this->utcTimestamp((string) ($plan['starts_at'] ?? ''));
$runtimeMonths = (int) ($plan['runtime_months'] ?? 0);
$startTs = $this->utcTimestamp((string) ($entry[$startField] ?? ''));
$runtimeMonths = (int) ($entry['runtime_months'] ?? 0);
if ($startTs <= 0 || $runtimeMonths <= 0 || $measurementTs < $startTs) {
continue;
}
$runtimeDays = $runtimeMonths * 30.4375;
$endTs = (int) round($startTs + ($runtimeDays * 86400));
$isCovered = !empty($plan['auto_renew']) || $measurementTs <= $endTs;
if (!$isCovered) {
if (!$this->entryIsCovered($entry, $measurementTs, $startField)) {
continue;
}
$planDailyCost = (float) $plan['total_cost_amount'] / $runtimeDays;
$convertedDailyCost = $this->convertAmount(
$planDailyCost,
(string) ($plan['currency'] ?? ''),
$currency,
$fxContext
);
$storedDailyCost = is_numeric($entry['daily_cost_amount'] ?? null) ? (float) $entry['daily_cost_amount'] : null;
$entryCurrency = strtoupper(trim((string) ($entry['daily_cost_currency'] ?? $entry['currency'] ?? '')));
if ($entryCurrency === '') {
continue;
}
$planDailyCost = $storedDailyCost;
if ($planDailyCost === null || $planDailyCost <= 0) {
$amount = is_numeric($entry['total_cost_amount'] ?? null) ? (float) $entry['total_cost_amount'] : null;
if ($amount === null || $amount <= 0) {
continue;
}
$runtimeDays = $runtimeMonths * 30.4375;
$planDailyCost = $amount / $runtimeDays;
}
$convertedDailyCost = $this->convertAmount($planDailyCost, $entryCurrency, $currency, $fxContext);
if ($convertedDailyCost === null) {
continue;
}
@@ -996,7 +1021,7 @@ final class AnalyticsService
$runtimeDays = $runtimeMonths * 30.4375;
$endTs = (int) round($startTs + ($runtimeDays * 86400));
return !empty($entry['auto_renew']) || $checkTs <= $endTs;
return $this->entryAutoRenewEnabled($entry) || $checkTs <= $endTs;
}
private function normalizeHashrateMh(mixed $value, mixed $unit): float
@@ -1018,6 +1043,29 @@ final class AnalyticsService
return array_map(fn (mixed $entry): mixed => is_array($entry) ? $this->normalizeLegacyHashrateEntry($entry) : $entry, $entries);
}
private function entryAutoRenewEnabled(array $entry): bool
{
if ($this->entryIsCryptoPaid($entry)) {
return false;
}
return !empty($entry['auto_renew']);
}
private function entryIsCryptoPaid(array $entry): bool
{
$paymentType = strtolower(trim((string) ($entry['payment_type'] ?? '')));
if ($paymentType === 'crypto') {
return true;
}
$currency = strtoupper(trim((string) ($entry['currency'] ?? '')));
return in_array($currency, [
'ADA', 'ARB', 'AVAX', 'BNB', 'BTC', 'CTC', 'DAI', 'DOGE', 'DOT', 'ETH',
'HSH', 'LINK', 'LTC', 'MATIC', 'SOL', 'TRX', 'USDC', 'USDT', 'XMR', 'XRP',
], true);
}
private function normalizeLegacyHashrateEntry(array $entry): array
{
$label = trim((string) ($entry['label'] ?? ''));
@@ -1522,7 +1570,7 @@ final class AnalyticsService
return 0;
}
if (!empty($entry['auto_renew']) || $runtimeMonths <= 0) {
if ($this->entryAutoRenewEnabled($entry) || $runtimeMonths <= 0) {
return $days - $startIndex;
}
@@ -1807,7 +1855,7 @@ final class AnalyticsService
private function entryFundingSource(array $entry): string
{
return !empty($entry['auto_renew']) ? 'cash' : 'reinvest';
return $this->entryIsCryptoPaid($entry) ? 'reinvest' : 'cash';
}
private function investmentBasisAmount(array $entry): ?float
@@ -1933,7 +1981,7 @@ final class AnalyticsService
private function entryCoverageEndTimestamp(array $entry, string $startField = 'starts_at'): ?int
{
if (!empty($entry['auto_renew'])) {
if ($this->entryAutoRenewEnabled($entry)) {
return null;
}