Skip to content

Commit

Permalink
update mapping data for existing synced transactions and always show …
Browse files Browse the repository at this point in the history
…direction dropdown (#4403)

* update sync mapping data for existing transactions on sync

* show payment direction dropdown regardless of sample data

* note

* ignore changes in raw_synced_data
  • Loading branch information
matt-fidd authored Feb 18, 2025
1 parent cab24df commit a4d3f27
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,22 +179,13 @@ export function EditSyncAccount({ account }: EditSyncAccountProps) {
<Trans>Field mapping</Trans>
</Text>

{fields.length > 0 ? (
<FieldMapping
transactionDirection={transactionDirection}
setTransactionDirection={setTransactionDirection}
fields={fields as MappableFieldWithExample[]}
mapping={mapping!}
setMapping={setMapping}
/>
) : (
<Text style={{ margin: '1em 0 .5em 0' }}>
<Trans>
No transactions found with mappable fields, accounts must have
been synced at least once for this function to be available.
</Trans>
</Text>
)}
<FieldMapping
transactionDirection={transactionDirection}
setTransactionDirection={setTransactionDirection}
fields={fields as MappableFieldWithExample[]}
mapping={mapping!}
setMapping={setMapping}
/>

<Text style={{ fontSize: 15, margin: '1em 0 .5em 0' }}>
<Trans>Options</Trans>
Expand Down
173 changes: 92 additions & 81 deletions packages/desktop-client/src/components/banksync/FieldMapping.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Trans, useTranslation } from 'react-i18next';

import { Text } from '@actual-app/components/text';

Expand Down Expand Up @@ -65,92 +65,103 @@ export function FieldMapping({
}}
/>

<TableHeader>
<Cell
value={t('Actual field')}
width={100}
style={{ paddingLeft: '10px' }}
/>
<Cell
value={t('Bank field')}
width={330}
style={{ paddingLeft: '10px' }}
/>
<Cell
value={t('Example')}
width="flex"
style={{ paddingLeft: '10px' }}
/>
</TableHeader>

{fields.map(field => {
return (
<Row
key={field.actualField}
style={{
fontSize: 13,
backgroundColor: theme.tableRowBackgroundHover,
display: 'flex',
alignItems: 'center',
border: '1px solid var(--color-tableBorder)',
minHeight: '40px',
}}
collapsed={true}
>
{fields.length === 0 ? (
<Text style={{ margin: '1em 0 .5em 0' }}>
<Trans>
No transactions found with mappable fields, accounts must have been
synced at least once for this function to be available.
</Trans>
</Text>
) : (
<>
<TableHeader>
<Cell
value={field.actualField}
width={75}
style={{ paddingLeft: '10px', height: '100%', border: 0 }}
value={t('Actual field')}
width={100}
style={{ paddingLeft: '10px' }}
/>

<Text>
<SvgRightArrow2
style={{
width: 15,
height: 15,
color: theme.tableText,
marginRight: '20px',
}}
/>
</Text>

<Select
aria-label={t('Synced field to map to {{field}}', {
field: field.actualField,
})}
options={field.syncFields.map(({ field }) => [field, field])}
value={mapping.get(field.actualField)}
style={{
width: 290,
}}
onChange={newValue => {
if (newValue) setMapping(field.actualField, newValue);
}}
<Cell
value={t('Bank field')}
width={330}
style={{ paddingLeft: '10px' }}
/>

<Text>
<SvgEquals
style={{
width: 12,
height: 12,
color: theme.tableText,
marginLeft: '20px',
}}
/>
</Text>

<Cell
value={
field.syncFields.find(
f => f.field === mapping.get(field.actualField),
)?.example
}
value={t('Example')}
width="flex"
style={{ paddingLeft: '10px', height: '100%', border: 0 }}
style={{ paddingLeft: '10px' }}
/>
</Row>
);
})}
</TableHeader>

{fields.map(field => {
return (
<Row
key={field.actualField}
style={{
fontSize: 13,
backgroundColor: theme.tableRowBackgroundHover,
display: 'flex',
alignItems: 'center',
border: '1px solid var(--color-tableBorder)',
minHeight: '40px',
}}
collapsed={true}
>
<Cell
value={field.actualField}
width={75}
style={{ paddingLeft: '10px', height: '100%', border: 0 }}
/>

<Text>
<SvgRightArrow2
style={{
width: 15,
height: 15,
color: theme.tableText,
marginRight: '20px',
}}
/>
</Text>

<Select
aria-label={t('Synced field to map to {{field}}', {
field: field.actualField,
})}
options={field.syncFields.map(({ field }) => [field, field])}
value={mapping.get(field.actualField)}
style={{
width: 290,
}}
onChange={newValue => {
if (newValue) setMapping(field.actualField, newValue);
}}
/>

<Text>
<SvgEquals
style={{
width: 12,
height: 12,
color: theme.tableText,
marginLeft: '20px',
}}
/>
</Text>

<Cell
value={
field.syncFields.find(
f => f.field === mapping.get(field.actualField),
)?.example
}
width="flex"
style={{ paddingLeft: '10px', height: '100%', border: 0 }}
/>
</Row>
);
})}
</>
)}
</>
);
}
13 changes: 12 additions & 1 deletion packages/loot-core/src/server/accounts/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,20 @@ export async function reconcileTransactions(
imported_payee: trans.imported_payee || null,
notes: existing.notes || trans.notes || null,
cleared: trans.cleared ?? existing.cleared,
raw_synced_data:
existing.raw_synced_data ?? trans.raw_synced_data ?? null,
};

if (hasFieldsChanged(existing, updates, Object.keys(updates))) {
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) {
return k !== 'raw_synced_data';
}

return true;
});

if (hasFieldsChanged(existing, updates, fieldsToMarkUpdated)) {
updated.push({ id: existing.id, ...updates });
if (!existingPayeeMap.has(existing.payee)) {
const payee = await db.getPayee(existing.payee);
Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/4403.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [matt-fidd]
---

Update bank sync mapping data for existing transactions on sync

0 comments on commit a4d3f27

Please sign in to comment.