This commit is contained in:
2026-06-03 01:27:00 +02:00
parent 99cf5eaef2
commit 7783f65b26
3 changed files with 303 additions and 59 deletions

View File

@@ -7,6 +7,16 @@ use Modules\MiningChecker\Support\ApiException;
final class AnalyticsService
{
private const BASE_OFFER_SPEEDS = [
'fiat' => ['value' => 50.0, 'unit' => 'kH/s'],
'crypto' => ['value' => 75.0, 'unit' => 'kH/s'],
];
private const OFFER_SPEED_MULTIPLIERS = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
];
private ?FxService $fx;
public function __construct(?FxService $fx = null)
@@ -245,7 +255,7 @@ final class AnalyticsService
$purchasedMiners
));
$offerSummary = [];
foreach ($minerOffers as $offer) {
foreach ($this->expandOfferVariants($minerOffers, $settings) as $offer) {
$offerSummary[] = $this->evaluateMinerOffer($offer, $latest, $latestPriceByCurrency, $currentHashrateMh, $settings);
}
@@ -256,7 +266,7 @@ final class AnalyticsService
$linkedOffer = null;
if (is_numeric($target['miner_offer_id'] ?? null)) {
foreach ($offerSummary as $offer) {
if ((int) ($offer['id'] ?? 0) === (int) $target['miner_offer_id']) {
if ((int) ($offer['base_offer_id'] ?? $offer['id'] ?? 0) === (int) $target['miner_offer_id']) {
$linkedOffer = $offer;
break;
}
@@ -823,6 +833,102 @@ final class AnalyticsService
};
}
private function expandOfferVariants(array $offers, array $settings): array
{
$expanded = [];
foreach ($offers as $offer) {
$paymentType = $this->normalizeOfferPaymentType($offer);
$baseSpeed = self::BASE_OFFER_SPEEDS[$paymentType] ?? self::BASE_OFFER_SPEEDS['fiat'];
$baseSpeedValue = (float) $baseSpeed['value'];
$baseSpeedUnit = (string) $baseSpeed['unit'];
$baseBonusPercent = $this->deriveBonusPercent($offer, $baseSpeedValue, $baseSpeedUnit);
$basePriceAmount = is_numeric($offer['base_price_amount'] ?? null)
? (float) $offer['base_price_amount']
: (is_numeric($offer['reference_price_amount'] ?? null)
? (float) $offer['reference_price_amount']
: (is_numeric($offer['usd_reference_amount'] ?? null)
? (float) $offer['usd_reference_amount']
: (is_numeric($offer['price_amount'] ?? null) ? (float) $offer['price_amount'] : null)));
foreach (self::OFFER_SPEED_MULTIPLIERS as $multiplier) {
$derivedSpeedValue = $baseSpeedValue * $multiplier;
$derivedBonusValue = $baseBonusPercent !== null
? round($derivedSpeedValue * ($baseBonusPercent / 100), 4)
: null;
$derivedPriceAmount = $basePriceAmount !== null
? round($basePriceAmount * $multiplier, 8)
: null;
$expanded[] = array_merge($offer, [
'id' => sprintf('%s:%s:%s', (string) ($offer['id'] ?? 'offer'), $paymentType, rtrim(rtrim(number_format($derivedSpeedValue, 4, '.', ''), '0'), '.')),
'base_offer_id' => $offer['id'] ?? null,
'base_offer_label' => $offer['label'] ?? null,
'payment_type' => $paymentType,
'label' => trim(((string) ($offer['label'] ?? 'Miner-Angebot')) . ' · ' . $this->formatSpeedLabel($derivedSpeedValue, $baseSpeedUnit)),
'mining_speed_value' => $derivedSpeedValue,
'mining_speed_unit' => $baseSpeedUnit,
'bonus_speed_value' => $derivedBonusValue,
'bonus_speed_unit' => $derivedBonusValue !== null ? $baseSpeedUnit : null,
'bonus_percent' => $baseBonusPercent,
'speed_factor' => $multiplier,
'base_speed_value' => $baseSpeedValue,
'base_speed_unit' => $baseSpeedUnit,
'base_price_amount' => $derivedPriceAmount,
'reference_price_amount' => $derivedPriceAmount,
]);
}
}
usort($expanded, static function (array $left, array $right): int {
$paymentCompare = strcmp((string) ($left['payment_type'] ?? ''), (string) ($right['payment_type'] ?? ''));
if ($paymentCompare !== 0) {
return $paymentCompare;
}
$runtimeCompare = ((int) ($left['runtime_months'] ?? 0)) <=> ((int) ($right['runtime_months'] ?? 0));
if ($runtimeCompare !== 0) {
return $runtimeCompare;
}
return ((int) ($left['speed_factor'] ?? 0)) <=> ((int) ($right['speed_factor'] ?? 0));
});
return $expanded;
}
private function normalizeOfferPaymentType(array $offer): string
{
$paymentType = strtolower(trim((string) ($offer['payment_type'] ?? '')));
if (in_array($paymentType, ['fiat', 'crypto'], true)) {
return $paymentType;
}
return !empty($offer['price_currency']) && in_array(strtoupper((string) $offer['price_currency']), ['ADA','ARB','BNB','BTC','DAI','DOGE','DOT','ETH','LINK','LTC','SOL','USDC','USDT','XRP'], true)
? 'crypto'
: 'fiat';
}
private function deriveBonusPercent(array $offer, float $speedValue, string $speedUnit): ?float
{
if (is_numeric($offer['bonus_percent'] ?? null)) {
$numeric = (float) $offer['bonus_percent'];
return $numeric >= 0 ? $numeric : null;
}
$baseSpeedMh = $this->normalizeHashrateMh($speedValue, $speedUnit);
$bonusMh = $this->normalizeHashrateMh($offer['bonus_speed_value'] ?? null, $offer['bonus_speed_unit'] ?? null);
if ($baseSpeedMh <= 0 || $bonusMh <= 0) {
return null;
}
return ($bonusMh / $baseSpeedMh) * 100;
}
private function formatSpeedLabel(float $value, string $unit): string
{
return rtrim(rtrim(number_format($value, 4, '.', ''), '0'), '.') . ' ' . $unit;
}
private function evaluateMinerOffer(array $offer, array $latest, array $latestPriceByCurrency, float $currentHashrateMh, array $settings): array
{
$offerHashrateMh = $this->normalizeHashrateMh($offer['mining_speed_value'] ?? null, $offer['mining_speed_unit'] ?? null)