Skip to content

Commit

Permalink
Merge branch 'master' into reportsReorg
Browse files Browse the repository at this point in the history
  • Loading branch information
carkom authored Nov 5, 2023
2 parents 4cb782f + be18891 commit 585390a
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 30 deletions.
63 changes: 62 additions & 1 deletion packages/desktop-client/e2e/data/ynab5-demo-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -1671,9 +1671,70 @@
"import_payee_name_original": null,
"debt_transaction_type": null,
"deleted": false
},
{
"id": "213526fc-ba49-4790-8a96-cc2a50182728",
"date": "2023-09-04",
"amount": -100000,
"memo": "Test transaction",
"cleared": "cleared",
"approved": true,
"flag_color": null,
"account_id": "bc1d862f-bab0-41c3-bd1e-6cee8c688e32",
"payee_id": "2a20470a-634f-4efa-a7f6-f1c0b0bdda41",
"category_id": "36120d44-6c61-4402-985a-891a8d267858",
"transfer_account_id": null,
"transfer_transaction_id": null,
"matched_transaction_id": null,
"import_id": null,
"import_payee_name": null,
"import_payee_name_original": null,
"debt_transaction_type": null,
"deleted": false
},
{
"id": "024494a1-f1e0-4667-9fc0-91e4a4262193",
"date": "2023-09-04",
"amount": 50000,
"memo": "split part b",
"cleared": "cleared",
"approved": true,
"flag_color": null,
"account_id": "125f339b-2a63-481e-84c0-f04d898905d2",
"payee_id": "",
"category_id": null,
"transfer_account_id": "bc1d862f-bab0-41c3-bd1e-6cee8c688e32",
"transfer_transaction_id": "213526fc-ba49-4790-8a96-cc2a50182728",
"matched_transaction_id": "",
"import_id": null,
"import_payee_name": null,
"import_payee_name_original": null,
"debt_transaction_type": null,
"deleted": false
}
],
"subtransactions": [
{
"id": "d8ec8c84-5033-4f7e-8485-66bfe19a70d6",
"transaction_id": "213526fc-ba49-4790-8a96-cc2a50182728",
"amount": -50000,
"memo": "split part a",
"payee_id": "2a20470a-634f-4efa-a7f6-f1c0b0bdda41",
"category_id": "36120d44-6c61-4402-985a-891a8d267858",
"transfer_account_id": null,
"deleted": false
},
{
"id": "870d8780-79cf-4197-a341-47d24b2b5a59",
"transaction_id": "213526fc-ba49-4790-8a96-cc2a50182728",
"amount": -50000,
"memo": "split part b",
"payee_id": "2a20470a-634f-4efa-a7f6-f1c0b0bdda41",
"category_id": null,
"transfer_account_id": "125f339b-2a63-481e-84c0-f04d898905d2",
"deleted": false
}
],
"subtransactions": [],
"scheduled_transactions": [],
"scheduled_subtransactions": []
},
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/e2e/onboarding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ test.describe('Onboarding', () => {
await expect(budgetPage.budgetTable).toBeVisible({ timeout: 30000 });

const accountPage = await navigation.goToAccountPage('Checking');
await expect(accountPage.accountBalance).toHaveText('700.00');
await expect(accountPage.accountBalance).toHaveText('600.00');

await navigation.goToAccountPage('Saving');
await expect(accountPage.accountBalance).toHaveText('200.00');
await expect(accountPage.accountBalance).toHaveText('250.00');
});

test('creates a new budget file by importing Actual budget', async () => {
Expand Down
165 changes: 138 additions & 27 deletions packages/desktop-client/src/components/modals/ImportTransactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,22 @@ function getInitialMappings(transactions) {
),
);

let inOutField = key(
fields.find(
([name, value]) =>
name !== dateField &&
name !== amountField &&
name !== payeeField &&
name !== notesField,
),
);

return {
date: dateField,
amount: amountField,
payee: payeeField,
notes: notesField,
inOut: inOutField,
};
}

Expand All @@ -222,7 +233,14 @@ function parseAmount(amount, mapper) {
return value;
}

function parseAmountFields(trans, splitMode, flipAmount, multiplierAmount) {
function parseAmountFields(
trans,
splitMode,
inOutMode,
outValue,
flipAmount,
multiplierAmount,
) {
const multiplier = parseFloat(multiplierAmount) || 1.0;

if (splitMode) {
Expand All @@ -240,6 +258,16 @@ function parseAmountFields(trans, splitMode, flipAmount, multiplierAmount) {
inflow,
};
}
if (inOutMode) {
return {
amount:
parseAmount(trans.amount, n =>
trans.inOut === outValue ? Math.abs(n) * -1 : Math.abs(n),
) * multiplier,
outflow: null,
inflow: null,
};
}
return {
amount:
parseAmount(trans.amount, n => (flipAmount ? n * -1 : n)) * multiplier,
Expand All @@ -255,6 +283,8 @@ function Transaction({
parseDateFormat,
dateFormat,
splitMode,
inOutMode,
outValue,
flipAmount,
multiplierAmount,
}) {
Expand All @@ -269,6 +299,8 @@ function Transaction({
let { amount, outflow, inflow } = parseAmountFields(
transaction,
splitMode,
inOutMode,
outValue,
flipAmount,
multiplierAmount,
);
Expand Down Expand Up @@ -320,13 +352,24 @@ function Transaction({
</Field>
</>
) : (
<Field
width={90}
contentStyle={{ textAlign: 'right', ...styles.tnum }}
title={amount}
>
{amount}
</Field>
<>
{inOutMode && (
<Field
width={90}
contentStyle={{ textAlign: 'left', ...styles.tnum }}
title={transaction.inOut}
>
{transaction.inOut}
</Field>
)}
<Field
width={90}
contentStyle={{ textAlign: 'right', ...styles.tnum }}
title={amount}
>
{amount}
</Field>
</>
)}
</Row>
);
Expand Down Expand Up @@ -457,11 +500,43 @@ function MultiplierOption({
);
}

function InOutOption({
inOutMode,
outValue,
disabled,
onToggle,
onChangeText,
}) {
return (
<View style={{ flexDirection: 'row', gap: 10, height: 28 }}>
<CheckboxOption
id="form_inOut"
checked={inOutMode}
disabled={disabled}
onChange={onToggle}
>
{inOutMode
? 'in/out identifier'
: 'Select column to specify if amount goes in/out'}
</CheckboxOption>
{inOutMode && (
<Input
type="text"
value={outValue}
onUpdate={onChangeText}
placeholder="Value for out rows, i.e. Credit"
/>
)}
</View>
);
}

function FieldMappings({
transactions,
mappings,
onChange,
splitMode,
inOutMode,
hasHeaderRow,
}) {
if (transactions.length === 0) {
Expand Down Expand Up @@ -537,16 +612,30 @@ function FieldMappings({
</View>
</>
) : (
<View style={{ flex: 1 }}>
<SubLabel title="Amount" />
<SelectField
options={options}
value={mappings.amount}
onChange={name => onChange('amount', name)}
hasHeaderRow={hasHeaderRow}
firstTransaction={transactions[0]}
/>
</View>
<>
{inOutMode && (
<View style={{ flex: 1 }}>
<SubLabel title="In/Out" />
<SelectField
options={options}
value={mappings.inOut}
onChange={name => onChange('inOut', name)}
hasHeaderRow={hasHeaderRow}
firstTransaction={transactions[0]}
/>
</View>
)}
<View style={{ flex: 1 }}>
<SubLabel title="Amount" />
<SelectField
options={options}
value={mappings.amount}
onChange={name => onChange('amount', name)}
hasHeaderRow={hasHeaderRow}
firstTransaction={transactions[0]}
/>
</View>
</>
)}
</Stack>
</View>
Expand All @@ -569,6 +658,8 @@ export default function ImportTransactions({ modalProps, options }) {
let [filetype, setFileType] = useState(null);
let [fieldMappings, setFieldMappings] = useState(null);
let [splitMode, setSplitMode] = useState(false);
let [inOutMode, setInOutMode] = useState(false);
let [outValue, setOutValue] = useState('');
let [flipAmount, setFlipAmount] = useState(false);
let [multiplierEnabled, setMultiplierEnabled] = useState(false);
let { accountId, onImported } = options;
Expand Down Expand Up @@ -684,6 +775,8 @@ export default function ImportTransactions({ modalProps, options }) {

let isSplit = !splitMode;
setSplitMode(isSplit);
setInOutMode(false);
setFlipAmount(false);

// Run auto-detection on the fields to try to detect the fields
// automatically
Expand Down Expand Up @@ -749,6 +842,8 @@ export default function ImportTransactions({ modalProps, options }) {
let { amount } = parseAmountFields(
trans,
splitMode,
inOutMode,
outValue,
flipAmount,
multiplierAmount,
);
Expand All @@ -757,7 +852,7 @@ export default function ImportTransactions({ modalProps, options }) {
break;
}

let { inflow, outflow, ...finalTransaction } = trans;
let { inflow, outflow, inOut, ...finalTransaction } = trans;
finalTransactions.push({
...finalTransaction,
date,
Expand Down Expand Up @@ -812,6 +907,9 @@ export default function ImportTransactions({ modalProps, options }) {
{ name: 'Notes', width: 'flex' },
];

if (inOutMode) {
headers.push({ name: 'In/Out', width: 90, style: { textAlign: 'left' } });
}
if (splitMode) {
headers.push({ name: 'Outflow', width: 90, style: { textAlign: 'right' } });
headers.push({ name: 'Inflow', width: 90, style: { textAlign: 'right' } });
Expand Down Expand Up @@ -873,6 +971,8 @@ export default function ImportTransactions({ modalProps, options }) {
dateFormat={dateFormat}
fieldMappings={fieldMappings}
splitMode={splitMode}
inOutMode={inOutMode}
outValue={outValue}
flipAmount={flipAmount}
multiplierAmount={multiplierAmount}
/>
Expand Down Expand Up @@ -905,6 +1005,7 @@ export default function ImportTransactions({ modalProps, options }) {
onChange={onUpdateFields}
mappings={fieldMappings}
splitMode={splitMode}
inOutMode={inOutMode}
hasHeaderRow={hasHeaderRow}
/>
</View>
Expand Down Expand Up @@ -1018,19 +1119,29 @@ export default function ImportTransactions({ modalProps, options }) {
<CheckboxOption
id="form_flip"
checked={flipAmount}
disabled={splitMode}
disabled={splitMode || inOutMode}
onChange={() => setFlipAmount(!flipAmount)}
>
Flip amount
</CheckboxOption>
{filetype === 'csv' && (
<CheckboxOption
id="form_split"
checked={splitMode}
onChange={onSplitMode}
>
Split amount into separate inflow/outflow columns
</CheckboxOption>
<>
<CheckboxOption
id="form_split"
checked={splitMode}
disabled={inOutMode || flipAmount}
onChange={onSplitMode}
>
Split amount into separate inflow/outflow columns
</CheckboxOption>
<InOutOption
inOutMode={inOutMode}
outValue={outValue}
disabled={splitMode || flipAmount}
onToggle={() => setInOutMode(!inOutMode)}
onChangeText={setOutValue}
/>
</>
)}
<MultiplierOption
multiplierEnabled={multiplierEnabled}
Expand Down
2 changes: 2 additions & 0 deletions packages/loot-core/src/server/importers/ynab5-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export namespace YNAB5 {
id: string;
name: string;
deleted: boolean;
transfer_acct?: string;
}

interface CategoryGroup {
Expand Down Expand Up @@ -61,6 +62,7 @@ export namespace YNAB5 {
category_id: string;
memo: string;
amount: number;
transfer_account_id: string;
}

interface Month {
Expand Down
Loading

0 comments on commit 585390a

Please sign in to comment.