74 lines
1.9 KiB
TypeScript
74 lines
1.9 KiB
TypeScript
export type SuggestionSource = {
|
|
description: string;
|
|
amountCents: number;
|
|
accountId: number | null;
|
|
date: string;
|
|
};
|
|
|
|
export type Suggestion = {
|
|
key: string;
|
|
description: string;
|
|
/** Most common amount for this description (latest wins ties). */
|
|
amountCents: number;
|
|
/** Account used most recently with this description. */
|
|
accountId: number | null;
|
|
count: number;
|
|
lastDate: string;
|
|
};
|
|
|
|
/** Past descriptions ranked by use, each with its usual amount and latest account. */
|
|
export function descriptionSuggestions(rows: SuggestionSource[], today: string): Suggestion[] {
|
|
const groups = new Map<
|
|
string,
|
|
{
|
|
description: string;
|
|
amounts: Map<number, number>;
|
|
accountId: number | null;
|
|
count: number;
|
|
lastDate: string;
|
|
lastAmount: number;
|
|
}
|
|
>();
|
|
for (const row of rows) {
|
|
if (row.date > today) continue;
|
|
const key = row.description.trim().toLowerCase();
|
|
if (!key) continue;
|
|
const group = groups.get(key) ?? {
|
|
description: row.description.trim(),
|
|
amounts: new Map(),
|
|
accountId: row.accountId,
|
|
count: 0,
|
|
lastDate: '',
|
|
lastAmount: row.amountCents
|
|
};
|
|
group.count++;
|
|
group.amounts.set(row.amountCents, (group.amounts.get(row.amountCents) ?? 0) + 1);
|
|
if (row.date >= group.lastDate) {
|
|
group.lastDate = row.date;
|
|
group.description = row.description.trim();
|
|
group.accountId = row.accountId;
|
|
group.lastAmount = row.amountCents;
|
|
}
|
|
groups.set(key, group);
|
|
}
|
|
return [...groups.entries()]
|
|
.map(([key, group]) => {
|
|
let amountCents = group.lastAmount;
|
|
let best = group.amounts.get(amountCents) ?? 0;
|
|
for (const [value, uses] of group.amounts)
|
|
if (uses > best) {
|
|
best = uses;
|
|
amountCents = value;
|
|
}
|
|
return {
|
|
key,
|
|
description: group.description,
|
|
amountCents,
|
|
accountId: group.accountId,
|
|
count: group.count,
|
|
lastDate: group.lastDate
|
|
};
|
|
})
|
|
.sort((a, b) => b.count - a.count || b.lastDate.localeCompare(a.lastDate));
|
|
}
|