Skip to content

Instantly share code, notes, and snippets.

@Helmi
Created March 26, 2025 09:37
Show Gist options
  • Save Helmi/b5124b8e82deb73fa3f5db83a8b5ef1a to your computer and use it in GitHub Desktop.
Save Helmi/b5124b8e82deb73fa3f5db83a8b5ef1a to your computer and use it in GitHub Desktop.
Finom: Bulk Remover for Prepared Transactions

Bulk Transaction Deletion Script for Finom X

This script was created to help remove prepared transactions from the Finom Bank (Finom.co) interface after their recent update to Finom X. Finom now allows you to upload up to 200 transactions via CSV to "prepare" them before processing. However, there’s currently no built-in way to collectively remove these transactions, so this script simulates human interaction through your browser’s JavaScript console to delete them one by one.

It's important to say it was made for the german language interface. If you're using a different language you might have to change some parts of it.

Important:
This script is provided as-is. It is strongly advised that you only use it if you fully understand what it does. I am not responsible for any damage or unintended consequences that may result from using this code.

How It Works

  • DOM Querying: The script looks for transaction elements using their data-test attribute.
  • Simulated Hover: It simulates hover events on each transaction to reveal the three-dot menu.
  • Menu Interaction: It clicks the three-dot menu and then clicks the "Zahlung löschen" (delete) menu item to trigger deletion.
  • Error Handling: After each transaction, the script checks for error notifications (displayed by Finom's UI) and clicks their close button if present.
  • Human-like Delays: Randomized delays (200–500 ms) are used between actions to mimic real user behavior and avoid running into problems with too many fast, consecutive executions.
  • Continuous Processing: The script continuously re-checks for remaining transactions until none are found.

Usage Instructions

  1. Log in to Finom X: Open Finom X in your browser and navigate to the transactions page where your prepared transactions are listed.
  2. Open the Developer Console: Press F12 (or right-click and select "Inspect") to open the Developer Tools, and switch to the Console tab.
  3. Copy & Paste the Script: Copy the entire script from your file and paste it into the Console.
  4. Execute the Script: Press Enter to run the script. The console will log messages as transactions are deleted.
  5. Monitor the Process: Watch the console output to track the number of transactions deleted and any potential errors.

Disclaimer

Use this script at your own risk. Make sure you understand what it does before executing it. The author is not responsible for any consequences that may occur from using this script.

(async function bulkDeleteTransactions() {
// Helper: wait for a specified time (ms)
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Helper: return a random delay between min and max (ms)
function getRandomDelay(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Simulate hovering by dispatching multiple pointer/mouse events with coordinates
function simulateHover(element) {
const rect = element.getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
const events = ["pointerover", "pointerenter", "mouseover", "mouseenter", "mousemove"];
for (const evt of events) {
element.dispatchEvent(new MouseEvent(evt, {
bubbles: true,
cancelable: true,
clientX: x,
clientY: y
}));
}
}
// Poll for the "Zahlung löschen" remove item a few times before giving up
async function waitForRemoveItem(attempts = 3, interval = 300) {
for (let i = 0; i < attempts; i++) {
const el = document.querySelector('[data-test="transaction_action_Remove"]');
if (el) return el;
await delay(interval);
}
return null;
}
// Close any ant notifications if they are present by clicking their close button
function closeNotifications() {
const notifCloseButtons = document.querySelectorAll('a.ant-notification-notice-close');
notifCloseButtons.forEach(btn => btn.click());
}
let count = 0;
while (true) {
// Always query the first remaining transaction.
const tx = document.querySelector('[data-test="transation-list-item"]');
if (!tx) {
console.log("No more transactions found.");
break;
}
// Simulate hover over the transaction so that the three-dot button appears.
simulateHover(tx);
await delay(getRandomDelay(200, 500));
const menuButton = tx.querySelector('[data-test="transaction_action_more"]');
if (!menuButton) {
console.warn("No '...' button found for transaction:", tx);
// Remove the element to avoid endless looping.
tx.remove();
continue;
}
// Click the three-dot menu button to open the dropdown.
menuButton.click();
await delay(getRandomDelay(200, 500));
// Try to find the "Zahlung löschen" remove item.
let removeItem = await waitForRemoveItem(3, 300);
if (!removeItem) {
// Retry silently: re-trigger hover and click the menu button again.
simulateHover(tx);
await delay(getRandomDelay(200, 500));
menuButton.click();
await delay(getRandomDelay(200, 500));
removeItem = await waitForRemoveItem(3, 300);
}
if (removeItem) {
removeItem.click();
count++;
console.log(`Deleted transaction ${count}`);
}
// After each transaction, close any ant notifications if present.
closeNotifications();
await delay(getRandomDelay(200, 500));
// Every 10 deletions, pause for 1 second to let the UI catch up.
if (count && count % 10 === 0) {
await delay(1000);
}
}
console.log("Bulk deletion complete. Total transactions deleted:", count);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment