Implement account and transaction upsert functionality; add updateAccounts API endpoint
This commit is contained in:
@ -166,5 +166,97 @@ export async function setTransactionNote(transactionId, note) {
|
||||
return result
|
||||
}
|
||||
|
||||
export async function updateAccounts(data) {
|
||||
try {
|
||||
console.log('Updating accounts with data:', data);
|
||||
for (const account of data.accounts) {
|
||||
// Upsert Org
|
||||
console.log(`Upserting org for account: ${account.id}`, account.org);
|
||||
await db`
|
||||
insert into org (id, domain, name, sfin_url, url)
|
||||
values (${account.org.id}, ${account.org.domain ?? null}, ${account.org.name ?? null}, ${account.org.sfin_url ?? null}, ${account.org.url ?? null})
|
||||
on conflict (id) do update set
|
||||
domain = excluded.domain,
|
||||
name = excluded.name,
|
||||
sfin_url = excluded.sfin_url,
|
||||
url = excluded.url
|
||||
`;
|
||||
console.log(`Upserting account: ${account.id} (${account.name})`);
|
||||
// Upsert Account
|
||||
await db`
|
||||
insert into account (id, org_id, name, currency, balance, available_balance, balance_date)
|
||||
values (
|
||||
${account.id},
|
||||
${account.org.id},
|
||||
${account.name ?? null},
|
||||
${account.currency ?? null},
|
||||
${account.balance ?? null},
|
||||
${account.available_balance ?? null},
|
||||
${account.balance_date ?? null}
|
||||
)
|
||||
on conflict (id) do update set
|
||||
org_id = excluded.org_id,
|
||||
name = excluded.name,
|
||||
currency = excluded.currency,
|
||||
balance = excluded.balance,
|
||||
available_balance = excluded.available_balance,
|
||||
balance_date = excluded.balance_date
|
||||
`;
|
||||
|
||||
// Upsert Transactions
|
||||
if (account.transactions && account.transactions.length > 0) {
|
||||
for (const txn of account.transactions) {
|
||||
let extraId = null;
|
||||
console.log(`Upserting transaction: ${txn.id} for account: ${account.id}`);
|
||||
if (txn.extra) {
|
||||
// Upsert TransactionExtra (insert only, update not needed for category)
|
||||
const extraResult = await db`
|
||||
insert into transaction_extra (category)
|
||||
values (${txn.extra.category ?? null})
|
||||
on conflict (category) do nothing
|
||||
returning id
|
||||
`;
|
||||
if (extraResult.length > 0) {
|
||||
extraId = extraResult[0].id;
|
||||
} else {
|
||||
// If already exists, fetch id
|
||||
const existing = await db`
|
||||
select id from transaction_extra where category = ${txn.extra.category ?? null}
|
||||
`;
|
||||
if (existing.length > 0) {
|
||||
extraId = existing[0].id;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`Preparing to upsert transaction: ${txn.id} with data:`, txn);
|
||||
await db`
|
||||
insert into transaction (id, account_id, posted, amount, description, pending, extra_id)
|
||||
values (
|
||||
${txn.id},
|
||||
${account.id},
|
||||
${txn.posted},
|
||||
${txn.amount ?? null},
|
||||
${txn.description ?? null},
|
||||
${txn.pending},
|
||||
${extraId}
|
||||
)
|
||||
on conflict (id) do update set
|
||||
account_id = excluded.account_id,
|
||||
posted = excluded.posted,
|
||||
amount = excluded.amount,
|
||||
description = excluded.description,
|
||||
pending = excluded.pending,
|
||||
extra_id = excluded.extra_id
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('updateAccounts error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default db
|
||||
@ -1,5 +1,14 @@
|
||||
|
||||
export async function updateAccounts()
|
||||
{
|
||||
fetch
|
||||
export async function fetchAccounts(url, startDate) {
|
||||
const { username, password, origin, pathname } = new URL(url);
|
||||
const start = Math.floor(startDate.getTime() / 1000);
|
||||
const apiUrl = `${origin}${pathname}/accounts?start-date=${start}`;
|
||||
const headers = {};
|
||||
|
||||
if (username && password) {
|
||||
headers['Authorization'] = 'Basic ' + btoa(`${username}:${password}`);
|
||||
}
|
||||
|
||||
const response = await fetch(apiUrl, { headers });
|
||||
return await response.json();
|
||||
}
|
||||
@ -7,6 +7,11 @@
|
||||
amount: 0,
|
||||
notes: ''
|
||||
});
|
||||
async function update() {
|
||||
let res = await fetch('/api/simplefin/update', {
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
async function saveBudget() {
|
||||
let res = await fetch('/budget', {
|
||||
method: 'POST',
|
||||
@ -23,7 +28,6 @@
|
||||
});
|
||||
newBudget = { name: '', amount: 0, notes: '' }; // Reset the form
|
||||
// Optionally, you can refresh the budgets list or show a success message
|
||||
|
||||
} else {
|
||||
console.error('Failed to save budget');
|
||||
}
|
||||
@ -32,7 +36,7 @@
|
||||
|
||||
<div class="drawer lg:drawer-open">
|
||||
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
|
||||
<div class="drawer-content flex flex-col items-center justify-center">
|
||||
<div class="drawer-content flex flex-col m-5">
|
||||
<!-- Page content here -->
|
||||
{@render children()}
|
||||
<label for="my-drawer-2" class="btn btn-primary drawer-button lg:hidden"> Open drawer </label>
|
||||
@ -40,14 +44,10 @@
|
||||
<div class="drawer-side">
|
||||
<label for="my-drawer-2" aria-label="close sidebar" class="drawer-overlay"></label>
|
||||
<ul class="menu bg-base-200 text-base-content min-h-full w-80 p-4">
|
||||
{#each data.accounts as account}
|
||||
<li>
|
||||
<a href={`/account/${account.id}`}>
|
||||
{account.name} ({account.balance})
|
||||
</a>
|
||||
<button onclick={update}>Update</button>
|
||||
</li>
|
||||
{/each}
|
||||
<li><div class="divider"></div></li>
|
||||
<li><div class="divider">Budgets</div></li>
|
||||
{#each budgets as budget}
|
||||
<li>
|
||||
<a href={`/budget/${budget.id}`}>
|
||||
@ -56,7 +56,7 @@
|
||||
</li>
|
||||
{/each}
|
||||
<li>
|
||||
<button class="btn btn-circle" aria-label="Add" onclick={()=>AddBudgetModal.showModal()}>
|
||||
<button class="btn btn-circle" aria-label="Add" onclick={() => AddBudgetModal.showModal()}>
|
||||
<svg
|
||||
fill="#F0F0F0F0"
|
||||
height="800px"
|
||||
@ -76,28 +76,36 @@
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
<li><div class="divider">Accounts</div></li>
|
||||
{#each data.accounts as account}
|
||||
<li>
|
||||
<a href={`/account/${account.id}`}>
|
||||
{account.name} ({account.balance})
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<dialog id="AddBudgetModal" class="modal">
|
||||
<div class="modal-box">
|
||||
<form method="dialog">
|
||||
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<input
|
||||
bind:value={newBudget.name}
|
||||
type="text"
|
||||
placeholder="Budget Name"
|
||||
class="input input-bordered w-full max-w-xs"/>
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
<input
|
||||
bind:value={newBudget.amount}
|
||||
type="number"
|
||||
placeholder="Budget Amount"
|
||||
class="input input-bordered w-full max-w-xs mt-2"/>
|
||||
class="input input-bordered w-full max-w-xs mt-2"
|
||||
/>
|
||||
<textarea bind:value={newBudget.notes} class="textarea w-100"></textarea>
|
||||
</div>
|
||||
<button onclick={() => saveBudget()} class="btn btn-primary mt-4">Save</button>
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
<h4>${currentTransaction?.amount}</h4>
|
||||
<p> {currentTransaction?.date?.toDateString()}</p>
|
||||
<div>
|
||||
<textarea bind:value={notes} class="textarea w-100"/>
|
||||
<textarea bind:value={notes} class="textarea w-100"></textarea>
|
||||
</div>
|
||||
<button onclick={() => saveNotes()} class="btn btn-primary mt-4">Save</button>
|
||||
</div>
|
||||
|
||||
11
src/routes/api/simplefin/update/+server.js
Normal file
11
src/routes/api/simplefin/update/+server.js
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
import { fetchAccounts } from '$lib/simplefin';
|
||||
import { updateAccounts } from '$lib/db' ;
|
||||
|
||||
const url = "https://19443E0E8171E175EC5DA0C69B35DD50197F234B9A74C00D27FD606121257ECF:DAA3702E2100CFFD3B544251E6D755E86B1EDDFBFCC7F6FA9CE77AB3677E60DE@beta-bridge.simplefin.org/simplefin";
|
||||
|
||||
export async function POST() {
|
||||
const res = await fetchAccounts(url, new Date("2025-07-01"))
|
||||
return new Response(await updateAccounts(res));
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user