Skip to content

Instantly share code, notes, and snippets.

@radekstepan
Created May 19, 2024 18:52
Show Gist options
  • Save radekstepan/ed3f8f2a0fe111e0f9693325b8e85b35 to your computer and use it in GitHub Desktop.
Save radekstepan/ed3f8f2a0fe111e0f9693325b8e85b35 to your computer and use it in GitHub Desktop.
import {ratio} from 'fuzzball';
import data from './data.js';
const currencyThresholds = {
USD: 50,
EUR: 40,
GBP: 35,
JPY: 5000,
};
function findMatchingReports(data) {
const expenses = data.expenses;
const reports = data.reports;
for (const expense of expenses) {
let bestMatchReport = null;
let bestMatchScore = 0;
for (const report of reports) {
let bestReportExpenseScore = 0;
let bestReportExpense = null;
// Find the most closely matching expense within the report
for (const reportExpense of report.expenses) {
let expenseScore = 0;
// A - 2 points for matching expense type
if (expense.expenseType === reportExpense.expenseType) {
expenseScore += 2;
}
// B - 0..1 points for matching vendor
const vendorScore = ratio(expense.vendor, reportExpense.vendor);
expenseScore += vendorScore / 100; // normalize to 0..1
// C - 0..1 points for matching amount (exponential distance)
const amountDistance = Math.abs(expense.amount - reportExpense.amount);
const currency = expense.currency || 'USD';
const amountScore = Math.exp(-amountDistance / currencyThresholds[currency]);
expenseScore += amountScore * (
currency === reportExpense.currency ? 1 : 0.2
);
// D - dampen the score for each additional expense in the report
expenseScore *= Math.pow(0.95, report.expenses.length);
// console.log(
// expense.expenseType,
// report.name,
// reportExpense.expenseType,
// expenseScore
// );
// Update the best matching expense within the report
if (expenseScore > bestReportExpenseScore) {
bestReportExpenseScore = expenseScore;
bestReportExpense = reportExpense;
}
}
// Update the best matching report if the current report has a higher score
if (bestReportExpenseScore > bestMatchScore) {
bestMatchScore = bestReportExpenseScore;
bestMatchReport = report;
}
}
// Result 🚀
console.log(expense.expenseType, bestMatchReport.name, bestMatchScore);
// console.log('---');
}
}
findMatchingReports(data);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment