asdasd
This commit is contained in:
@@ -20,7 +20,12 @@ final class AnalyticsService
|
||||
$baselineAt = (string) ($settings['baseline_measured_at'] ?? '');
|
||||
$costPlans = is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [];
|
||||
$payouts = is_array($settings['payouts'] ?? null) ? $settings['payouts'] : [];
|
||||
$measurementRates = is_array($settings['measurement_rates'] ?? null) ? $settings['measurement_rates'] : [];
|
||||
$preferredPriceCurrencies = array_values(array_unique(array_filter([
|
||||
strtoupper(trim((string) ($settings['report_currency'] ?? ''))),
|
||||
'USD',
|
||||
'EUR',
|
||||
'DOGE',
|
||||
])));
|
||||
|
||||
$baselineTs = $this->utcTimestamp($baselineAt);
|
||||
$previous = null;
|
||||
@@ -79,7 +84,7 @@ final class AnalyticsService
|
||||
$latestPriceByCurrency[(string) $rawPriceCurrency] = $rawPrice;
|
||||
}
|
||||
|
||||
$measurementDerivedPrices = $this->measurementDerivedPrices($measurementRates, (int) ($row['id'] ?? 0));
|
||||
$measurementDerivedPrices = $this->measurementDerivedPrices($row, $preferredPriceCurrencies);
|
||||
foreach ($measurementDerivedPrices as $derivedCurrency => $derivedPrice) {
|
||||
$latestPriceByCurrency[$derivedCurrency] = $derivedPrice;
|
||||
}
|
||||
@@ -96,7 +101,7 @@ final class AnalyticsService
|
||||
}
|
||||
if ($price === null) {
|
||||
foreach (['USD', 'EUR'] as $fallbackCurrency) {
|
||||
$fxPrice = $this->convertAmount(1.0, 'DOGE', $fallbackCurrency);
|
||||
$fxPrice = $this->convertAmount(1.0, 'DOGE', $fallbackCurrency, $row);
|
||||
if ($fxPrice !== null && $fxPrice > 0) {
|
||||
$latestPriceByCurrency[$fallbackCurrency] = $fxPrice;
|
||||
}
|
||||
@@ -107,7 +112,7 @@ final class AnalyticsService
|
||||
}
|
||||
}
|
||||
|
||||
$effectiveDailyCost = $this->effectiveDailyCost($costPlans, $measuredTs, $priceCurrency);
|
||||
$effectiveDailyCost = $this->effectiveDailyCost($costPlans, $measuredTs, $priceCurrency, $row);
|
||||
$currentValue = $price !== null ? $visibleCoinsTotal * $price : null;
|
||||
$currentValueEffective = $price !== null ? $effectiveCoinsTotal * $price : null;
|
||||
$theoreticalDailyRevenue = ($price !== null && $perDayInterval !== null) ? $perDayInterval * $price : null;
|
||||
@@ -148,6 +153,7 @@ final class AnalyticsService
|
||||
'effective_price_per_coin' => $this->roundOrNull($price, 8),
|
||||
'effective_price_currency' => $priceCurrency,
|
||||
'price_is_fallback' => $rawPrice === null && $price !== null,
|
||||
'price_quotes' => $measurementDerivedPrices,
|
||||
'current_value' => $this->roundOrNull($currentValue, 8),
|
||||
'current_value_effective' => $this->roundOrNull($currentValueEffective, 8),
|
||||
'effective_daily_cost' => $this->roundOrNull($effectiveDailyCost, 8),
|
||||
@@ -183,10 +189,18 @@ final class AnalyticsService
|
||||
$latest = $measurements[array_key_last($measurements)];
|
||||
$latestPriceByCurrency = [];
|
||||
foreach ($measurements as $measurement) {
|
||||
if ($measurement['price_per_coin'] !== null && $measurement['price_currency'] !== null) {
|
||||
$latestPriceByCurrency[(string) $measurement['price_currency']] = (float) $measurement['price_per_coin'];
|
||||
$quotes = is_array($measurement['price_quotes'] ?? null) ? $measurement['price_quotes'] : [];
|
||||
foreach ($quotes as $currency => $price) {
|
||||
$normalizedCurrency = strtoupper(trim((string) $currency));
|
||||
if ($normalizedCurrency !== '' && is_numeric($price)) {
|
||||
$latestPriceByCurrency[$normalizedCurrency] = (float) $price;
|
||||
}
|
||||
}
|
||||
}
|
||||
$latestEffectiveCurrency = strtoupper(trim((string) ($latest['effective_price_currency'] ?? $latest['price_currency'] ?? '')));
|
||||
if ($latestEffectiveCurrency !== '' && is_numeric($latest['effective_price_per_coin'] ?? null)) {
|
||||
$latestPriceByCurrency[$latestEffectiveCurrency] = (float) $latest['effective_price_per_coin'];
|
||||
}
|
||||
|
||||
$payouts = is_array($settings['payouts'] ?? null) ? $settings['payouts'] : [];
|
||||
$purchasedMiners = is_array($settings['purchased_miners'] ?? null) ? $settings['purchased_miners'] : [];
|
||||
@@ -221,7 +235,7 @@ final class AnalyticsService
|
||||
: (is_numeric($linkedOffer['effective_price_amount'] ?? null) ? (float) $linkedOffer['effective_price_amount'] : $targetAmount);
|
||||
}
|
||||
|
||||
$price = $latestPriceByCurrency[$currency] ?? $this->convertLatestPrice($latestPriceByCurrency, $currency);
|
||||
$price = $latestPriceByCurrency[$currency] ?? $this->convertLatestPrice($latestPriceByCurrency, $currency, $latest);
|
||||
$requiredDoge = ($price && $targetAmount !== null) ? $targetAmount / $price : null;
|
||||
$remainingDoge = $requiredDoge !== null ? $requiredDoge - (float) ($latest['coins_total_effective'] ?? $latest['coins_total']) : null;
|
||||
$remainingDays = (
|
||||
@@ -264,7 +278,8 @@ final class AnalyticsService
|
||||
is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [],
|
||||
$purchasedMiners,
|
||||
$this->utcTimestamp((string) ($latest['measured_at'] ?? '')),
|
||||
$latestCurrency
|
||||
$latestCurrency,
|
||||
$latest
|
||||
)
|
||||
: null;
|
||||
$currentDailyRevenue = is_numeric($latest['theoretical_daily_revenue'] ?? null) ? (float) $latest['theoretical_daily_revenue'] : null;
|
||||
@@ -399,7 +414,7 @@ final class AnalyticsService
|
||||
return $value === null ? null : round($value, $precision);
|
||||
}
|
||||
|
||||
private function effectiveDailyCost(array $costPlans, int $measurementTs, ?string $currency): ?float
|
||||
private function effectiveDailyCost(array $costPlans, int $measurementTs, ?string $currency, ?array $fxContext = null): ?float
|
||||
{
|
||||
if ($currency === null) {
|
||||
return null;
|
||||
@@ -429,7 +444,8 @@ final class AnalyticsService
|
||||
$convertedDailyCost = $this->convertAmount(
|
||||
$planDailyCost,
|
||||
(string) ($plan['currency'] ?? ''),
|
||||
$currency
|
||||
$currency,
|
||||
$fxContext
|
||||
);
|
||||
if ($convertedDailyCost === null) {
|
||||
continue;
|
||||
@@ -442,10 +458,10 @@ final class AnalyticsService
|
||||
return $matched ? $dailyTotal : null;
|
||||
}
|
||||
|
||||
private function convertLatestPrice(array $latestPriceByCurrency, string $targetCurrency): ?float
|
||||
private function convertLatestPrice(array $latestPriceByCurrency, string $targetCurrency, ?array $fxContext = null): ?float
|
||||
{
|
||||
foreach ($latestPriceByCurrency as $sourceCurrency => $price) {
|
||||
$converted = $this->convertAmount((float) $price, (string) $sourceCurrency, $targetCurrency);
|
||||
$converted = $this->convertAmount((float) $price, (string) $sourceCurrency, $targetCurrency, $fxContext);
|
||||
if ($converted !== null) {
|
||||
return $converted;
|
||||
}
|
||||
@@ -474,33 +490,32 @@ final class AnalyticsService
|
||||
return is_string($derivedFirst) ? $derivedFirst : null;
|
||||
}
|
||||
|
||||
private function measurementDerivedPrices(array $measurementRates, int $measurementId): array
|
||||
private function measurementDerivedPrices(array $measurement, array $targetCurrencies): array
|
||||
{
|
||||
if ($measurementId <= 0 || $measurementRates === []) {
|
||||
$rawPrice = is_numeric($measurement['price_per_coin'] ?? null) ? (float) $measurement['price_per_coin'] : null;
|
||||
$rawCurrency = strtoupper(trim((string) ($measurement['price_currency'] ?? '')));
|
||||
|
||||
if ($rawPrice === null || $rawPrice <= 0 || $rawCurrency === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$prices = [];
|
||||
foreach ($measurementRates as $row) {
|
||||
if ((int) ($row['measurement_id'] ?? 0) !== $measurementId) {
|
||||
$prices = [$rawCurrency => $rawPrice];
|
||||
foreach ($targetCurrencies as $targetCurrency) {
|
||||
$targetCurrency = strtoupper(trim((string) $targetCurrency));
|
||||
if ($targetCurrency === '' || isset($prices[$targetCurrency])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$baseCurrency = strtoupper(trim((string) ($row['base_currency'] ?? '')));
|
||||
$quoteCurrency = strtoupper(trim((string) ($row['target_currency'] ?? $row['quote_currency'] ?? '')));
|
||||
$rate = is_numeric($row['rate'] ?? null) ? (float) $row['rate'] : null;
|
||||
|
||||
if ($baseCurrency !== 'DOGE' || $quoteCurrency === '' || $rate === null || $rate <= 0) {
|
||||
continue;
|
||||
$converted = $this->convertAmount($rawPrice, $rawCurrency, $targetCurrency, $measurement);
|
||||
if ($converted !== null && $converted > 0) {
|
||||
$prices[$targetCurrency] = $converted;
|
||||
}
|
||||
|
||||
$prices[$quoteCurrency] = $rate;
|
||||
}
|
||||
|
||||
return $prices;
|
||||
}
|
||||
|
||||
private function convertAmount(?float $amount, ?string $fromCurrency, ?string $toCurrency): ?float
|
||||
private function convertAmount(?float $amount, ?string $fromCurrency, ?string $toCurrency, ?array $fxContext = null): ?float
|
||||
{
|
||||
if ($amount === null || $fromCurrency === null || $toCurrency === null) {
|
||||
return null;
|
||||
@@ -520,7 +535,12 @@ final class AnalyticsService
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->fx->convert($amount, $from, $to);
|
||||
$fetchId = isset($fxContext['fx_fetch_id']) && is_numeric($fxContext['fx_fetch_id'])
|
||||
? (int) $fxContext['fx_fetch_id']
|
||||
: null;
|
||||
$at = is_string($fxContext['measured_at'] ?? null) ? (string) $fxContext['measured_at'] : null;
|
||||
|
||||
return $this->fx->convertAt($amount, $from, $to, $at, null, $fetchId);
|
||||
}
|
||||
|
||||
private function totalHashrateMh(array $entries): float
|
||||
@@ -541,7 +561,7 @@ final class AnalyticsService
|
||||
return $total;
|
||||
}
|
||||
|
||||
private function totalPurchasedMinerCost(array $purchasedMiners, string $targetCurrency, ?int $measurementTs = null): ?float
|
||||
private function totalPurchasedMinerCost(array $purchasedMiners, string $targetCurrency, ?int $measurementTs = null, ?array $fxContext = null): ?float
|
||||
{
|
||||
$target = strtoupper(trim($targetCurrency));
|
||||
if ($target === '') {
|
||||
@@ -564,7 +584,7 @@ final class AnalyticsService
|
||||
continue;
|
||||
}
|
||||
|
||||
$converted = $this->convertAmount($amount, $currency, $target);
|
||||
$converted = $this->convertAmount($amount, $currency, $target, $fxContext);
|
||||
if ($converted === null) {
|
||||
continue;
|
||||
}
|
||||
@@ -576,7 +596,7 @@ final class AnalyticsService
|
||||
return $matched ? $total : null;
|
||||
}
|
||||
|
||||
private function totalInvestmentBasis(array $costPlans, array $purchasedMiners, int $measurementTs, string $targetCurrency): ?float
|
||||
private function totalInvestmentBasis(array $costPlans, array $purchasedMiners, int $measurementTs, string $targetCurrency, ?array $fxContext = null): ?float
|
||||
{
|
||||
$target = strtoupper(trim($targetCurrency));
|
||||
if ($target === '') {
|
||||
@@ -586,7 +606,7 @@ final class AnalyticsService
|
||||
$total = 0.0;
|
||||
$matched = false;
|
||||
|
||||
$purchasedTotal = $this->totalPurchasedMinerCost($purchasedMiners, $target, $measurementTs);
|
||||
$purchasedTotal = $this->totalPurchasedMinerCost($purchasedMiners, $target, $measurementTs, $fxContext);
|
||||
if ($purchasedTotal !== null) {
|
||||
$matched = true;
|
||||
$total += $purchasedTotal;
|
||||
@@ -616,7 +636,7 @@ final class AnalyticsService
|
||||
continue;
|
||||
}
|
||||
|
||||
$converted = $this->convertAmount($amount, $currency, $target);
|
||||
$converted = $this->convertAmount($amount, $currency, $target, $fxContext);
|
||||
if ($converted === null) {
|
||||
continue;
|
||||
}
|
||||
@@ -688,7 +708,7 @@ final class AnalyticsService
|
||||
: $basePriceCurrency;
|
||||
$effectivePriceAmount = $basePriceAmount;
|
||||
if ($basePriceAmount !== null && $basePriceAmount > 0 && $basePriceCurrency !== '' && $effectivePriceCurrency !== '' && strtoupper($basePriceCurrency) !== strtoupper($effectivePriceCurrency)) {
|
||||
$convertedReference = $this->convertAmount($basePriceAmount, $basePriceCurrency, $effectivePriceCurrency);
|
||||
$convertedReference = $this->convertAmount($basePriceAmount, $basePriceCurrency, $effectivePriceCurrency, $latest);
|
||||
if ($convertedReference !== null && $convertedReference > 0) {
|
||||
$effectivePriceAmount = $convertedReference;
|
||||
}
|
||||
@@ -701,7 +721,7 @@ final class AnalyticsService
|
||||
$expectedDogePerDay = ((float) $latest['doge_per_day_interval'] / $currentHashrateMh) * $offerHashrateMh;
|
||||
}
|
||||
|
||||
$offerCurrencyPrice = $effectivePriceCurrency !== '' ? ($latestPriceByCurrency[$effectivePriceCurrency] ?? $this->convertLatestPrice($latestPriceByCurrency, $effectivePriceCurrency)) : null;
|
||||
$offerCurrencyPrice = $effectivePriceCurrency !== '' ? ($latestPriceByCurrency[$effectivePriceCurrency] ?? $this->convertLatestPrice($latestPriceByCurrency, $effectivePriceCurrency, $latest)) : null;
|
||||
$expectedDailyRevenue = ($expectedDogePerDay !== null && $offerCurrencyPrice !== null)
|
||||
? $expectedDogePerDay * $offerCurrencyPrice
|
||||
: null;
|
||||
@@ -752,7 +772,7 @@ final class AnalyticsService
|
||||
$offerPriceAmount !== null &&
|
||||
$offerPriceCurrency !== '' &&
|
||||
$latestCurrency !== ''
|
||||
) ? $this->convertAmount($offerPriceAmount, $offerPriceCurrency, $latestCurrency) : null;
|
||||
) ? $this->convertAmount($offerPriceAmount, $offerPriceCurrency, $latestCurrency, $latest) : null;
|
||||
$scenarioDogePerDay = (
|
||||
$currentDogePerDay !== null &&
|
||||
$expectedDogePerDay !== null
|
||||
@@ -864,7 +884,7 @@ final class AnalyticsService
|
||||
$runtimeMonths = (int) ($plan['runtime_months'] ?? 0);
|
||||
if ($runtimeMonths > 0 && is_numeric($plan['total_cost_amount'] ?? null)) {
|
||||
$runtimeDays = $runtimeMonths * 30.4375;
|
||||
$dailyCost = $this->convertAmount((float) $plan['total_cost_amount'] / $runtimeDays, (string) ($plan['currency'] ?? ''), $currency);
|
||||
$dailyCost = $this->convertAmount((float) $plan['total_cost_amount'] / $runtimeDays, (string) ($plan['currency'] ?? ''), $currency, $latest);
|
||||
if ($dailyCost !== null) {
|
||||
$cost += $dailyCost;
|
||||
}
|
||||
@@ -882,7 +902,7 @@ final class AnalyticsService
|
||||
$runtimeMonths = (int) ($miner['runtime_months'] ?? 0);
|
||||
if ($runtimeMonths > 0 && is_numeric($miner['total_cost_amount'] ?? null)) {
|
||||
$runtimeDays = $runtimeMonths * 30.4375;
|
||||
$dailyCost = $this->convertAmount((float) $miner['total_cost_amount'] / $runtimeDays, (string) ($miner['currency'] ?? ''), $currency);
|
||||
$dailyCost = $this->convertAmount((float) $miner['total_cost_amount'] / $runtimeDays, (string) ($miner['currency'] ?? ''), $currency, $latest);
|
||||
if ($dailyCost !== null) {
|
||||
$cost += $dailyCost;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user