[Bug]: importTransactions API won't check for duplicates in same import #1809

Open
opened 2026-02-28 19:55:04 -06:00 by GiteaMirror · 1 comment
Owner

Originally created by @SimonMayerhofer on GitHub (Feb 2, 2025).

Verified issue does not already exist?

  • I have searched and found no existing issue

What happened?

I'm currently writing an CSV importer and noticed a minor bug in the importTransactions API function.

I created a hash from an row in the CSV file to detect duplicates and to create the imported_id.

If a duplicated transaction with the same imported_id is imported in the same importTransactions API call, it will still be imported. If the calls are after each other, it works just fine how it should.

How can we reproduce the issue?

POC Code

import * as api from "@actual-app/api";
import fs from "fs";
import dotenv from "dotenv";

dotenv.config();

const SERVER_URL = process.env.SERVER_URL;
const ACTUAL_PASSWORD = process.env.ACTUAL_PASSWORD;
const SYNC_ID = process.env.SYNC_ID;
const E2E_PASSWORD = process.env.E2E_PASSWORD;

async function testImportTransactions() {
	const cacheDir = './local-budgets-cache';
	if (!fs.existsSync(cacheDir)) {
		fs.mkdirSync(cacheDir, { recursive: true });
		console.log(`✔ Created missing directory: ${cacheDir}`);
	}

	await api.init({
		dataDir: cacheDir,
		serverURL: SERVER_URL,
		password: ACTUAL_PASSWORD,
	});

	await api.downloadBudget(SYNC_ID, E2E_PASSWORD ? { password: E2E_PASSWORD } : undefined);

	// Create a new test account
	const accountId = await api.createAccount({ name: "Testaccount" });


    // Import transactions at the same time with the same imported_id
	let result = await api.importTransactions(accountId, [
        {
            date: "2024-02-01",
            amount: 10000, // 100.00
            notes: "#1",
            imported_id: "duplicate-id",
        },
        {
            date: "2024-02-02",
            amount: 20000, // 200.00
            notes: "#2",
            imported_id: "duplicate-id",
        }
    ]);

	// Import transactions separately with the same imported_id
	result = await api.importTransactions(accountId, [
        {
            date: "2024-02-03",
            amount: 10000, // 100.00
            notes: "#3",
            imported_id: "duplicate-id-2",
        }
    ]);
	result = await api.importTransactions(accountId, [
        {
            date: "2024-02-04",
            amount: 20000, // 200.00
            notes: "#4",
            imported_id: "duplicate-id-2",
        }
    ]);

	await api.shutdown();
}

// Run the test
testImportTransactions().catch(console.error);

Result: #1, #2 and #3 are created.
Expected behaviour: #1 and #3 are created.

Where are you hosting Actual?

Docker

What browsers are you seeing the problem on?

No response

Operating System

None

Originally created by @SimonMayerhofer on GitHub (Feb 2, 2025). ### Verified issue does not already exist? - [x] I have searched and found no existing issue ### What happened? I'm currently writing an CSV importer and noticed a minor bug in the importTransactions API function. I created a hash from an row in the CSV file to detect duplicates and to create the `imported_id`. If a duplicated transaction with the same `imported_id` is imported in the same importTransactions API call, it will still be imported. If the calls are after each other, it works just fine how it should. ### How can we reproduce the issue? <details><summary>POC Code</summary> <p> ```js import * as api from "@actual-app/api"; import fs from "fs"; import dotenv from "dotenv"; dotenv.config(); const SERVER_URL = process.env.SERVER_URL; const ACTUAL_PASSWORD = process.env.ACTUAL_PASSWORD; const SYNC_ID = process.env.SYNC_ID; const E2E_PASSWORD = process.env.E2E_PASSWORD; async function testImportTransactions() { const cacheDir = './local-budgets-cache'; if (!fs.existsSync(cacheDir)) { fs.mkdirSync(cacheDir, { recursive: true }); console.log(`✔ Created missing directory: ${cacheDir}`); } await api.init({ dataDir: cacheDir, serverURL: SERVER_URL, password: ACTUAL_PASSWORD, }); await api.downloadBudget(SYNC_ID, E2E_PASSWORD ? { password: E2E_PASSWORD } : undefined); // Create a new test account const accountId = await api.createAccount({ name: "Testaccount" }); // Import transactions at the same time with the same imported_id let result = await api.importTransactions(accountId, [ { date: "2024-02-01", amount: 10000, // 100.00 notes: "#1", imported_id: "duplicate-id", }, { date: "2024-02-02", amount: 20000, // 200.00 notes: "#2", imported_id: "duplicate-id", } ]); // Import transactions separately with the same imported_id result = await api.importTransactions(accountId, [ { date: "2024-02-03", amount: 10000, // 100.00 notes: "#3", imported_id: "duplicate-id-2", } ]); result = await api.importTransactions(accountId, [ { date: "2024-02-04", amount: 20000, // 200.00 notes: "#4", imported_id: "duplicate-id-2", } ]); await api.shutdown(); } // Run the test testImportTransactions().catch(console.error); ``` </p> </details> Result: `#1`, `#2` and `#3` are created. Expected behaviour: `#1` and `#3` are created. ### Where are you hosting Actual? Docker ### What browsers are you seeing the problem on? _No response_ ### Operating System None
GiteaMirror added the bugAPI labels 2026-02-28 19:55:04 -06:00
Author
Owner

@SimonMayerhofer commented on GitHub (Feb 2, 2025):

I'm actually unsure whether this is wanted behavior or not, I just wanted to let you know that I noticed it, because it wasn't mentioned in the docs. It might be good, like in my case, when importing from a CSV where you don't have an imported_id set by a bank or so and specifically want to import without checking for duplicates in the same dataset.
But when running the import again, then the duplicates should be detected.
If it's wanted behavior, there should be a notice in the docs.

@SimonMayerhofer commented on GitHub (Feb 2, 2025): I'm actually unsure whether this is wanted behavior or not, I just wanted to let you know that I noticed it, because it wasn't mentioned in the docs. It might be good, like in my case, when importing from a CSV where you don't have an imported_id set by a bank or so and specifically want to import without checking for duplicates in the same dataset. But when running the import again, then the duplicates should be detected. If it's wanted behavior, there should be a notice in the docs.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#1809