asdasd
This commit is contained in:
@@ -1016,7 +1016,21 @@
|
|||||||
? `Verwendet den letzten Upload von ${fmtDate(latest.measured_at)} mit ${fmtNumber(fullTransferCoins, 6)} ${currentMiningCurrency}.`
|
? `Verwendet den letzten Upload von ${fmtDate(latest.measured_at)} mit ${fmtNumber(fullTransferCoins, 6)} ${currentMiningCurrency}.`
|
||||||
: `Verwendet den letzten Upload von ${fmtDate(latest.measured_at)} mit ${fmtNumber(fullTransferCoins, 6)} ${currentMiningCurrency}. Backend erlaubt den Kompletttransfer nur, wenn dieser Upload hoechstens 3 Minuten alt ist.`;
|
: `Verwendet den letzten Upload von ${fmtDate(latest.measured_at)} mit ${fmtNumber(fullTransferCoins, 6)} ${currentMiningCurrency}. Backend erlaubt den Kompletttransfer nur, wenn dieser Upload hoechstens 3 Minuten alt ist.`;
|
||||||
const latestWalletSnapshot = currentWalletSnapshots.length ? currentWalletSnapshots[0] : null;
|
const latestWalletSnapshot = currentWalletSnapshots.length ? currentWalletSnapshots[0] : null;
|
||||||
const currentWalletMiningBalance = walletAssetBalance(latestWalletSnapshot, currentMiningCurrency);
|
const currentWalletPrimaryCurrency = (() => {
|
||||||
|
const snapshotCurrency = String((latestWalletSnapshot && latestWalletSnapshot.wallet_currency) || '').toUpperCase();
|
||||||
|
if (snapshotCurrency) {
|
||||||
|
return snapshotCurrency;
|
||||||
|
}
|
||||||
|
const latestWithdrawal = currentWalletWithdrawals.length ? currentWalletWithdrawals[currentWalletWithdrawals.length - 1] : null;
|
||||||
|
const latestWalletTransfer = currentPayouts.length ? currentPayouts[currentPayouts.length - 1] : null;
|
||||||
|
const ledgerCurrency = String(
|
||||||
|
(latestWithdrawal && latestWithdrawal.withdrawal_currency)
|
||||||
|
|| (latestWalletTransfer && latestWalletTransfer.payout_currency)
|
||||||
|
|| ''
|
||||||
|
).toUpperCase();
|
||||||
|
return ledgerCurrency || currentMiningCurrency || currentSettings.crypto_currency || 'DOGE';
|
||||||
|
})();
|
||||||
|
const currentWalletMiningBalance = walletPurchasingPower(latestWalletSnapshot, currentMiningCurrency);
|
||||||
const preferredCurrencyCodes = Array.isArray(currentSettings.preferred_currencies)
|
const preferredCurrencyCodes = Array.isArray(currentSettings.preferred_currencies)
|
||||||
? currentSettings.preferred_currencies.map((code) => String(code || '').toUpperCase()).filter(Boolean)
|
? currentSettings.preferred_currencies.map((code) => String(code || '').toUpperCase()).filter(Boolean)
|
||||||
: [];
|
: [];
|
||||||
@@ -1053,7 +1067,7 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedOfferType === 'crypto' && !isOfferAvailableForWallet(offer, currentMiningCurrency, currentWalletMiningBalance)) {
|
if (selectedOfferType === 'crypto' && !isOfferAvailableForWallet(offer, latestWalletSnapshot)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1075,7 +1089,7 @@
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
const scenarioMinerOffers = filteredMinerOffers.filter((offer) => isOfferAvailableForWallet(offer, currentMiningCurrency, currentWalletMiningBalance));
|
const scenarioMinerOffers = filteredMinerOffers.filter((offer) => isOfferAvailableForWallet(offer, latestWalletSnapshot));
|
||||||
const speedUnits = ['kH/s', 'MH/s'];
|
const speedUnits = ['kH/s', 'MH/s'];
|
||||||
const fiatCurrencies = currencies.filter((currency) => !currency.is_crypto);
|
const fiatCurrencies = currencies.filter((currency) => !currency.is_crypto);
|
||||||
const cryptoCurrencies = currencies.filter((currency) => !!currency.is_crypto);
|
const cryptoCurrencies = currencies.filter((currency) => !!currency.is_crypto);
|
||||||
@@ -1342,7 +1356,56 @@
|
|||||||
return Number.isFinite(balance) ? balance : null;
|
return Number.isFinite(balance) ? balance : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOfferAvailableForWallet(offer, miningCurrency, walletBalance) {
|
function walletPurchasingPower(snapshot, targetCurrency) {
|
||||||
|
const target = String(targetCurrency || '').toUpperCase();
|
||||||
|
if (!snapshot || !target) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const directBalance = walletAssetBalance(snapshot, target);
|
||||||
|
if (Number.isFinite(directBalance)) {
|
||||||
|
return directBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalValueAmount = Number(snapshot.total_value_amount);
|
||||||
|
const totalValueCurrency = String(snapshot.total_value_currency || '').toUpperCase();
|
||||||
|
if (Number.isFinite(totalValueAmount) && totalValueCurrency) {
|
||||||
|
const convertedTotal = convertCurrencyValue(totalValueAmount, totalValueCurrency, target);
|
||||||
|
if (Number.isFinite(convertedTotal)) {
|
||||||
|
return convertedTotal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const assets = snapshot.balances_json && typeof snapshot.balances_json === 'object' ? snapshot.balances_json : {};
|
||||||
|
let total = 0;
|
||||||
|
let matched = false;
|
||||||
|
for (const [assetCode, assetValue] of Object.entries(assets)) {
|
||||||
|
const normalizedCode = String(assetCode || '').toUpperCase();
|
||||||
|
const balance = Number(assetValue && typeof assetValue === 'object' ? assetValue.balance : assetValue);
|
||||||
|
const priceAmount = Number(assetValue && typeof assetValue === 'object' ? assetValue.price_amount : null);
|
||||||
|
const priceCurrency = String(assetValue && typeof assetValue === 'object' ? assetValue.price_currency : '').toUpperCase();
|
||||||
|
if (!normalizedCode || !Number.isFinite(balance) || balance <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (normalizedCode === target) {
|
||||||
|
total += balance;
|
||||||
|
matched = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Number.isFinite(priceAmount) && priceAmount > 0 && priceCurrency) {
|
||||||
|
const assetValueInPriceCurrency = balance * priceAmount;
|
||||||
|
const converted = convertCurrencyValue(assetValueInPriceCurrency, priceCurrency, target);
|
||||||
|
if (Number.isFinite(converted)) {
|
||||||
|
total += converted;
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched ? total : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOfferAvailableForWallet(offer, walletSnapshot) {
|
||||||
if (!offer || !offer.is_active) {
|
if (!offer || !offer.is_active) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1352,11 +1415,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const currency = String(offer.effective_price_currency || offer.price_currency || '').toUpperCase();
|
const currency = String(offer.effective_price_currency || offer.price_currency || '').toUpperCase();
|
||||||
const expectedCurrency = String(miningCurrency || '').toUpperCase();
|
|
||||||
const price = Number(offer.effective_price_amount);
|
const price = Number(offer.effective_price_amount);
|
||||||
const balance = Number(walletBalance);
|
const balance = Number(walletPurchasingPower(walletSnapshot, currency));
|
||||||
|
|
||||||
if (!currency || !expectedCurrency || currency !== expectedCurrency || !Number.isFinite(price) || !Number.isFinite(balance)) {
|
if (!currency || !Number.isFinite(price) || !Number.isFinite(balance)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1676,11 +1738,15 @@
|
|||||||
const preview = normalizeOcrPreview(ocrPreview);
|
const preview = normalizeOcrPreview(ocrPreview);
|
||||||
const raw = fromPreview ? {
|
const raw = fromPreview ? {
|
||||||
...preview.suggested,
|
...preview.suggested,
|
||||||
|
coin_currency: currentMiningCurrency,
|
||||||
image_path: preview.image_path,
|
image_path: preview.image_path,
|
||||||
ocr_raw_text: preview.raw_text,
|
ocr_raw_text: preview.raw_text,
|
||||||
ocr_confidence: preview.confidence,
|
ocr_confidence: preview.confidence,
|
||||||
ocr_flags: preview.flags,
|
ocr_flags: preview.flags,
|
||||||
} : measurementForm;
|
} : {
|
||||||
|
...measurementForm,
|
||||||
|
coin_currency: currentMiningCurrency,
|
||||||
|
};
|
||||||
|
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
setError('');
|
setError('');
|
||||||
@@ -1819,7 +1885,8 @@
|
|||||||
body.append('image', nextForm.image);
|
body.append('image', nextForm.image);
|
||||||
body.append('date_context', nextForm.date_context);
|
body.append('date_context', nextForm.date_context);
|
||||||
body.append('ocr_hint_text', nextForm.ocr_hint_text);
|
body.append('ocr_hint_text', nextForm.ocr_hint_text);
|
||||||
body.append('wallet_currency_hint', currentSettings.crypto_currency || 'DOGE');
|
body.append('wallet_currency_hint', currentWalletPrimaryCurrency);
|
||||||
|
body.append('mining_currency_hint', currentMiningCurrency);
|
||||||
const data = await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/ocr-preview`, {
|
const data = await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/ocr-preview`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body,
|
body,
|
||||||
@@ -2037,7 +2104,7 @@
|
|||||||
applySavedPayout(savedPayout);
|
applySavedPayout(savedPayout);
|
||||||
setWalletTransferRows((previous) => previous.filter((row) => String(row.id) !== String(savedPayout.id)).concat(savedPayout).sort((left, right) => String(left?.payout_at || '').localeCompare(String(right?.payout_at || ''))));
|
setWalletTransferRows((previous) => previous.filter((row) => String(row.id) !== String(savedPayout.id)).concat(savedPayout).sort((left, right) => String(left?.payout_at || '').localeCompare(String(right?.payout_at || ''))));
|
||||||
invalidateProjectBootstrapCache(projectKey);
|
invalidateProjectBootstrapCache(projectKey);
|
||||||
setPayoutForm({ payout_at: '', coins_amount: '', payout_currency: currentSettings.crypto_currency || 'DOGE', note: '' });
|
setPayoutForm({ payout_at: '', coins_amount: '', payout_currency: currentMiningCurrency, note: '' });
|
||||||
setPayoutModalOpen(false);
|
setPayoutModalOpen(false);
|
||||||
await reloadBootstrapAfterMutation('Wallet-Transfer gespeichert.');
|
await reloadBootstrapAfterMutation('Wallet-Transfer gespeichert.');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -2131,7 +2198,7 @@
|
|||||||
setWalletWithdrawalForm({
|
setWalletWithdrawalForm({
|
||||||
withdrawal_at: '',
|
withdrawal_at: '',
|
||||||
coins_amount: '',
|
coins_amount: '',
|
||||||
withdrawal_currency: currentSettings.crypto_currency || 'DOGE',
|
withdrawal_currency: currentWalletPrimaryCurrency,
|
||||||
note: '',
|
note: '',
|
||||||
});
|
});
|
||||||
setWalletWithdrawalModalOpen(false);
|
setWalletWithdrawalModalOpen(false);
|
||||||
@@ -2480,7 +2547,7 @@
|
|||||||
isWalletPreview
|
isWalletPreview
|
||||||
? h('div', { key: 'wallet-form', className: 'mc-two-col' }, [
|
? h('div', { key: 'wallet-form', className: 'mc-two-col' }, [
|
||||||
displayField('Erkannter Typ', 'Wallet-Snapshot'),
|
displayField('Erkannter Typ', 'Wallet-Snapshot'),
|
||||||
displayField('Mining-Waehrung im Wallet', `${fmtNumber(preview.suggested_wallet.wallet_balance, 8)} ${preview.suggested_wallet.wallet_currency || currentSettings.crypto_currency || 'DOGE'}`),
|
displayField('Wallet-Bestand', `${fmtNumber(preview.suggested_wallet.wallet_balance, 8)} ${preview.suggested_wallet.wallet_currency || currentWalletPrimaryCurrency}`),
|
||||||
displayField('Gesamtwert', preview.suggested_wallet.total_value_amount !== '' && preview.suggested_wallet.total_value_amount !== null
|
displayField('Gesamtwert', preview.suggested_wallet.total_value_amount !== '' && preview.suggested_wallet.total_value_amount !== null
|
||||||
? `${fmtNumber(preview.suggested_wallet.total_value_amount, 4)} ${preview.suggested_wallet.total_value_currency || ''}`.trim()
|
? `${fmtNumber(preview.suggested_wallet.total_value_amount, 4)} ${preview.suggested_wallet.total_value_currency || ''}`.trim()
|
||||||
: 'n/a'),
|
: 'n/a'),
|
||||||
@@ -2629,6 +2696,7 @@
|
|||||||
const breakEvenReached = breakEvenRemainingAmount !== null && breakEvenRemainingAmount <= 0;
|
const breakEvenReached = breakEvenRemainingAmount !== null && breakEvenRemainingAmount <= 0;
|
||||||
const breakEvenEta = latest && latest.break_even_eta_at ? fmtDate(latest.break_even_eta_at) : null;
|
const breakEvenEta = latest && latest.break_even_eta_at ? fmtDate(latest.break_even_eta_at) : null;
|
||||||
const walletBalanceCurrentAsset = payload?.summary?.payouts?.wallet_balance_current_asset;
|
const walletBalanceCurrentAsset = payload?.summary?.payouts?.wallet_balance_current_asset;
|
||||||
|
const walletBalanceCurrentAssetDirect = payload?.summary?.payouts?.wallet_balance_current_asset_direct;
|
||||||
const holdingsCurrentAsset = payload?.summary?.payouts?.holdings_current_asset;
|
const holdingsCurrentAsset = payload?.summary?.payouts?.holdings_current_asset;
|
||||||
|
|
||||||
return h('div', { className: 'mc-stack' }, [
|
return h('div', { className: 'mc-stack' }, [
|
||||||
@@ -2660,7 +2728,7 @@
|
|||||||
label: `Theoretischer Bestand ${currentCoinCurrency}`,
|
label: `Theoretischer Bestand ${currentCoinCurrency}`,
|
||||||
value: payload?.summary?.payouts ? fmtNumber(holdingsCurrentAsset, 6) : 'n/a',
|
value: payload?.summary?.payouts ? fmtNumber(holdingsCurrentAsset, 6) : 'n/a',
|
||||||
sub: payload?.summary?.payouts
|
sub: payload?.summary?.payouts
|
||||||
? `Wallet ${fmtNumber(walletBalanceCurrentAsset, 6)} ${currentCoinCurrency} · Miner ${fmtNumber(latest?.coins_total_visible ?? latest?.coins_total, 6)} ${currentCoinCurrency}`
|
? `Wallet-Gegenwert ${fmtNumber(walletBalanceCurrentAsset, 6)} ${currentCoinCurrency}${currentWalletPrimaryCurrency !== currentCoinCurrency ? ` · direkt ${fmtNumber(walletBalanceCurrentAssetDirect, 6)} ${currentCoinCurrency}` : ''} · Miner ${fmtNumber(latest?.coins_total_visible ?? latest?.coins_total, 6)} ${currentCoinCurrency}`
|
||||||
: '',
|
: '',
|
||||||
}),
|
}),
|
||||||
h(StatCard, {
|
h(StatCard, {
|
||||||
@@ -2944,7 +3012,7 @@
|
|||||||
setWalletWithdrawalForm((previous) => ({
|
setWalletWithdrawalForm((previous) => ({
|
||||||
withdrawal_at: previous.withdrawal_at || nowDateTimeLocalValue(),
|
withdrawal_at: previous.withdrawal_at || nowDateTimeLocalValue(),
|
||||||
coins_amount: previous.coins_amount || '',
|
coins_amount: previous.coins_amount || '',
|
||||||
withdrawal_currency: currentMiningCurrency,
|
withdrawal_currency: currentWalletPrimaryCurrency,
|
||||||
note: previous.note || '',
|
note: previous.note || '',
|
||||||
}));
|
}));
|
||||||
setWalletWithdrawalModalOpen(true);
|
setWalletWithdrawalModalOpen(true);
|
||||||
@@ -3117,7 +3185,7 @@
|
|||||||
]),
|
]),
|
||||||
panel('Miner-Angebote', selectedOfferType === 'crypto'
|
panel('Miner-Angebote', selectedOfferType === 'crypto'
|
||||||
? (currentWalletMiningBalance !== null
|
? (currentWalletMiningBalance !== null
|
||||||
? `Crypto-Angebote sind aktiv. Angezeigt werden nur Angebote, die dein NC-Wallet aktuell tragen kann (${fmtNumber(currentWalletMiningBalance, 8)} ${currentMiningCurrency}).`
|
? `Crypto-Angebote sind aktiv. Angezeigt werden nur Angebote, die dein NC-Wallet aktuell tragen kann (${fmtNumber(currentWalletMiningBalance, 8)} ${currentMiningCurrency} Gegenwert).`
|
||||||
: 'Crypto-Angebote sind aktiv. Solange kein Wallet-Bestand erkannt wird, bleiben die Krypto-Angebote sichtbar.')
|
: 'Crypto-Angebote sind aktiv. Solange kein Wallet-Bestand erkannt wird, bleiben die Krypto-Angebote sichtbar.')
|
||||||
: 'Fiat-Angebote sind aktiv. Die Berechnung startet erst, wenn du eine Geschwindigkeit eingibst.',
|
: 'Fiat-Angebote sind aktiv. Die Berechnung startet erst, wenn du eine Geschwindigkeit eingibst.',
|
||||||
[
|
[
|
||||||
@@ -3224,7 +3292,7 @@
|
|||||||
? h('div', { key: 'rec-ref', className: 'mc-kicker' }, `Basis ${fmtNumber(offer.base_price_amount, 6)} ${offer.base_price_currency}`)
|
? h('div', { key: 'rec-ref', className: 'mc-kicker' }, `Basis ${fmtNumber(offer.base_price_amount, 6)} ${offer.base_price_currency}`)
|
||||||
: null,
|
: null,
|
||||||
offer.payment_type ? h('div', { key: 'paytype', className: 'mc-kicker' }, offer.payment_type === 'crypto' ? `Zahlung in Krypto (${currentSettings.crypto_currency || 'DOGE'})` : `Zahlung in FIAT (${offer.base_price_currency || 'EUR'})`) : null,
|
offer.payment_type ? h('div', { key: 'paytype', className: 'mc-kicker' }, offer.payment_type === 'crypto' ? `Zahlung in Krypto (${currentSettings.crypto_currency || 'DOGE'})` : `Zahlung in FIAT (${offer.base_price_currency || 'EUR'})`) : null,
|
||||||
h('div', { key: 'availability', className: 'mc-kicker' }, isOfferAvailableForWallet(offer, currentMiningCurrency, currentWalletMiningBalance) ? 'Im NC Wallet verfuegbar' : 'Nicht genug NC Wallet Bestand'),
|
h('div', { key: 'availability', className: 'mc-kicker' }, isOfferAvailableForWallet(offer, latestWalletSnapshot) ? 'Im NC Wallet verfuegbar' : 'Nicht genug NC Wallet Bestand'),
|
||||||
h('div', { key: 'renew', className: 'mc-kicker' }, offer.auto_renew ? 'Automatische Verlängerung' : 'Laeuft aus'),
|
h('div', { key: 'renew', className: 'mc-kicker' }, offer.auto_renew ? 'Automatische Verlängerung' : 'Laeuft aus'),
|
||||||
]),
|
]),
|
||||||
h('td', { key: 'action' }, [
|
h('td', { key: 'action' }, [
|
||||||
@@ -3272,7 +3340,7 @@
|
|||||||
});
|
});
|
||||||
setPurchaseMinerModalOpen(true);
|
setPurchaseMinerModalOpen(true);
|
||||||
},
|
},
|
||||||
disabled: !isOfferAvailableForWallet(offer, currentMiningCurrency, currentWalletMiningBalance),
|
disabled: !isOfferAvailableForWallet(offer, latestWalletSnapshot),
|
||||||
}, 'Mieten'),
|
}, 'Mieten'),
|
||||||
]),
|
]),
|
||||||
]))
|
]))
|
||||||
@@ -3434,7 +3502,7 @@
|
|||||||
h('form', { key: 'form', className: 'mc-form', onSubmit: submitWalletWithdrawal }, [
|
h('form', { key: 'form', className: 'mc-form', onSubmit: submitWalletWithdrawal }, [
|
||||||
inputField('Auszahlungszeitpunkt', 'datetime-local', walletWithdrawalForm.withdrawal_at, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_at: value })),
|
inputField('Auszahlungszeitpunkt', 'datetime-local', walletWithdrawalForm.withdrawal_at, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_at: value })),
|
||||||
inputField('Coins', 'number', walletWithdrawalForm.coins_amount, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, coins_amount: value }), '0.000001'),
|
inputField('Coins', 'number', walletWithdrawalForm.coins_amount, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, coins_amount: value }), '0.000001'),
|
||||||
selectField('Waehrung', walletWithdrawalForm.withdrawal_currency, [currentMiningCurrency].concat(selectableCurrencies.map((currency) => currency.code).filter((code) => code !== currentMiningCurrency)), (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_currency: value })),
|
selectField('Waehrung', walletWithdrawalForm.withdrawal_currency, [currentWalletPrimaryCurrency].concat(selectableCurrencies.map((currency) => currency.code).filter((code) => code !== currentWalletPrimaryCurrency)), (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_currency: value })),
|
||||||
textareaField('Notiz', walletWithdrawalForm.note, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, note: value })),
|
textareaField('Notiz', walletWithdrawalForm.note, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, note: value })),
|
||||||
h('div', { className: 'mc-inline-row' }, [
|
h('div', { className: 'mc-inline-row' }, [
|
||||||
h('button', { type: 'button', className: 'mc-button mc-button--ghost', onClick: () => setWalletWithdrawalModalOpen(false) }, 'Abbrechen'),
|
h('button', { type: 'button', className: 'mc-button mc-button--ghost', onClick: () => setWalletWithdrawalModalOpen(false) }, 'Abbrechen'),
|
||||||
@@ -3656,7 +3724,7 @@
|
|||||||
h('form', { key: 'form', className: 'mc-form', onSubmit: submitWalletWithdrawal }, [
|
h('form', { key: 'form', className: 'mc-form', onSubmit: submitWalletWithdrawal }, [
|
||||||
inputField('Auszahlungszeitpunkt', 'datetime-local', walletWithdrawalForm.withdrawal_at, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_at: value })),
|
inputField('Auszahlungszeitpunkt', 'datetime-local', walletWithdrawalForm.withdrawal_at, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_at: value })),
|
||||||
inputField('Coins', 'number', walletWithdrawalForm.coins_amount, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, coins_amount: value }), '0.000001'),
|
inputField('Coins', 'number', walletWithdrawalForm.coins_amount, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, coins_amount: value }), '0.000001'),
|
||||||
selectField('Waehrung', walletWithdrawalForm.withdrawal_currency, [currentMiningCurrency].concat(selectableCurrencies.map((currency) => currency.code).filter((code) => code !== currentMiningCurrency)), (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_currency: value })),
|
selectField('Waehrung', walletWithdrawalForm.withdrawal_currency, [currentWalletPrimaryCurrency].concat(selectableCurrencies.map((currency) => currency.code).filter((code) => code !== currentWalletPrimaryCurrency)), (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_currency: value })),
|
||||||
textareaField('Notiz', walletWithdrawalForm.note, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, note: value })),
|
textareaField('Notiz', walletWithdrawalForm.note, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, note: value })),
|
||||||
h('div', { className: 'mc-inline-row' }, [
|
h('div', { className: 'mc-inline-row' }, [
|
||||||
h('button', { type: 'button', className: 'mc-button mc-button--ghost', onClick: () => setWalletWithdrawalModalOpen(false) }, 'Abbrechen'),
|
h('button', { type: 'button', className: 'mc-button mc-button--ghost', onClick: () => setWalletWithdrawalModalOpen(false) }, 'Abbrechen'),
|
||||||
|
|||||||
@@ -1262,8 +1262,10 @@ final class Router
|
|||||||
|
|
||||||
$this->assertCurrencyType($settings['report_currency'], false, 'report_currency');
|
$this->assertCurrencyType($settings['report_currency'], false, 'report_currency');
|
||||||
$this->assertCurrencyType($settings['crypto_currency'], true, 'crypto_currency');
|
$this->assertCurrencyType($settings['crypto_currency'], true, 'crypto_currency');
|
||||||
|
$currencyChange = $this->prepareMiningCurrencyChange($projectKey, $existingSettings, $settings);
|
||||||
|
|
||||||
$this->repository()->saveSettings($projectKey, $settings);
|
$this->repository()->saveSettings($projectKey, $settings);
|
||||||
|
$this->applyPreparedMiningCurrencyChange($projectKey, $currencyChange);
|
||||||
$this->syncFxRatesPreferredCurrencies($settings['preferred_currencies']);
|
$this->syncFxRatesPreferredCurrencies($settings['preferred_currencies']);
|
||||||
return $this->settings($projectKey);
|
return $this->settings($projectKey);
|
||||||
}
|
}
|
||||||
@@ -1973,12 +1975,17 @@ final class Router
|
|||||||
$balances = [];
|
$balances = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$walletCurrency = $this->optionalCurrency($input['wallet_currency'] ?? null)
|
||||||
|
?? $this->inferWalletCurrencyFromBalances($balances)
|
||||||
|
?? $this->latestWalletCurrency($projectKey)
|
||||||
|
?? 'DOGE';
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'measured_at' => $this->requiredDateTime($input['measured_at'] ?? null, 'measured_at', $this->projectTimezone($projectKey)),
|
'measured_at' => $this->requiredDateTime($input['measured_at'] ?? null, 'measured_at', $this->projectTimezone($projectKey)),
|
||||||
'total_value_amount' => $this->optionalDecimal($input['total_value_amount'] ?? null),
|
'total_value_amount' => $this->optionalDecimal($input['total_value_amount'] ?? null),
|
||||||
'total_value_currency' => $this->optionalCurrency($input['total_value_currency'] ?? null),
|
'total_value_currency' => $this->optionalCurrency($input['total_value_currency'] ?? null),
|
||||||
'wallet_balance' => $this->optionalDecimal($input['wallet_balance'] ?? null),
|
'wallet_balance' => $this->optionalDecimal($input['wallet_balance'] ?? null),
|
||||||
'wallet_currency' => $this->requiredCurrency($input['wallet_currency'] ?? ($this->settings($projectKey)['crypto_currency'] ?? 'DOGE'), 'wallet_currency'),
|
'wallet_currency' => $this->requiredCurrency($walletCurrency, 'wallet_currency'),
|
||||||
'balances_json' => $balances,
|
'balances_json' => $balances,
|
||||||
'note' => $this->optionalString($input['note'] ?? null, 1000),
|
'note' => $this->optionalString($input['note'] ?? null, 1000),
|
||||||
'source' => $this->enumValue($input['source'] ?? 'manual', ['manual', 'image_ocr', 'seed_import'], 'source'),
|
'source' => $this->enumValue($input['source'] ?? 'manual', ['manual', 'image_ocr', 'seed_import'], 'source'),
|
||||||
@@ -2002,10 +2009,14 @@ final class Router
|
|||||||
|
|
||||||
private function saveWalletWithdrawal(string $projectKey, array $input): array
|
private function saveWalletWithdrawal(string $projectKey, array $input): array
|
||||||
{
|
{
|
||||||
|
$withdrawalCurrency = $this->optionalCurrency($input['withdrawal_currency'] ?? null)
|
||||||
|
?? $this->latestWalletCurrency($projectKey)
|
||||||
|
?? 'DOGE';
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'withdrawal_at' => $this->requiredDateTime($input['withdrawal_at'] ?? null, 'withdrawal_at', $this->projectTimezone($projectKey)),
|
'withdrawal_at' => $this->requiredDateTime($input['withdrawal_at'] ?? null, 'withdrawal_at', $this->projectTimezone($projectKey)),
|
||||||
'coins_amount' => $this->requiredDecimal($input['coins_amount'] ?? null, 'coins_amount'),
|
'coins_amount' => $this->requiredDecimal($input['coins_amount'] ?? null, 'coins_amount'),
|
||||||
'withdrawal_currency' => $this->requiredCurrency($input['withdrawal_currency'] ?? 'DOGE', 'withdrawal_currency'),
|
'withdrawal_currency' => $this->requiredCurrency($withdrawalCurrency, 'withdrawal_currency'),
|
||||||
'note' => $this->optionalString($input['note'] ?? null, 1000),
|
'note' => $this->optionalString($input['note'] ?? null, 1000),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -2765,6 +2776,177 @@ final class Router
|
|||||||
return $this->requiredCurrency($settings['crypto_currency'] ?? 'DOGE', 'crypto_currency');
|
return $this->requiredCurrency($settings['crypto_currency'] ?? 'DOGE', 'crypto_currency');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function prepareMiningCurrencyChange(string $projectKey, array $existingSettings, array &$nextSettings): ?array
|
||||||
|
{
|
||||||
|
$previousCurrency = $this->requiredCurrency($existingSettings['crypto_currency'] ?? ($nextSettings['crypto_currency'] ?? 'DOGE'), 'crypto_currency');
|
||||||
|
$nextCurrency = $this->requiredCurrency($nextSettings['crypto_currency'] ?? 'DOGE', 'crypto_currency');
|
||||||
|
if ($previousCurrency === $nextCurrency) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestMeasurement = $this->repository()->listRecentMeasurements($projectKey, 1)[0] ?? null;
|
||||||
|
$fetchId = null;
|
||||||
|
try {
|
||||||
|
$fresh = $this->fx()->refreshLatestRates(null, 'USD');
|
||||||
|
$fetchId = is_numeric($fresh['fetch_id'] ?? null) ? (int) $fresh['fetch_id'] : null;
|
||||||
|
} catch (\Throwable) {
|
||||||
|
$fetchId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$baselineAmount = $this->optionalDecimal($nextSettings['baseline_coins_total'] ?? null);
|
||||||
|
if ($baselineAmount !== null && $baselineAmount > 0) {
|
||||||
|
$convertedBaseline = $this->convertMiningAssetAmount(
|
||||||
|
$baselineAmount,
|
||||||
|
$previousCurrency,
|
||||||
|
$nextCurrency,
|
||||||
|
(string) ($nextSettings['baseline_measured_at'] ?? $existingSettings['baseline_measured_at'] ?? ''),
|
||||||
|
$fetchId
|
||||||
|
);
|
||||||
|
if ($convertedBaseline === null) {
|
||||||
|
throw new ApiException('Baseline konnte nicht in die neue Mining-Waehrung umgerechnet werden.', 422, [
|
||||||
|
'from_currency' => $previousCurrency,
|
||||||
|
'to_currency' => $nextCurrency,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$nextSettings['baseline_coins_total'] = $convertedBaseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'previous_currency' => $previousCurrency,
|
||||||
|
'next_currency' => $nextCurrency,
|
||||||
|
'latest_measurement' => is_array($latestMeasurement) ? $latestMeasurement : null,
|
||||||
|
'fetch_id' => $fetchId,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyPreparedMiningCurrencyChange(string $projectKey, ?array $change): void
|
||||||
|
{
|
||||||
|
if (!is_array($change)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestMeasurement = is_array($change['latest_measurement'] ?? null) ? $change['latest_measurement'] : null;
|
||||||
|
if (!is_array($latestMeasurement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceCurrency = $this->requiredCurrency($latestMeasurement['coin_currency'] ?? ($change['previous_currency'] ?? null), 'coin_currency');
|
||||||
|
$targetCurrency = $this->requiredCurrency($change['next_currency'] ?? null, 'crypto_currency');
|
||||||
|
if ($sourceCurrency === $targetCurrency) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$visibleCoins = $this->optionalDecimal($latestMeasurement['coins_total'] ?? null) ?? 0.0;
|
||||||
|
$convertedCoins = $this->convertMiningAssetAmount(
|
||||||
|
$visibleCoins,
|
||||||
|
$sourceCurrency,
|
||||||
|
$targetCurrency,
|
||||||
|
(string) ($latestMeasurement['measured_at'] ?? $this->currentTimestamp()),
|
||||||
|
is_numeric($change['fetch_id'] ?? null) ? (int) $change['fetch_id'] : null
|
||||||
|
);
|
||||||
|
if ($convertedCoins === null) {
|
||||||
|
throw new ApiException('Aktueller Miner-Bestand konnte nicht in die neue Mining-Waehrung umgerechnet werden.', 422, [
|
||||||
|
'from_currency' => $sourceCurrency,
|
||||||
|
'to_currency' => $targetCurrency,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$priceCurrency = $this->optionalCurrency($latestMeasurement['price_currency'] ?? null) ?? 'USD';
|
||||||
|
$convertedPricePerCoin = $this->convertMiningAssetAmount(
|
||||||
|
1.0,
|
||||||
|
$targetCurrency,
|
||||||
|
$priceCurrency,
|
||||||
|
$this->currentTimestamp(),
|
||||||
|
is_numeric($change['fetch_id'] ?? null) ? (int) $change['fetch_id'] : null
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->repository()->createMeasurement($projectKey, [
|
||||||
|
'measured_at' => $this->currentTimestamp(),
|
||||||
|
'coins_total' => $convertedCoins,
|
||||||
|
'coin_currency' => $targetCurrency,
|
||||||
|
'price_per_coin' => $convertedPricePerCoin,
|
||||||
|
'price_currency' => $priceCurrency,
|
||||||
|
'fx_fetch_id' => is_numeric($change['fetch_id'] ?? null) ? (int) $change['fetch_id'] : null,
|
||||||
|
'note' => sprintf(
|
||||||
|
'Mining-Waehrung umgestellt: %s -> %s. Vorhandener Miner-Bestand wurde automatisch umgerechnet.',
|
||||||
|
$sourceCurrency,
|
||||||
|
$targetCurrency
|
||||||
|
),
|
||||||
|
'source' => 'manual',
|
||||||
|
'image_path' => null,
|
||||||
|
'ocr_raw_text' => null,
|
||||||
|
'ocr_confidence' => null,
|
||||||
|
'ocr_flags' => ['currency_change'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function convertMiningAssetAmount(float $amount, string $fromCurrency, string $toCurrency, string $at = '', ?int $fetchId = null): ?float
|
||||||
|
{
|
||||||
|
if ($amount === 0.0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$from = $this->requiredCurrency($fromCurrency, 'from_currency');
|
||||||
|
$to = $this->requiredCurrency($toCurrency, 'to_currency');
|
||||||
|
if ($from === $to) {
|
||||||
|
return $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$converted = $this->fx()->convertAt(
|
||||||
|
$amount,
|
||||||
|
$from,
|
||||||
|
$to,
|
||||||
|
$at !== '' ? $at : null,
|
||||||
|
null,
|
||||||
|
$fetchId
|
||||||
|
);
|
||||||
|
|
||||||
|
return is_numeric($converted) ? (float) $converted : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function latestWalletCurrency(string $projectKey): ?string
|
||||||
|
{
|
||||||
|
$latestSnapshot = $this->repository()->listWalletSnapshots($projectKey, 1)[0] ?? null;
|
||||||
|
$snapshotCurrency = $this->optionalCurrency(is_array($latestSnapshot) ? ($latestSnapshot['wallet_currency'] ?? null) : null);
|
||||||
|
if ($snapshotCurrency !== null) {
|
||||||
|
return $snapshotCurrency;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->repository()->tableExists('wallet_withdrawals')) {
|
||||||
|
$withdrawals = $this->repository()->listWalletWithdrawals($projectKey);
|
||||||
|
if ($withdrawals !== []) {
|
||||||
|
$withdrawalCurrency = $this->optionalCurrency($withdrawals[array_key_last($withdrawals)]['withdrawal_currency'] ?? null);
|
||||||
|
if ($withdrawalCurrency !== null) {
|
||||||
|
return $withdrawalCurrency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$payouts = $this->repository()->listPayouts($projectKey);
|
||||||
|
if ($payouts !== []) {
|
||||||
|
return $this->optionalCurrency($payouts[array_key_last($payouts)]['payout_currency'] ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function inferWalletCurrencyFromBalances(array $balances): ?string
|
||||||
|
{
|
||||||
|
foreach ($balances as $code => $asset) {
|
||||||
|
$currency = $this->optionalCurrency($code);
|
||||||
|
if ($currency === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$balance = is_array($asset) ? ($asset['balance'] ?? null) : $asset;
|
||||||
|
if (is_numeric($balance)) {
|
||||||
|
return $currency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private function ensureMeasurementFxReferences(string $projectKey, array $rows, ?array $settings = null): array
|
private function ensureMeasurementFxReferences(string $projectKey, array $rows, ?array $settings = null): array
|
||||||
{
|
{
|
||||||
$maxAgeHours = self::FX_FETCH_MAX_AGE_HOURS;
|
$maxAgeHours = self::FX_FETCH_MAX_AGE_HOURS;
|
||||||
|
|||||||
@@ -429,8 +429,15 @@ final class AnalyticsService
|
|||||||
$postMeasurementPayoutAmount = $this->postMeasurementPayoutAmount($payouts, $latestMeasuredTs, $latestAsset);
|
$postMeasurementPayoutAmount = $this->postMeasurementPayoutAmount($payouts, $latestMeasuredTs, $latestAsset);
|
||||||
$visibleCoinsAtMeasurement = (float) ($latest['coins_total_visible'] ?? $latest['coins_total'] ?? 0.0);
|
$visibleCoinsAtMeasurement = (float) ($latest['coins_total_visible'] ?? $latest['coins_total'] ?? 0.0);
|
||||||
$adjustedVisibleCoins = max(0.0, $visibleCoinsAtMeasurement - $postMeasurementPayoutAmount);
|
$adjustedVisibleCoins = max(0.0, $visibleCoinsAtMeasurement - $postMeasurementPayoutAmount);
|
||||||
$walletBalanceCurrentAsset = (float) ($walletBalances[$latestAsset] ?? 0.0);
|
$walletBalanceCurrentAssetDirect = (float) ($walletBalances[$latestAsset] ?? 0.0);
|
||||||
$holdingsCurrentAsset = $walletBalanceCurrentAsset + $adjustedVisibleCoins;
|
$walletBalanceCurrentAssetEquivalent = $latestAsset !== ''
|
||||||
|
? (
|
||||||
|
$useWalletSnapshot
|
||||||
|
? $this->walletSnapshotValue($latestWalletSnapshot, $latestAsset, $latest)
|
||||||
|
: $this->walletBalanceValue($walletBalances, $latestAsset, $latest)
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
$holdingsCurrentAsset = ($walletBalanceCurrentAssetEquivalent !== null ? $walletBalanceCurrentAssetEquivalent : 0.0) + $adjustedVisibleCoins;
|
||||||
$walletValue = $latestCurrency !== ''
|
$walletValue = $latestCurrency !== ''
|
||||||
? (
|
? (
|
||||||
$useWalletSnapshot
|
$useWalletSnapshot
|
||||||
@@ -478,7 +485,8 @@ final class AnalyticsService
|
|||||||
'invested_capital' => $this->roundOrNull($cashInvestedCapital, 8),
|
'invested_capital' => $this->roundOrNull($cashInvestedCapital, 8),
|
||||||
'cash_invested_capital' => $this->roundOrNull($cashInvestedCapital, 8),
|
'cash_invested_capital' => $this->roundOrNull($cashInvestedCapital, 8),
|
||||||
'reinvested_capital' => $this->roundOrNull($reinvestedCapital, 8),
|
'reinvested_capital' => $this->roundOrNull($reinvestedCapital, 8),
|
||||||
'wallet_balance_current_asset' => $this->roundOrNull($walletBalanceCurrentAsset, 6),
|
'wallet_balance_current_asset' => $this->roundOrNull($walletBalanceCurrentAssetEquivalent, 6),
|
||||||
|
'wallet_balance_current_asset_direct' => $this->roundOrNull($walletBalanceCurrentAssetDirect, 6),
|
||||||
'holdings_current_asset' => $this->roundOrNull($holdingsCurrentAsset, 6),
|
'holdings_current_asset' => $this->roundOrNull($holdingsCurrentAsset, 6),
|
||||||
'wallet_value' => $this->roundOrNull($walletValue, 8),
|
'wallet_value' => $this->roundOrNull($walletValue, 8),
|
||||||
'wallet_snapshot_measured_at' => $useWalletSnapshot ? (string) ($latestWalletSnapshot['measured_at'] ?? '') : null,
|
'wallet_snapshot_measured_at' => $useWalletSnapshot ? (string) ($latestWalletSnapshot['measured_at'] ?? '') : null,
|
||||||
@@ -533,7 +541,8 @@ final class AnalyticsService
|
|||||||
'current_visible_coins' => $this->roundOrNull($adjustedVisibleCoins, 6),
|
'current_visible_coins' => $this->roundOrNull($adjustedVisibleCoins, 6),
|
||||||
'current_effective_coins' => $this->roundOrNull((float) ($latest['coins_total_effective'] ?? $latest['coins_total']), 6),
|
'current_effective_coins' => $this->roundOrNull((float) ($latest['coins_total_effective'] ?? $latest['coins_total']), 6),
|
||||||
'wallet_balances' => $walletBalances,
|
'wallet_balances' => $walletBalances,
|
||||||
'wallet_balance_current_asset' => $this->roundOrNull($walletBalanceCurrentAsset, 6),
|
'wallet_balance_current_asset' => $this->roundOrNull($walletBalanceCurrentAssetEquivalent, 6),
|
||||||
|
'wallet_balance_current_asset_direct' => $this->roundOrNull($walletBalanceCurrentAssetDirect, 6),
|
||||||
'holdings_current_asset' => $this->roundOrNull($holdingsCurrentAsset, 6),
|
'holdings_current_asset' => $this->roundOrNull($holdingsCurrentAsset, 6),
|
||||||
],
|
],
|
||||||
'current_hashrate_mh' => $this->roundOrNull($currentHashrateMh, 4),
|
'current_hashrate_mh' => $this->roundOrNull($currentHashrateMh, 4),
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ final class OcrService
|
|||||||
$parsed = $this->parseText(
|
$parsed = $this->parseText(
|
||||||
$rawText,
|
$rawText,
|
||||||
(string) ($input['date_context'] ?? date('Y-m-d')),
|
(string) ($input['date_context'] ?? date('Y-m-d')),
|
||||||
strtoupper(trim((string) ($input['wallet_currency_hint'] ?? '')))
|
strtoupper(trim((string) ($input['wallet_currency_hint'] ?? ''))),
|
||||||
|
strtoupper(trim((string) ($input['mining_currency_hint'] ?? '')))
|
||||||
);
|
);
|
||||||
$parsed['image_path'] = $targetFile;
|
$parsed['image_path'] = $targetFile;
|
||||||
$parsed['raw_text'] = $rawText;
|
$parsed['raw_text'] = $rawText;
|
||||||
@@ -295,9 +296,9 @@ final class OcrService
|
|||||||
return $binary !== '' && trim((string) shell_exec('command -v ' . escapeshellarg($binary) . ' 2>/dev/null')) !== '';
|
return $binary !== '' && trim((string) shell_exec('command -v ' . escapeshellarg($binary) . ' 2>/dev/null')) !== '';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseText(string $rawText, string $dateContext, string $walletCurrencyHint = ''): array
|
private function parseText(string $rawText, string $dateContext, string $walletCurrencyHint = '', string $miningCurrencyHint = ''): array
|
||||||
{
|
{
|
||||||
$measurement = $this->parseMeasurementText($rawText, $dateContext);
|
$measurement = $this->parseMeasurementText($rawText, $dateContext, $miningCurrencyHint);
|
||||||
$wallet = $this->parseWalletText($rawText, $dateContext, $walletCurrencyHint);
|
$wallet = $this->parseWalletText($rawText, $dateContext, $walletCurrencyHint);
|
||||||
|
|
||||||
$isWallet = ($wallet['score'] ?? 0) > ($measurement['score'] ?? 0)
|
$isWallet = ($wallet['score'] ?? 0) > ($measurement['score'] ?? 0)
|
||||||
@@ -315,7 +316,7 @@ final class OcrService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseMeasurementText(string $rawText, string $dateContext): array
|
private function parseMeasurementText(string $rawText, string $dateContext, string $miningCurrencyHint = ''): array
|
||||||
{
|
{
|
||||||
$flags = [];
|
$flags = [];
|
||||||
$suggestedTime = null;
|
$suggestedTime = null;
|
||||||
@@ -352,7 +353,11 @@ final class OcrService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match('/DOGE\s*\/\s*(USD|EUR|USDT|USDC|BTC|ETH|LTC)/i', $normalizedText, $pairMatch)) {
|
$assetPattern = $miningCurrencyHint !== ''
|
||||||
|
? preg_quote($miningCurrencyHint, '/')
|
||||||
|
: '(?:DOGE|BTC|ETH|LTC|XRP|ADA|SOL|USDT|USDC|TRX|XMR|DOT|ARB|BNB|AVAX|MATIC)';
|
||||||
|
|
||||||
|
if (preg_match('/' . $assetPattern . '\s*\/\s*(USD|EUR|USDT|USDC|BTC|ETH|LTC)/i', $normalizedText, $pairMatch)) {
|
||||||
$currency = strtoupper((string) $pairMatch[1]);
|
$currency = strtoupper((string) $pairMatch[1]);
|
||||||
} elseif (preg_match('/\b(EUR|USD|USDT|USDC|BTC|ETH|LTC)\b/i', $normalizedText, $currencyMatch)) {
|
} elseif (preg_match('/\b(EUR|USD|USDT|USDC|BTC|ETH|LTC)\b/i', $normalizedText, $currencyMatch)) {
|
||||||
$currency = strtoupper((string) $currencyMatch[1]);
|
$currency = strtoupper((string) $currencyMatch[1]);
|
||||||
@@ -362,7 +367,7 @@ final class OcrService
|
|||||||
$flags[] = 'currency_missing';
|
$flags[] = 'currency_missing';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match('/DOGE\s*\/\s*(?:USD|EUR|USDT|USDC|BTC|ETH|LTC)[^\d]{0,20}(\d+[.,]\d{3,8})/i', $normalizedText, $priceMatch)) {
|
if (preg_match('/' . $assetPattern . '\s*\/\s*(?:USD|EUR|USDT|USDC|BTC|ETH|LTC)[^\d]{0,20}(\d+[.,]\d{3,8})/i', $normalizedText, $priceMatch)) {
|
||||||
$price = round((float) str_replace(',', '.', $priceMatch[1]), 8);
|
$price = round((float) str_replace(',', '.', $priceMatch[1]), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,7 +385,7 @@ final class OcrService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($coinsTotal === null && preg_match('/(\d+[.,]\d{4,8})\s*(?:DOGE)?\s*(?:MINING[- ]?GUTHABEN|MINING[- ]?BALANCE|GUTHABEN|BALANCE)/i', $normalizedText, $coinsMatch)) {
|
if ($coinsTotal === null && preg_match('/(\d+[.,]\d{4,8})\s*(?:' . $assetPattern . ')?\s*(?:MINING[- ]?GUTHABEN|MINING[- ]?BALANCE|GUTHABEN|BALANCE)/i', $normalizedText, $coinsMatch)) {
|
||||||
$coinsTotal = round((float) str_replace(',', '.', $coinsMatch[1]), 6);
|
$coinsTotal = round((float) str_replace(',', '.', $coinsMatch[1]), 6);
|
||||||
$flags[] = 'coins_from_balance_context';
|
$flags[] = 'coins_from_balance_context';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user