mirror of
https://github.com/actualbudget/actual.git
synced 2026-10-12 02:10:19 +00:00
Resolve payee name during rule evaluation (#8360)
When a rule action sets payee_name, resolve it to the actual payee ID immediately during rule execution instead of waiting until finalization. This allows later staged rules to match on the resolved payee. Previously, payee_name actions temporarily set payee to "new", and the real payee ID was only resolved in finalizeTransactionForRules after rule matching had completed. Fixes #8359
This commit is contained in:
@@ -220,6 +220,42 @@ describe('Transaction rules', () => {
|
||||
expect(transaction.category).toBe(null);
|
||||
});
|
||||
|
||||
test('payee rules match after a staged formula sets payee name', async () => {
|
||||
await loadRules();
|
||||
|
||||
await db.insertPayee({ id: 'amazon_id', name: 'Amazon' });
|
||||
|
||||
await insertRule({
|
||||
stage: 'pre',
|
||||
conditionsOp: 'and',
|
||||
conditions: [{ op: 'is', field: 'imported_payee', value: 'AMZN MKTP' }],
|
||||
actions: [
|
||||
{
|
||||
op: 'set',
|
||||
field: 'payee_name',
|
||||
value: null,
|
||||
options: { formula: '="Amazon"' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await insertRule({
|
||||
stage: null,
|
||||
conditionsOp: 'and',
|
||||
conditions: [{ op: 'is', field: 'payee', value: 'amazon_id' }],
|
||||
actions: [{ op: 'set', field: 'category', value: 'shopping' }],
|
||||
});
|
||||
|
||||
const transaction = await runRules({
|
||||
imported_payee: 'AMZN MKTP',
|
||||
payee: null,
|
||||
category: null,
|
||||
});
|
||||
|
||||
expect(transaction.payee).toBe('amazon_id');
|
||||
expect(transaction.category).toBe('shopping');
|
||||
});
|
||||
|
||||
test('loadRules loads all the rules', async () => {
|
||||
await loadRules();
|
||||
await insertRule({
|
||||
|
||||
@@ -370,16 +370,19 @@ export async function runRules(
|
||||
// bypass condition checking to run the rule even if the transaction date falls outside of the schedule's date range.
|
||||
const changes = rules[i].execActions(finalTrans);
|
||||
finalTrans = Object.assign({}, finalTrans, changes);
|
||||
await resolvePayeeNameForRules(finalTrans);
|
||||
} else if (RuleIdsLinkedToSchedules.includes(rules[i].id)) {
|
||||
// skip all other rules that are linked to other schedules.
|
||||
continue;
|
||||
} else {
|
||||
// if a rule is not linked to a schedule, run it.
|
||||
finalTrans = rules[i].apply(finalTrans);
|
||||
await resolvePayeeNameForRules(finalTrans);
|
||||
}
|
||||
} else {
|
||||
// if there is no scheduleRuleID then just run all rules.
|
||||
finalTrans = rules[i].apply(finalTrans);
|
||||
await resolvePayeeNameForRules(finalTrans);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1098,23 +1101,30 @@ export async function prepareTransactionForRules(
|
||||
return r;
|
||||
}
|
||||
|
||||
async function resolvePayeeNameForRules(
|
||||
trans: TransactionEntity | TransactionForRules,
|
||||
): Promise<void> {
|
||||
if (!('payee_name' in trans) || trans.payee !== 'new') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trans.payee_name) {
|
||||
let payee_id = (await getPayeeByName(trans.payee_name))?.id;
|
||||
payee_id ??= await insertPayee({
|
||||
name: trans.payee_name,
|
||||
});
|
||||
|
||||
trans.payee = payee_id;
|
||||
} else {
|
||||
trans.payee = null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function finalizeTransactionForRules(
|
||||
trans: TransactionEntity | TransactionForRules,
|
||||
): Promise<TransactionEntity> {
|
||||
if ('payee_name' in trans) {
|
||||
if (trans.payee === 'new') {
|
||||
if (trans.payee_name) {
|
||||
let payeeId = (await getPayeeByName(trans.payee_name))?.id;
|
||||
payeeId ??= await insertPayee({
|
||||
name: trans.payee_name,
|
||||
});
|
||||
|
||||
trans.payee = payeeId;
|
||||
} else {
|
||||
trans.payee = null;
|
||||
}
|
||||
}
|
||||
|
||||
await resolvePayeeNameForRules(trans);
|
||||
delete trans.payee_name;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Bugfixes
|
||||
authors: [julienvincent]
|
||||
---
|
||||
|
||||
When a rule action sets payee_name, resolve it to the actual payee ID immediately during rule execution instead of waiting until finalization.
|
||||
Reference in New Issue
Block a user