CodingSoftware Engineer
Create a payment-reconciliation system that associates received payments with unpaid invoices. The matching behavior grows in sophistication through three stages:
Payment (one string):
"payment-id, amount, memo"
payment-id: A payment's unique identifier.amount: The received payment amount, expressed as an integer number of cents.memo: A payment note that can include an invoice reference.Invoices (an array of strings):
[
"invoice-id, due-date, amount",
"invoice-id, due-date, amount",
...
]
invoice-id: A unique invoice identifier.due-date: The invoice deadline, formatted as YYYY-MM-DD.amount: The invoice total, represented as integer cents.Return a string that reports the successful reconciliation:
"Payment {payment-id} paid {amount} for invoice {invoice-id} due on {date}"
When no invoice qualifies, return:
"Payment {payment-id} could not be matched to any invoice"
Write reconcile_payment(payment, invoices) to pair a payment with an invoice when its memo directly names an invoice ID.
A memo can contain either "paying for: invoice-id" or "Paying off: invoice-id", without regard to letter casing. Obtain that invoice ID and locate the corresponding invoice.
Input:
payment = "payment-014, 750, PAYING FOR: inv-842"
invoices = [
"inv-731, 2024-06-18, 750",
"inv-842, 2024-05-09, 750",
"inv-963, 2024-04-27, 300"
]
Output:
"Payment payment-014 paid 750 for invoice inv-842 due on 2024-05-09"
"paying for: inv-842".Enhance the solution for payments whose memos do not name a particular invoice. If the memo does not yield an invoice ID, find an invoice whose amount equals the payment amount exactly.
When several invoices have that amount, use the one with the earliest due date.
ID-based behavior from Part 1 must remain supported, and an ID match must be attempted before an amount match.
Input:
payment = "payment-027, 600, Service renewal"
invoices = [
"inv-110, 2024-07-14, 900",
"inv-220, 2024-05-16, 600",
"inv-330, 2024-06-03, 600",
"inv-440, 2024-04-08, 600"
]
Output:
"Payment payment-027 paid 600 for invoice inv-440 due on 2024-04-08"
Note: inv-440 wins because it is due first among the invoices totaling 600.
Wire transfers can lose value to fees or differ slightly because of rounding. For instance, an invoice may be for $100, but a $2 bank charge can mean that only $98 arrives. Reconcile these close, rather than identical, values.
Introduce a third strategy: amount matching with a forgiveness threshold. Extend the function signature to reconcile_payment(payment, invoices, forgiveness=0), where forgiveness is the additional threshold parameter. If no exact amount candidate exists, consider invoices whose total falls within ±forgiveness of the received payment. If several invoices meet that condition, choose the one with the earliest due date.
Matching Priority:
Input:
payment = "payment-038, 118, Client remittance"
invoices = [
"inv-510, 2024-06-21, 120",
"inv-620, 2024-05-12, 118",
"inv-730, 2024-04-04, 122"
]
forgiveness = 5
Output:
"Payment payment-038 paid 118 for invoice inv-620 due on 2024-05-12"
Note: inv-620 is an exact amount match, so it is preferred to inv-510, even though that invoice also lies inside the forgiveness range.
Another Example with Fuzzy Match:
payment = "payment-049, 76, Client remittance"
invoices = [
"inv-510, 2024-06-21, 80",
"inv-730, 2024-04-04, 78"
]
forgiveness = 5
Output:
"Payment payment-049 paid 76 for invoice inv-730 due on 2024-04-04"
Note: Both invoices differ from 76 by no more than 5, so inv-730 is chosen because its due date comes earlier.
forgiveness as one more function parameter.[payment_amount - forgiveness, payment_amount + forgiveness].When building tests, make sure that:
forgiveness=5 with a difference of 5.Question: How would you construct test cases that prove the priority rules work properly throughout all three parts?