Katkat

Match payments to invoices by memo or amount

GoogleData Scientist · Technical Screen

Last updated

This problem tests string parsing, hash-map based data indexing, and multi-criteria reconciliation logic (fuzzy matching via IDs vs. exact matching via amount).

Problem Statement

You are provided with two lists: a list of invoices and a list of payments. Each invoice has an id and an amount. Each payment has an amount, a memo string, and a date.

Your task is to reconcile these lists according to the following precedence rules:

  1. ID Match: If an invoice id is found anywhere inside a payment's memo (as a substring), match them. If multiple invoices match a single payment memo, prioritize the one with the highest amount.
  2. Amount Match: If no invoice ID is found in the memo, match the payment to an unpaid invoice with the exact same amount.
  3. Tie-breaking: If multiple invoices have the same amount, match the payment to the invoice with the earliest date.

Function Signature

def reconcile_payments(invoices, payments):
    # invoices: List of dicts {'id': str, 'amount': float, 'date': str}
    # payments: List of dicts {'amount': float, 'memo': str, 'date': str}
    # Return a list of tuples: (payment_index, matched_invoice_id)
    pass

Example

Input: invoices = [{'id': 'INV-001', 'amount': 100.0, 'date': '2023-01-01'}, {'id': 'INV-002', 'amount': 200.0, 'date': '2023-01-02'}] payments = [{'amount': 100.0, 'memo': 'Paid INV-001'}, {'amount': 200.0, 'memo': 'Final balance'}]

Output: [(0, 'INV-001'), (1, 'INV-002')]

Constraints

  • Number of invoices and payments: up to 10,000 each.
  • Invoice IDs are unique.
  • Each payment can be matched to at most one invoice.

Hints

Hint 1

Use a hash map to group invoices by their amount for O(1) lookups during the amount-matching phase.

Hint 2

For the ID-based matching, consider pre-processing the invoice IDs into a set or using a regex-friendly structure if IDs are complex.

Hint 3

Maintain a set of matched invoice IDs to ensure each invoice is only reconciled once.

Follow-up questions

  • How would you optimize the solution if the invoice list was so large it could not fit into memory?
  • What changes are required if the payment amount is allowed to match a total of multiple invoices (e.g., one payment covers two smaller invoices)?
  • How would you handle 'near-match' amounts (e.g., payments within 1% of the invoice amount)?