Skip to content

Instantly share code, notes, and snippets.

@Windowsfreak
Last active November 7, 2025 16:29
Show Gist options
  • Select an option

  • Save Windowsfreak/1dbff9f948f3629a1613b5f7d10ead74 to your computer and use it in GitHub Desktop.

Select an option

Save Windowsfreak/1dbff9f948f3629a1613b5f7d10ead74 to your computer and use it in GitHub Desktop.
Aurum-Verdienstrechner mit jährlicher Steuerauswertung
(function(){
let targetFinal = {
main: 0,
affiliate: 0,
invest: 0
};
let hideCreditCard = false;
let correctionsText = "";
class AurumCryptor {
#password;
#iterations;
#encoder;
#decoder;
constructor(password, iterations = 150000) {
if (!password) {
throw new Error("Password is required for key derivation");
}
this.#password = password;
this.#iterations = iterations;
this.#encoder = new TextEncoder();
this.#decoder = new TextDecoder();
}
async deriveKey(salt) {
const baseKey = await window.crypto.subtle.importKey(
"raw",
this.#encoder.encode(this.#password),
"PBKDF2",
false,
["deriveKey"]
);
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: this.#iterations,
hash: "SHA-256"
},
baseKey,
{
name: "AES-GCM",
length: 256
},
false,
["encrypt", "decrypt"]
);
}
async decode(encryptedBase64) {
const encryptedBytes = Uint8Array.from(atob(encryptedBase64), (char) => char.charCodeAt(0));
const salt = encryptedBytes.slice(0, 16);
const iv = encryptedBytes.slice(16, 28);
const ciphertext = encryptedBytes.slice(28);
const aesKey = await this.deriveKey(salt);
const decryptedBytes = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv
},
aesKey,
ciphertext
);
return this.#decoder.decode(decryptedBytes);
}
async encode(data) {
const dataStr = JSON.stringify(data);
const salt = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const aesKey = await this.deriveKey(salt);
const encrypted = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
aesKey,
this.#encoder.encode(dataStr)
);
const combined = new Uint8Array(salt.length + iv.length + encrypted.byteLength);
combined.set(salt, 0);
combined.set(iv, salt.length);
combined.set(new Uint8Array(encrypted), salt.length + iv.length);
return btoa(String.fromCharCode(...combined));
}
}
const cryptor = new AurumCryptor("default-password");
async function renderForm() {
const section = document.getElementsByTagName("section")[0];
const token = localStorage.getItem("token");
if (!token) {
section.innerHTML = `<b>Fehler:</b> No token found in localStorage.`;
return;
}
const headers = {
"Accept": "application/json",
"Authorization": `Bearer ${token}`
};
try {
const mainResp = await fetch('https://api.aurum.foundation/', { headers });
let mainRaw = await mainResp.json();
let mainData;
if (mainRaw.encrypted) {
const decryptedMainStr = await cryptor.decode(mainRaw.encrypted);
mainData = JSON.parse(decryptedMainStr);
} else {
mainData = mainRaw;
}
targetFinal.main = parseFloat(mainData.balance?.total.replace(' ', '') || '0');
const partnerResp = await fetch('https://api.aurum.foundation/partners', { headers });
let partnerRaw = await partnerResp.json();
let partnerData;
if (partnerRaw.encrypted) {
const decryptedPartnerStr = await cryptor.decode(partnerRaw.encrypted);
partnerData = JSON.parse(decryptedPartnerStr);
} else {
partnerData = partnerRaw;
}
targetFinal.affiliate = parseFloat(partnerData.partnerBalance.replace(' ', '') || '0');
const investResp = await fetch('https://api.aurum.foundation/investments', { headers });
let investRaw = await investResp.json();
let investData;
if (investRaw.encrypted) {
const decryptedInvestStr = await cryptor.decode(investRaw.encrypted);
investData = JSON.parse(decryptedInvestStr);
} else {
investData = investRaw;
}
const deposit = parseFloat(investData.balance?.totalDeposit.replace(' ', '') || '0');
const tokenBal = parseFloat(investData.balance?.tokenBalance.replace(' ', '') || '0');
targetFinal.invest = deposit + tokenBal;
} catch (e) {
console.error('Failed to fetch balances:', e);
targetFinal = { main: 0, affiliate: 0, invest: 0 };
}
section.innerHTML = `
<form id="configForm">
<label>Main Balance: <input type="number" step="0.01" name="main" value="${targetFinal.main.toFixed(2)}" required class="min-h-12 w-full text-[17px] rounded-[12px] border-2 bg-bg-color-input py-2 px-3 text-text-color-primary outline-hidden placeholder:text-text-color-placeholder pr-[145px]" placeholder="0.00"></label><br>
<label>Affiliate Balance: <input type="number" step="0.01" name="affiliate" value="${targetFinal.affiliate.toFixed(2)}" required class="min-h-12 w-full text-[17px] rounded-[12px] border-2 bg-bg-color-input py-2 px-3 text-text-color-primary outline-hidden placeholder:text-text-color-placeholder pr-[145px]" placeholder="0.00"></label><br>
<label>Invest Balance: <input type="number" step="0.01" name="invest" value="${targetFinal.invest.toFixed(2)}" required class="min-h-12 w-full text-[17px] rounded-[12px] border-2 bg-bg-color-input py-2 px-3 text-text-color-primary outline-hidden placeholder:text-text-color-placeholder pr-[145px]" placeholder="0.00"></label><br>
<label>Positionen korrigieren:<br><textarea name="corrections" rows="4" cols="50" class="min-h-24 w-full text-[17px] rounded-[12px] border-2 bg-bg-color-input py-2 px-3 text-text-color-primary outline-hidden placeholder:text-text-color-placeholder" placeholder="Beispiel:\n2020-06-25 16:18\n2020-06-26 17:30 DIVIDEND 420.69"></textarea></label><br>
<label><input type="checkbox" name="hideCreditCard"> Kreditkarte verstecken</label><br>
<button type="submit" id="submitBtn" class="text-sm flex gap-2 items-center font-medium font-geologica justify-center rounded-[12px] px-4 py-2.5 transition duration-300 ease-in-out focus:outline-hidden bg-bg-color-main-theme-deep text-white md:hover:bg-bg-color-main-theme-dark">Bestätigen und Bericht generieren</button>
</form>
`;
const form = document.getElementById("configForm");
form.addEventListener("submit", async (e) => {
e.preventDefault();
// Disable button and show loading state
const submitBtn = document.getElementById("submitBtn");
submitBtn.disabled = true;
submitBtn.className = "hover:cursor-not-allowed bg-bg-color-input hover:bg-bg-color-input text-text-color-placeholder text-sm flex gap-2 items-center font-medium font-geologica justify-center rounded-[12px] px-4 py-2.5 transition duration-300 ease-in-out focus:outline-hidden";
submitBtn.textContent = "Transaktionen werden abgerufen... 0%";
// Remove menu for full screen view
const menu = document.getElementsByTagName('aside');
if (menu.length > 0)
menu[0].parentNode.remove();
const formData = new FormData(form);
targetFinal = {
main: parseFloat(formData.get("main")),
affiliate: parseFloat(formData.get("affiliate")),
invest: parseFloat(formData.get("invest"))
};
hideCreditCard = formData.get("hideCreditCard") === "on";
correctionsText = formData.get("corrections") || "";
try {
const payments = await fetchAllPayments();
const history = buildHistory(payments, targetFinal);
section.innerHTML = renderTable(history) + renderFinancialReport(history);
const lastRow = history[history.length - 1];
function approxEqual(a, b, t = 0.001) { return Math.abs(a - b) < t; }
if (approxEqual(lastRow.main, targetFinal.main) &&
approxEqual(lastRow.invest, targetFinal.invest) &&
approxEqual(lastRow.affiliate, targetFinal.affiliate)) {
section.insertAdjacentHTML('beforeend', `<p style="color:green; font-weight:bold;">Abrechnung stimmt auf den Cent genau.</p>`);
} else {
section.insertAdjacentHTML('beforeend', `<p style="color:red; font-weight:bold;">Es gibt Abweichungen mit dem Endergebnis.</p>`);
section.insertAdjacentHTML('beforeend', `
<table class="w-full mt-2" style="border-collapse: collapse;">
<thead>
<tr>
<th class="py-2 px-2 text-left">Konto</th>
<th class="py-2 px-2 text-right">Soll</th>
<th class="py-2 px-2 text-right">Ist</th>
</tr>
</thead>
<tbody>
<tr>
<td>Main</td>
<td class="text-right">${lastRow.main.toFixed(2)}</td>
<td class="text-right">${targetFinal.main.toFixed(2)}</td>
</tr>
<tr>
<td>Invest</td>
<td class="text-right">${lastRow.invest.toFixed(2)}</td>
<td class="text-right">${targetFinal.invest.toFixed(2)}</td>
</tr>
<tr>
<td>Affiliate</td>
<td class="text-right">${lastRow.affiliate.toFixed(2)}</td>
<td class="text-right">${targetFinal.affiliate.toFixed(2)}</td>
</tr>
</tbody>
</table>
`);
}
} catch (e) {
section.innerHTML = `<b>Fehler:</b> ${e.message}`;
}
});
}
async function fetchAllPayments() {
const token = localStorage.getItem("token");
if (!token) throw new Error("No token found in localStorage.");
const headers = {
"Accept": "application/json",
"Authorization": `Bearer ${token}`
};
let all = [];
for (let page = 0; ; ++page) {
const resp = await fetch(`https://api.aurum.foundation/payments?limit=30&page=${page}`, { headers });
if (!resp.ok) throw new Error("Fetch failed: " + resp.status);
let jsonRaw = await resp.json();
let json;
if (jsonRaw.encrypted) {
const decryptedJsonStr = await cryptor.decode(jsonRaw.encrypted);
json = JSON.parse(decryptedJsonStr);
} else {
json = jsonRaw;
}
// Update progress in button
const submitBtn = document.getElementById("submitBtn");
if (submitBtn && json.pages > 0) {
const progress = Math.round(((page + 1) / json.pages) * 100);
submitBtn.textContent = `Transaktionen werden abgerufen... ${progress}%`;
}
all = all.concat(json.payments || []);
if (json.page >= json.pages) break;
}
// Filter out unsupported currencies
all = all.filter(tx => {
const supportedTickers = ['USDT', 'USDC'];
const tickerOk = !tx.ticker || supportedTickers.includes(tx.ticker);
const cryptoTickerOk = !tx.cryptoTicker || supportedTickers.includes(tx.cryptoTicker);
return tickerOk && cryptoTickerOk;
});
// Filter out rejected card recharges
all = all.filter(tx => !(tx.kind === "CARD_RECHARGE" && tx.statusName === "transactions:REJECTED"));
return all;
}
function buildHistory(payments, targetBalances) {
// Parse corrections from textarea
const corrections = parseCorrections(correctionsText);
// Sort payments chronologically (oldest first)
const paymentsChrono = [...payments].sort((a, b) => new Date(a.date) - new Date(b.date));
// Apply corrections - filter out unwanted entries and add synthetic ones
let filteredPayments = [];
for (const tx of paymentsChrono) {
const correction = corrections.find(c => c.date === tx.date);
if (correction && !correction.synthetic) {
// Skip this transaction
continue;
}
filteredPayments.push(tx);
}
// Add synthetic transactions
for (const correction of corrections) {
if (correction.synthetic) {
const syntheticTx = {
date: correction.date,
kind: correction.kind,
amount: correction.amount.toString(),
};
// Insert in correct chronological position
const insertIndex = filteredPayments.findIndex(tx => new Date(tx.date) > new Date(correction.date));
if (insertIndex === -1) {
filteredPayments.push(syntheticTx);
} else {
filteredPayments.splice(insertIndex, 0, syntheticTx);
}
}
}
const paymentsReversed = [...filteredPayments].reverse();
let reversedState = {
main: targetBalances.main,
invest: targetBalances.invest,
affiliate: targetBalances.affiliate,
card: 0,
profit: 0,
provision: 0,
totalCosts: 0
};
let totalProfit = 0;
let totalProvision = 0;
for (let i = paymentsReversed.length - 1; i >= 0; --i) {
const tx = paymentsReversed[i];
const kind = tx.kind;
const amt = getTransactionAmount(tx);
switch (kind) {
case "REPLENISHMENT": reversedState.main -= amt; break;
case "WITHDRAWAL": reversedState.main += amt; break;
case "SUBSCRIPTION":
case "LICENSE": reversedState.main += amt; break;
case "INVESTMENT": reversedState.main += amt; reversedState.invest -= amt; break;
case "TOP_UP_DEPOSIT": reversedState.main += amt; reversedState.invest -= amt; break;
case "REINVESTMENT": reversedState.invest -= amt; totalProfit += amt; break;
case "DIVIDEND": reversedState.invest -= amt; totalProfit += amt; break;
case "CLAIMED_DIVIDEND": reversedState.main -= amt; reversedState.invest += amt; break;
case "REFERRAL_FUND":
case "TEAM_EARNINGS":
case "REFERRAL_LICENSE_FUND":
case "REFERRAL_CARD_PURCHASE":
case "REFERRAL_CARD_TOPUP":
case "TEAM_EARNING_LIVE_TRADING":
case "SHAREHOLDER_BONUS": reversedState.affiliate -= amt; totalProvision += amt; break;
case "REFERRAL_RANK_BONUS": reversedState.main -= amt; totalProvision += amt; break;
case "TRANSFER":
if ((tx.asset === "PARTNER-USDT" && tx.targetAsset === "MAIN-USDT") || (!tx.asset && !tx.targetAsset)) {
reversedState.affiliate += amt;
reversedState.main -= amt;
}
break;
case "CARD_RECHARGE": reversedState.main += amt; break;
case "CARD_PURCHASE":
case "CARD_PURCHASE_PHYSICAL": reversedState.main += amt; break;
}
}
let history = [
{
date: "(Initial)",
kind: "-",
amount: 0,
main: 0,
invest: 0,
affiliate: 0,
card: 0,
sum: 0,
profit: 0,
provision: 0,
costs: 0,
totalCosts: 0
}
];
let main = 0;
let invest = 0;
let affiliate = 0;
let card = 0;
let profit = 0;
let provision = 0;
let totalCosts = 0;
filteredPayments.forEach(tx => {
let amount = getTransactionAmount(tx);
let kind = tx.kind;
let costAddition = 0;
if (hideCreditCard && (kind === "CARD_RECHARGE" || kind === "CARD_PURCHASE" || kind === "CARD_PURCHASE_PHYSICAL")) {
kind = "MAINTENANCE_FEE";
main -= amount;
costAddition = amount;
} else {
switch (kind) {
case "REPLENISHMENT": main += amount; break;
case "WITHDRAWAL":
main -= amount;
// Fix AURUM Bug: Calculate correct withdrawal fees
costAddition = (amount * 0.01) + 1.01;
break;
case "SUBSCRIPTION":
case "LICENSE":
main -= amount;
costAddition = amount;
break;
case "INVESTMENT":
// Fix AURUM Bug: Calculate correct initial investment amount
if (tx.kindName) {
amount += reversedState.invest;
}
invest += amount;
main -= amount;
break;
case "TOP_UP_DEPOSIT":
main -= amount;
invest += amount;
break;
case "DIVIDEND":
invest += amount;
profit += amount;
break;
case "REINVESTMENT":
invest += amount;
profit += amount;
break;
case "CLAIMED_DIVIDEND":
main += amount;
invest -= amount;
break;
case "REFERRAL_FUND":
case "TEAM_EARNINGS":
case "REFERRAL_LICENSE_FUND":
case "REFERRAL_CARD_PURCHASE":
case "REFERRAL_CARD_TOPUP":
case "TEAM_EARNING_LIVE_TRADING":
case "SHAREHOLDER_BONUS":
affiliate += amount;
provision += amount;
break;
case "REFERRAL_RANK_BONUS":
main += amount;
provision += amount;
break;
case "TRANSFER":
if ((tx.asset === "PARTNER-USDT" && tx.targetAsset === "MAIN-USDT") || (!tx.asset && !tx.targetAsset)) {
affiliate -= amount;
main += amount;
}
break;
case "CARD_RECHARGE":
// Fix AURUM Bug: Calculate correct card fees
main -= amount;
const fee = amount * 0.022;
const effective = amount - fee;
card += effective;
costAddition = fee;
break;
case "CARD_PURCHASE":
case "CARD_PURCHASE_PHYSICAL":
main -= amount;
costAddition = amount;
break;
}
}
totalCosts += costAddition;
history.push({
date: tx.date,
kind: kind,
amount: amount,
main: main,
invest: invest,
affiliate: affiliate,
card: card,
sum: main + invest + affiliate,
profit: profit,
provision: provision,
costs: costAddition,
totalCosts: totalCosts
});
});
return history;
}
function getTransactionAmount(tx) {
// If both cryptoAmount and amount are set, trust cryptoAmount
if (tx.cryptoAmount && tx.amount) {
return parseFloat(tx.cryptoAmount);
}
return parseFloat(tx.amount || '0');
}
function parseCorrections(correctionsText) {
if (!correctionsText.trim()) return [];
const lines = correctionsText.split('\n').filter(line => line.trim());
const corrections = [];
for (const line of lines) {
const parts = line.trim().split(' ');
if (parts.length >= 2) {
const date = parts[0] + ' ' + parts[1];
if (parts.length > 2) {
// Synthetic transaction
const kind = parts[2];
const amount = parseFloat(parts[3] || '0');
corrections.push({
date: date,
synthetic: true,
kind: kind,
amount: amount
});
} else {
// Filter out existing transaction
corrections.push({
date: date,
synthetic: false
});
}
}
}
return corrections;
}
function translateKind(kind) {
const map = {
"REPLENISHMENT": "Eingezahlt",
"WITHDRAWAL": "Ausgezahlt",
"WITHDRAWAL_DEPOSIT": "Ausgezahlt (Deposit)",
"INVESTMENT": "Invest",
"TOP_UP_DEPOSIT": "Invest",
"CARD_RECHARGE": "Karte aufladen",
"SUBSCRIPTION": "Abonnement",
"REINVESTMENT": "Reinvest",
"DIVIDEND": "Dividende",
"CLAIMED_DIVIDEND": "Umbuchung",
"REFERRAL_FUND": "Empfehlungsprovision",
"TEAM_EARNINGS": "Teameinnahmen",
"REFERRAL_RANK_BONUS": "Rangbonus",
"TRANSFER": "Übertragung",
"CARD_PURCHASE": "Kartenbestellung",
"CARD_PURCHASE_PHYSICAL": "Physische Karte",
"MAINTENANCE_FEE": "Verwaltungsgebühren",
"LICENSE": "Lizenz",
"FLASH_LOAN_PROFIT": "Flash Loan Profit (nicht unterstützt)",
"LIVE_TRADING": "Live Trading (nicht unterstützt)",
"LIVE_TRADING_BOTS": "Live Trading Bots (nicht unterstützt)",
"LIVE_TRADING_BOT_STOP": "Live Trading Bot Stop (nicht unterstützt)",
"TEAM_EARNING_LIVE_TRADING": "Team Live Trading",
"AURUM_TOKEN": "Aurum Token (nicht unterstützt)",
"REFERRAL_LICENSE_FUND": "Empfehlungs-Lizenz-Fonds",
"REFERRAL_CARD_PURCHASE": "Empfehlungs-Kartenkauf",
"REFERRAL_CARD_TOPUP": "Empfehlungs-Kartenaufladung",
"CARD_PURCHASE_CASHBACK": "Karten-Cashback (nicht unterstützt)",
"SHAREHOLDER_BONUS": "Aktionärsbonus"
};
return map[kind] || kind;
}
function renderTable(rows) {
let html = `<table class="w-full" style="border-collapse: collapse;">` +
`<thead><tr>` +
['Zeitpunkt', 'Vorgang', 'Betrag', 'Main', 'Invest', 'Affiliate', 'Gesamt', 'Profit', 'Provision', 'Gebühren', 'Gesamtkosten']
.map(h => `<th class="py-3 text-xs px-2 pb-5 pt-2 text-left font-light text-text-color-secondary">${h}</th>`).join('') +
`</tr></thead><tbody>`;
for (const row of rows) {
html += `<tr class="border-b border-border-color-primary">` +
`<td class="text-[14px] font-light text-text-color-primary">${row.date}</td>` +
`<td class="text-[14px] font-light text-text-color-primary">${translateKind(row.kind)}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.amount != null ? Number(row.amount).toFixed(2).replace('-0', '0') : ''}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.main.toFixed(2).replace('-0', '0')}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.invest.toFixed(2).replace('-0', '0')}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.affiliate.toFixed(2).replace('-0', '0')}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.sum.toFixed(2).replace('-0', '0')}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.profit.toFixed(2).replace('-0', '0')}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.provision.toFixed(2).replace('-0', '0')}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.costs.toFixed(2).replace('-0', '0')}</td>` +
`<td class="text-[14px] font-light text-text-color-primary text-right">${row.totalCosts.toFixed(2).replace('-0', '0')}</td>` +
`</tr>`;
}
html += '</tbody></table>';
return html;
}
function renderFinancialReport(rows) {
const years = {};
rows.forEach(row => {
if (row.date.startsWith('(')) return;
const yearMatch = row.date.match(/^(\d{4})/);
if (yearMatch) {
const year = yearMatch[1];
if (!years[year]) years[year] = [];
years[year].push(row);
}
});
const sortedYears = Object.keys(years).sort((a, b) => a - b);
let html = '';
sortedYears.forEach(year => {
const yearRows = years[year];
if (yearRows.length === 0) return;
let prevRow = rows[0];
const prevYearIndex = sortedYears.indexOf(year) - 1;
if (prevYearIndex >= 0) {
const prevYearRows = years[sortedYears[prevYearIndex]];
prevRow = prevYearRows[prevYearRows.length - 1];
}
const endRow = yearRows[yearRows.length - 1];
const diffProfit = endRow.profit - prevRow.profit;
const diffProvision = endRow.provision - prevRow.provision;
const diffCosts = endRow.totalCosts - prevRow.totalCosts;
// Calculate category breakdown
const categoryBreakdown = calculateCategoryBreakdown(yearRows, prevRow);
const net = diffProfit + diffProvision - diffCosts;
html += `
<div class="mt-4 mb-10">
<h3>Transaktionsaufstellung für den Zeitraum 01.01.-31.12.${year}</h3>
${renderCategoryTable(categoryBreakdown)}
<h3>Ertragsaufstellung für den Zeitraum 01.01.-31.12.${year}</h3>
<table class="w-full" style="border-collapse: collapse;">
<thead>
<tr>
<th class="py-3 text-l px-2 pb-5 pt-2 text-left font-light text-text-color-secondary" colspan="2">Höhe der ausländischen Kapitalerträge</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-[14px] font-light text-text-color-primary">Eigene Erträge</td>
<td class="text-[14px] font-light text-text-color-primary text-right">${diffProfit.toFixed(2)} USDT</td>
</tr>
<tr>
<td class="text-[14px] font-light text-text-color-primary">Erträge durch Partner (Provisionen)</td>
<td class="text-[14px] font-light text-text-color-primary text-right">${diffProvision.toFixed(2)} USDT</td>
</tr>
<tr>
<td class="text-[14px] font-light text-text-color-primary">Gebühren (Transaktionen, Netzwerk, System)</td>
<td class="text-[14px] font-light text-text-color-primary text-right">${diffCosts.toFixed(2)} USDT</td>
</tr>
<tr>
<td class="text-[14px] font-bold text-text-color-primary">Ausländische Kapitalerträge ohne Steuerabzug</td>
<td class="text-[14px] font-bold text-text-color-primary text-right">${net.toFixed(2)} USDT</td>
</tr>
</tbody>
</table>
</div>
`;
});
return html;
}
function calculateCategoryBreakdown(yearRows, prevRow) {
const categories = {};
// Initialize all possible categories
const allKinds = [
"REPLENISHMENT", "WITHDRAWAL", "WITHDRAWAL_DEPOSIT", "SUBSCRIPTION", "LICENSE",
"INVESTMENT", "REINVESTMENT", "TOP_UP_DEPOSIT", "DIVIDEND", "CLAIMED_DIVIDEND",
"AURUM_TOKEN", "FLASH_LOAN_PROFIT", "LIVE_TRADING", "LIVE_TRADING_BOTS",
"LIVE_TRADING_BOT_STOP", "REFERRAL_FUND", "REFERRAL_RANK_BONUS",
"TEAM_EARNINGS", "TEAM_EARNING_LIVE_TRADING", "REFERRAL_LICENSE_FUND",
"CARD_RECHARGE", "REFERRAL_CARD_PURCHASE", "REFERRAL_CARD_TOPUP",
"SHAREHOLDER_BONUS", "TRANSFER", "CARD_PURCHASE", "CARD_PURCHASE_PHYSICAL",
"CARD_PURCHASE_CASHBACK", "MAINTENANCE_FEE"
];
allKinds.forEach(kind => {
categories[kind] = { profit: 0, provision: 0, costs: 0 };
});
// Calculate differences for each transaction in the year
for (let i = 0; i < yearRows.length; i++) {
const currentRow = yearRows[i];
const previousRow = i === 0 ? prevRow : yearRows[i - 1];
let kind = currentRow.kind;
if (kind === 'MAINTENANCE_FEE' || kind === 'REINVESTMENT')
kind = 'DIVIDEND';
if (categories[kind]) {
categories[kind].profit += currentRow.profit - previousRow.profit;
categories[kind].provision += currentRow.provision - previousRow.provision;
categories[kind].costs += currentRow.costs;
}
}
return categories;
}
function renderCategoryTable(categories) {
const hasNonZeroValues = Object.values(categories).some(cat =>
cat.profit !== 0 || cat.provision !== 0 || cat.costs !== 0
);
if (!hasNonZeroValues) return '';
let html = `
<table class="w-full mb-4" style="border-collapse: collapse;">
<thead>
<tr>
<th class="py-3 text-l px-2 pb-5 pt-2 text-left font-light text-text-color-secondary">Kategorie</th>
<th class="py-3 text-l px-2 pb-5 pt-2 text-right font-light text-text-color-secondary">Profit</th>
<th class="py-3 text-l px-2 pb-5 pt-2 text-right font-light text-text-color-secondary">Provision</th>
<th class="py-3 text-l px-2 pb-5 pt-2 text-right font-light text-text-color-secondary">Kosten</th>
</tr>
</thead>
<tbody>
`;
Object.entries(categories).forEach(([kind, values]) => {
if (values.profit !== 0 || values.provision !== 0 || values.costs !== 0) {
html += `
<tr class="border-b border-border-color-primary">
<td class="text-[14px] font-light text-text-color-primary">${translateKind(kind)}</td>
<td class="text-[14px] font-light text-text-color-primary text-right">${values.profit.toFixed(2)}</td>
<td class="text-[14px] font-light text-text-color-primary text-right">${values.provision.toFixed(2)}</td>
<td class="text-[14px] font-light text-text-color-primary text-right">${values.costs.toFixed(2)}</td>
</tr>
`;
}
});
html += '</tbody></table>';
return html;
}
renderForm();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment