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

@@ -239,10 +239,12 @@ final class MiningRepository
$stmt = $this->pdo->prepare(
'INSERT INTO ' . $this->table('cost_plans') . ' (
project_key, owner_sub, label, starts_at, runtime_months, mining_speed_value, mining_speed_unit,
bonus_speed_value, bonus_speed_unit, auto_renew, base_price_amount, payment_type, total_cost_amount, currency, note, is_active
bonus_speed_value, bonus_speed_unit, auto_renew, base_price_amount, payment_type, total_cost_amount, currency,
daily_cost_amount, daily_cost_currency, note, is_active
) VALUES (
:project_key, :owner_sub, :label, :starts_at, :runtime_months, :mining_speed_value, :mining_speed_unit,
:bonus_speed_value, :bonus_speed_unit, :auto_renew, :base_price_amount, :payment_type, :total_cost_amount, :currency, :note, :is_active
:bonus_speed_value, :bonus_speed_unit, :auto_renew, :base_price_amount, :payment_type, :total_cost_amount, :currency,
:daily_cost_amount, :daily_cost_currency, :note, :is_active
)
RETURNING *'
);
@@ -253,10 +255,12 @@ final class MiningRepository
$stmt = $this->pdo->prepare(
'INSERT INTO ' . $this->table('cost_plans') . ' (
project_key, owner_sub, label, starts_at, runtime_months, mining_speed_value, mining_speed_unit,
bonus_speed_value, bonus_speed_unit, auto_renew, base_price_amount, payment_type, total_cost_amount, currency, note, is_active
bonus_speed_value, bonus_speed_unit, auto_renew, base_price_amount, payment_type, total_cost_amount, currency,
daily_cost_amount, daily_cost_currency, note, is_active
) VALUES (
:project_key, :owner_sub, :label, :starts_at, :runtime_months, :mining_speed_value, :mining_speed_unit,
:bonus_speed_value, :bonus_speed_unit, :auto_renew, :base_price_amount, :payment_type, :total_cost_amount, :currency, :note, :is_active
:bonus_speed_value, :bonus_speed_unit, :auto_renew, :base_price_amount, :payment_type, :total_cost_amount, :currency,
:daily_cost_amount, :daily_cost_currency, :note, :is_active
)'
);
$stmt->execute($this->normalizeInsertPayload($projectKey, $payload));
@@ -1001,11 +1005,13 @@ final class MiningRepository
'INSERT INTO ' . $this->table('purchased_miners') . ' (
project_key, owner_sub, miner_offer_id, purchased_at, label, runtime_months,
mining_speed_value, mining_speed_unit, bonus_speed_value, bonus_speed_unit,
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency, auto_renew, note, is_active
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency,
daily_cost_amount, daily_cost_currency, auto_renew, note, is_active
) VALUES (
:project_key, :owner_sub, :miner_offer_id, :purchased_at, :label, :runtime_months,
:mining_speed_value, :mining_speed_unit, :bonus_speed_value, :bonus_speed_unit,
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency, :auto_renew, :note, :is_active
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency,
:daily_cost_amount, :daily_cost_currency, :auto_renew, :note, :is_active
)
RETURNING *'
);
@@ -1017,11 +1023,13 @@ final class MiningRepository
'INSERT INTO ' . $this->table('purchased_miners') . ' (
project_key, owner_sub, miner_offer_id, purchased_at, label, runtime_months,
mining_speed_value, mining_speed_unit, bonus_speed_value, bonus_speed_unit,
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency, auto_renew, note, is_active
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency,
daily_cost_amount, daily_cost_currency, auto_renew, note, is_active
) VALUES (
:project_key, :owner_sub, :miner_offer_id, :purchased_at, :label, :runtime_months,
:mining_speed_value, :mining_speed_unit, :bonus_speed_value, :bonus_speed_unit,
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency, :auto_renew, :note, :is_active
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency,
:daily_cost_amount, :daily_cost_currency, :auto_renew, :note, :is_active
)'
);
$stmt->execute($this->normalizePurchasedPayload($projectKey, $offerId, $payload));
@@ -1049,6 +1057,8 @@ final class MiningRepository
'usd_reference_amount' => $payload['usd_reference_amount'] ?? null,
'reference_price_amount' => $payload['reference_price_amount'] ?? null,
'reference_price_currency' => $payload['reference_price_currency'] ?? null,
'daily_cost_amount' => $payload['daily_cost_amount'] ?? $this->deriveDailyCostAmount($payload['total_cost_amount'] ?? null, $payload['runtime_months'] ?? null),
'daily_cost_currency' => $payload['daily_cost_currency'] ?? ($payload['currency'] ?? null),
'auto_renew' => $payload['auto_renew'] ?? 0,
'note' => $payload['note'] ?? null,
'is_active' => $payload['is_active'] ?? 1,
@@ -1059,11 +1069,13 @@ final class MiningRepository
'INSERT INTO ' . $this->table('purchased_miners') . ' (
project_key, owner_sub, miner_offer_id, purchased_at, label, runtime_months,
mining_speed_value, mining_speed_unit, bonus_speed_value, bonus_speed_unit,
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency, auto_renew, note, is_active
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency,
daily_cost_amount, daily_cost_currency, auto_renew, note, is_active
) VALUES (
:project_key, :owner_sub, :miner_offer_id, :purchased_at, :label, :runtime_months,
:mining_speed_value, :mining_speed_unit, :bonus_speed_value, :bonus_speed_unit,
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency, :auto_renew, :note, :is_active
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency,
:daily_cost_amount, :daily_cost_currency, :auto_renew, :note, :is_active
)
RETURNING *'
);
@@ -1075,11 +1087,13 @@ final class MiningRepository
'INSERT INTO ' . $this->table('purchased_miners') . ' (
project_key, owner_sub, miner_offer_id, purchased_at, label, runtime_months,
mining_speed_value, mining_speed_unit, bonus_speed_value, bonus_speed_unit,
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency, auto_renew, note, is_active
total_cost_amount, currency, usd_reference_amount, reference_price_amount, reference_price_currency,
daily_cost_amount, daily_cost_currency, auto_renew, note, is_active
) VALUES (
:project_key, :owner_sub, :miner_offer_id, :purchased_at, :label, :runtime_months,
:mining_speed_value, :mining_speed_unit, :bonus_speed_value, :bonus_speed_unit,
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency, :auto_renew, :note, :is_active
:total_cost_amount, :currency, :usd_reference_amount, :reference_price_amount, :reference_price_currency,
:daily_cost_amount, :daily_cost_currency, :auto_renew, :note, :is_active
)'
);
$stmt->execute($params);
@@ -1567,6 +1581,9 @@ final class MiningRepository
private function normalizeInsertPayload(string $projectKey, array $payload): array
{
$dailyCostAmount = $payload['daily_cost_amount'] ?? $this->deriveDailyCostAmount($payload['total_cost_amount'] ?? null, $payload['runtime_months'] ?? null);
$dailyCostCurrency = $payload['daily_cost_currency'] ?? ($payload['currency'] ?? null);
return [
'project_key' => $projectKey,
'owner_sub' => $this->ownerSub,
@@ -1582,6 +1599,8 @@ final class MiningRepository
'payment_type' => $payload['payment_type'] ?? 'fiat',
'total_cost_amount' => $payload['total_cost_amount'],
'currency' => $payload['currency'],
'daily_cost_amount' => $dailyCostAmount,
'daily_cost_currency' => $dailyCostCurrency,
'note' => $payload['note'],
'is_active' => $payload['is_active'],
];
@@ -1608,6 +1627,9 @@ final class MiningRepository
private function normalizePurchasedPayload(string $projectKey, ?int $offerId, array $payload): array
{
$dailyCostAmount = $payload['daily_cost_amount'] ?? $this->deriveDailyCostAmount($payload['total_cost_amount'] ?? null, $payload['runtime_months'] ?? null);
$dailyCostCurrency = $payload['daily_cost_currency'] ?? ($payload['currency'] ?? null);
return [
'project_key' => $projectKey,
'owner_sub' => $this->ownerSub,
@@ -1624,12 +1646,33 @@ final class MiningRepository
'usd_reference_amount' => $payload['usd_reference_amount'],
'reference_price_amount' => $payload['reference_price_amount'] ?? null,
'reference_price_currency' => $payload['reference_price_currency'] ?? null,
'daily_cost_amount' => $dailyCostAmount,
'daily_cost_currency' => $dailyCostCurrency,
'auto_renew' => $payload['auto_renew'] ?? 0,
'note' => $payload['note'],
'is_active' => $payload['is_active'],
];
}
private function deriveDailyCostAmount(mixed $totalCostAmount, mixed $runtimeMonths): ?float
{
if (!is_numeric($totalCostAmount) || !is_numeric($runtimeMonths)) {
return null;
}
$months = (float) $runtimeMonths;
if ($months <= 0) {
return null;
}
$runtimeDays = $months * 30.4375;
if ($runtimeDays <= 0) {
return null;
}
return round(((float) $totalCostAmount) / $runtimeDays, 10);
}
private function normalizeRows(array $rows): array
{
return array_map(fn (array $row): array => $this->normalizeRow($row), $rows);

View File

@@ -178,6 +178,19 @@ final class SchemaManager
$applied[] = 'cost_plan_columns';
}
}
if (
($this->tableExists($this->prefix . 'cost_plans') && (
!$this->columnExists($this->prefix . 'cost_plans', 'daily_cost_amount') ||
!$this->columnExists($this->prefix . 'cost_plans', 'daily_cost_currency')
)) ||
($this->tableExists($this->prefix . 'purchased_miners') && (
!$this->columnExists($this->prefix . 'purchased_miners', 'daily_cost_amount') ||
!$this->columnExists($this->prefix . 'purchased_miners', 'daily_cost_currency')
))
) {
$this->upgradeServerDailyCostColumns();
$applied[] = 'server_daily_cost_columns';
}
$settingsColumns = $this->existingColumns($this->prefix . 'settings', ['preferred_currencies', 'report_currency', 'crypto_currency', 'display_timezone', 'fx_max_age_hours', 'module_theme_mode', 'module_theme_accent']);
if (!in_array('preferred_currencies', $settingsColumns, true) || !in_array('report_currency', $settingsColumns, true) || !in_array('crypto_currency', $settingsColumns, true) || !in_array('display_timezone', $settingsColumns, true) || !in_array('fx_max_age_hours', $settingsColumns, true) || !in_array('module_theme_mode', $settingsColumns, true) || !in_array('module_theme_accent', $settingsColumns, true)) {
@@ -665,6 +678,19 @@ final class SchemaManager
}
}
foreach ([$this->prefix . 'cost_plans', $this->prefix . 'purchased_miners'] as $serverTable) {
if (
in_array($serverTable, $presentTables, true) &&
(
!$this->columnExists($serverTable, 'daily_cost_amount') ||
!$this->columnExists($serverTable, 'daily_cost_currency')
)
) {
$upgrades[] = 'server_daily_cost_columns';
break;
}
}
if ($this->tableExists($this->prefix . 'settings')) {
$requiredSettingsColumns = ['preferred_currencies', 'report_currency', 'crypto_currency', 'display_timezone', 'fx_max_age_hours', 'module_theme_mode', 'module_theme_accent'];
$existingSettingsColumns = $this->existingColumns($this->prefix . 'settings', $requiredSettingsColumns);
@@ -1252,6 +1278,8 @@ final class SchemaManager
usd_reference_amount NUMERIC(20,8),
reference_price_amount NUMERIC(20,8),
reference_price_currency VARCHAR(10),
daily_cost_amount NUMERIC(20,10),
daily_cost_currency VARCHAR(10),
auto_renew BOOLEAN NOT NULL DEFAULT FALSE,
note TEXT,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
@@ -1278,6 +1306,8 @@ final class SchemaManager
usd_reference_amount DECIMAL(20,8) NULL,
reference_price_amount DECIMAL(20,8) NULL,
reference_price_currency VARCHAR(10) NULL,
daily_cost_amount DECIMAL(20,10) NULL,
daily_cost_currency VARCHAR(10) NULL,
auto_renew TINYINT(1) NOT NULL DEFAULT 0,
note TEXT,
is_active TINYINT(1) NOT NULL DEFAULT 1,
@@ -1451,6 +1481,40 @@ final class SchemaManager
}
}
private function upgradeServerDailyCostColumns(): void
{
foreach ([$this->prefix . 'cost_plans', $this->prefix . 'purchased_miners'] as $table) {
if (!$this->tableExists($table)) {
continue;
}
$statements = $this->driver === 'pgsql'
? [
'ALTER TABLE ' . $table . ' ADD COLUMN IF NOT EXISTS daily_cost_amount NUMERIC(20,10)',
'ALTER TABLE ' . $table . ' ADD COLUMN IF NOT EXISTS daily_cost_currency VARCHAR(10)',
'UPDATE ' . $table . ' SET daily_cost_amount = ROUND((total_cost_amount / NULLIF(runtime_months * 30.4375, 0))::numeric, 10) WHERE daily_cost_amount IS NULL AND total_cost_amount IS NOT NULL AND runtime_months IS NOT NULL AND runtime_months > 0',
'UPDATE ' . $table . ' SET daily_cost_currency = COALESCE(daily_cost_currency, currency) WHERE currency IS NOT NULL',
]
: [
'ALTER TABLE `' . $table . '` ADD COLUMN daily_cost_amount DECIMAL(20,10) NULL',
'ALTER TABLE `' . $table . '` ADD COLUMN daily_cost_currency VARCHAR(10) NULL',
'UPDATE `' . $table . '` SET daily_cost_amount = ROUND(total_cost_amount / NULLIF(runtime_months * 30.4375, 0), 10) WHERE daily_cost_amount IS NULL AND total_cost_amount IS NOT NULL AND runtime_months IS NOT NULL AND runtime_months > 0',
'UPDATE `' . $table . '` SET daily_cost_currency = COALESCE(daily_cost_currency, currency) WHERE currency IS NOT NULL',
];
foreach ($statements as $statement) {
try {
$this->executeUpgradeStatements([$statement], 'Schema-Upgrade fuer Server-Tageskosten fehlgeschlagen.');
} catch (\Throwable $exception) {
if ($this->driver === 'mysql' && str_contains(strtolower($exception->getMessage()), 'duplicate column')) {
continue;
}
throw $exception;
}
}
}
}
private function upgradeTargetOfferColumn(): void
{
$table = $this->prefix . 'targets';