mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 17:47:00 -05:00
Add bank sync option to update dates. (#6850)
Signed-off-by: Christian Speich <christian@spei.ch>
This commit is contained in:
@@ -152,6 +152,8 @@ type BankSyncCheckboxOptionsProps = {
|
||||
setReimportDeleted: (value: boolean) => void;
|
||||
importTransactions: boolean;
|
||||
setImportTransactions: (value: boolean) => void;
|
||||
updateDates: boolean;
|
||||
setUpdateDates: (value: boolean) => void;
|
||||
helpMode?: 'desktop' | 'mobile';
|
||||
};
|
||||
|
||||
@@ -164,6 +166,8 @@ export function BankSyncCheckboxOptions({
|
||||
setReimportDeleted,
|
||||
importTransactions,
|
||||
setImportTransactions,
|
||||
updateDates,
|
||||
setUpdateDates,
|
||||
helpMode = 'desktop',
|
||||
}: BankSyncCheckboxOptionsProps) {
|
||||
const { t } = useTranslation();
|
||||
@@ -214,6 +218,18 @@ export function BankSyncCheckboxOptions({
|
||||
>
|
||||
<Trans>Investment Account</Trans>
|
||||
</CheckboxOptionWithHelp>
|
||||
|
||||
<CheckboxOptionWithHelp
|
||||
id="form_update_dates"
|
||||
checked={updateDates}
|
||||
onChange={() => setUpdateDates(!updateDates)}
|
||||
helpText={t(
|
||||
'By enabling this, the transaction date will be overwritten by the one provided by the bank.',
|
||||
)}
|
||||
helpMode={helpMode}
|
||||
>
|
||||
<Trans>Update Dates</Trans>
|
||||
</CheckboxOptionWithHelp>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,6 +148,8 @@ export function EditSyncAccount({ account }: EditSyncAccountProps) {
|
||||
setReimportDeleted,
|
||||
importTransactions,
|
||||
setImportTransactions,
|
||||
updateDates,
|
||||
setUpdateDates,
|
||||
mappings,
|
||||
setMapping,
|
||||
fields,
|
||||
@@ -222,6 +224,8 @@ export function EditSyncAccount({ account }: EditSyncAccountProps) {
|
||||
setReimportDeleted={setReimportDeleted}
|
||||
importTransactions={importTransactions}
|
||||
setImportTransactions={setImportTransactions}
|
||||
updateDates={updateDates}
|
||||
setUpdateDates={setUpdateDates}
|
||||
helpMode="desktop"
|
||||
/>
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ export function useBankSyncAccountSettings(accountId: string) {
|
||||
const [savedImportTransactions = true, setSavedImportTransactions] =
|
||||
useSyncedPref(`sync-import-transactions-${accountId}`);
|
||||
|
||||
const [savedUpdateDates = false, setSavedUpdateDates] = useSyncedPref(
|
||||
`sync-update-dates-${accountId}`,
|
||||
);
|
||||
|
||||
const [transactionDirection, setTransactionDirection] =
|
||||
useState<TransactionDirection>('payment');
|
||||
const [importPending, setImportPending] = useState(
|
||||
@@ -49,6 +53,9 @@ export function useBankSyncAccountSettings(accountId: string) {
|
||||
const [importTransactions, setImportTransactions] = useState(
|
||||
String(savedImportTransactions) === 'true',
|
||||
);
|
||||
const [updateDates, setUpdateDates] = useState(
|
||||
String(savedUpdateDates) === 'true',
|
||||
);
|
||||
|
||||
const transactionQuery = q('transactions')
|
||||
.filter({
|
||||
@@ -84,6 +91,7 @@ export function useBankSyncAccountSettings(accountId: string) {
|
||||
setSavedImportNotes(String(importNotes));
|
||||
setSavedReimportDeleted(String(reimportDeleted));
|
||||
setSavedImportTransactions(String(importTransactions));
|
||||
setSavedUpdateDates(String(updateDates));
|
||||
};
|
||||
|
||||
const setMapping = (field: string, value: string) => {
|
||||
@@ -110,6 +118,8 @@ export function useBankSyncAccountSettings(accountId: string) {
|
||||
setReimportDeleted,
|
||||
importTransactions,
|
||||
setImportTransactions,
|
||||
updateDates,
|
||||
setUpdateDates,
|
||||
mappings,
|
||||
setMapping,
|
||||
exampleTransaction,
|
||||
|
||||
@@ -37,6 +37,8 @@ export function MobileBankSyncAccountEditPage() {
|
||||
setReimportDeleted,
|
||||
importTransactions,
|
||||
setImportTransactions,
|
||||
updateDates,
|
||||
setUpdateDates,
|
||||
mappings,
|
||||
setMapping,
|
||||
fields,
|
||||
@@ -146,6 +148,8 @@ export function MobileBankSyncAccountEditPage() {
|
||||
setReimportDeleted={setReimportDeleted}
|
||||
importTransactions={importTransactions}
|
||||
setImportTransactions={setImportTransactions}
|
||||
updateDates={updateDates}
|
||||
setUpdateDates={setUpdateDates}
|
||||
helpMode="mobile"
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -488,6 +488,7 @@ export async function reconcileTransactions(
|
||||
strictIdChecking = true,
|
||||
isPreview = false,
|
||||
defaultCleared = true,
|
||||
updateDates = false,
|
||||
): Promise<ReconcileTransactionsResult> {
|
||||
logger.log('Performing transaction reconciliation');
|
||||
|
||||
@@ -536,6 +537,10 @@ export async function reconcileTransactions(
|
||||
existing.raw_synced_data ?? trans.raw_synced_data ?? null,
|
||||
};
|
||||
|
||||
if (updateDates && trans.date) {
|
||||
updates['date'] = trans.date;
|
||||
}
|
||||
|
||||
const fieldsToMarkUpdated = Object.keys(updates).filter(k => {
|
||||
// do not mark raw_synced_data if it's gone from falsy to falsy
|
||||
if (!existing.raw_synced_data && !trans.raw_synced_data) {
|
||||
@@ -558,13 +563,27 @@ export async function reconcileTransactions(
|
||||
updatedPreview.push({ transaction: trans, ignored: true });
|
||||
}
|
||||
|
||||
if (existing.is_parent && existing.cleared !== updates.cleared) {
|
||||
const clearedUpdated = existing.cleared !== updates.cleared;
|
||||
const dateUpdated =
|
||||
updateDates && trans.date && existing.date !== trans.date;
|
||||
|
||||
if (existing.is_parent && (clearedUpdated || dateUpdated)) {
|
||||
const children = await db.all<Pick<db.DbViewTransaction, 'id'>>(
|
||||
'SELECT id FROM v_transactions WHERE parent_id = ?',
|
||||
[existing.id],
|
||||
);
|
||||
const childUpdates = {};
|
||||
|
||||
if (clearedUpdated) {
|
||||
childUpdates['cleared'] = updates.cleared;
|
||||
}
|
||||
|
||||
if (dateUpdated) {
|
||||
childUpdates['date'] = trans.date;
|
||||
}
|
||||
|
||||
for (const child of children) {
|
||||
updated.push({ id: child.id, cleared: updates.cleared });
|
||||
updated.push({ id: child.id, ...childUpdates });
|
||||
}
|
||||
}
|
||||
} else if (trans.tombstone) {
|
||||
@@ -895,6 +914,12 @@ async function processBankSyncDownload(
|
||||
.select('value'),
|
||||
).then(data => String(data?.data?.[0]?.value ?? 'true') === 'true');
|
||||
|
||||
const updateDates = await aqlQuery(
|
||||
q('preferences')
|
||||
.filter({ id: `sync-update-dates-${id}` })
|
||||
.select('value'),
|
||||
).then(data => String(data?.data?.[0]?.value ?? 'false') === 'true');
|
||||
|
||||
/** Starting balance is actually the current balance of the account. */
|
||||
const {
|
||||
transactions: originalTransactions,
|
||||
@@ -948,6 +973,9 @@ async function processBankSyncDownload(
|
||||
transactions,
|
||||
true,
|
||||
useStrictIdChecking,
|
||||
false,
|
||||
true,
|
||||
updateDates,
|
||||
);
|
||||
return {
|
||||
...result,
|
||||
@@ -967,6 +995,9 @@ async function processBankSyncDownload(
|
||||
importTransactions ? transactions : [],
|
||||
true,
|
||||
useStrictIdChecking,
|
||||
false,
|
||||
true,
|
||||
updateDates,
|
||||
);
|
||||
|
||||
if (currentBalance != null) {
|
||||
|
||||
@@ -43,6 +43,7 @@ export type SyncedPrefs = Partial<
|
||||
| `sync-reimport-deleted-${string}`
|
||||
| `sync-import-notes-${string}`
|
||||
| `sync-import-transactions-${string}`
|
||||
| `sync-update-dates-${string}`
|
||||
| `ofx-fallback-missing-payee-${string}`
|
||||
| `flip-amount-${string}-${'csv' | 'qif'}`
|
||||
| `flags.${FeatureFlag}`
|
||||
|
||||
6
upcoming-release-notes/6850.md
Normal file
6
upcoming-release-notes/6850.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Enhancements
|
||||
authors: [kleinweby]
|
||||
---
|
||||
|
||||
Add bank sync option to allow overwriting dates with the bank's value.
|
||||
Reference in New Issue
Block a user