Split Tender Transactions Part 1 - Basic Split Tendering
Problem statement
Many of Stripe's merchants rely on Stripe Terminal to accept in-person payments at the point of sale. In physical retail, it's common for a customer to cover a purchase with multiple payment methods. For example, they might cover a $100 purchase with a $40 gift card combined with a $60 credit card. This is called a split-tender transaction, and supporting it is a key requirement for retail merchants on Terminal.
For this multi-part question, we will be writing a system to process split-tender payments. When a transaction occurs, the system first deducts from the customer's available gift card balance, then charges the remaining balance to the customer's credit card. Given a chronological stream of payment events, your task is to calculate the correct credit card charge for each transaction. The question is broken down into four parts, each introducing a new event type: gift card expiration, regional credit card surcharges, and complex refund logic.
Function
processEvents(events: String[]) → String[] Complete the source function process_events in the editor below. FastPrep exposes the language-adapted method name processEvents.
Function Parameters
string events[n]: lines for each event in chronological order. Lines have a format defined by one of three schemas:
timestamp,ADD_GIFTCARD,customer_id,card_id,amount,valid_before
timestamp,CHARGE,charge_id,customer_id,amount,zip_code
timestamp,REFUND,charge_id,refund_amountstring surcharge_rates[m]: a list of non-overlapping ZIP-code ranges mapped to a surcharge percentage in the format start_zip-end_zip:rate, where start and end are inclusive. Example: 90000-99999:0.05 (representing 5%).
Part 1 practice adapter: the judged Part 1 input contains only ADD_GIFTCARD and CHARGE events and therefore exposes only events. The source-wide surcharge_rates parameter and REFUND schema are retained above for fidelity but belong to later parts.
Returns. string[n]: an array of strings, one per input event, in the same order. For CHARGE events, return the formatted charge string using the schema below. For all other event types, return an empty string "". The length of the output array must exactly match the length of the input events array.
CC_CHARGE_AMOUNT,GIFT_CARD_ID_1:AMOUNT_USED,GIFT_CARD_ID_2:AMOUNT_USEDPart 1: Basic split tendering
For Part 1, process ADD_GIFTCARD and CHARGE events. All customer balances start at 0.
When an ADD_GIFTCARD event is received, add the specified amount to the designated customer's total gift card balance. Return an empty string "".
When a CHARGE event is received, attempt to cover the transaction cost using the customer's available gift card balance first.
- If the gift card balance is greater than or equal to the charge amount, deduct the charge amount from the gift card balance. The credit card charge is 0.
- If the charge amount exceeds the gift card balance, drain the entire gift card balance to 0. The remaining unpaid amount becomes the credit card charge.
Output Format for CHARGE
Return a string starting with the credit card charge, followed by a comma-separated list of the gift cards debited and their amounts (CARD_ID:AMOUNT). If no gift cards were debited, output only the credit card charge.
CC_CHARGE_AMOUNT,GIFT_CARD_ID_1:AMOUNT_USED,GIFT_CARD_ID_2:AMOUNT_USEDNote
In Part 1, each customer will hold at most one active gift card at a time. You do not need to implement card prioritization or sorting logic until Part 2.
Later-Part Context from the Related Caption (Not Judged)
The related caption explains that later parts remove expired cards, prioritize earlier expiration dates and then card IDs, apply a ZIP-code credit-card surcharge, record the actual credit-card portion for refunds, and turn any refund beyond that portion into a new never-expiring gift card. It also suggests heaps for avoiding repeated gift-card sorting and sorting only the gift cards actually used for output. None of those later-part rules changes the judged Part 1 behavior above.
Source Example
Suppose we receive the following events in order. Example 1 below reproduces the source input and output.
Examples
Example 1
events = ["1,ADD_GIFTCARD,cust1,gc1,50,10","2,ADD_GIFTCARD,cust2,gc2,20,15","3,CHARGE,chg1,cust2,30,10000","4,CHARGE,chg2,cust1,30,10000"]return = ["","","10.00,gc2:20.00","0.00,gc1:30.00"]The first two events load 50.00 onto gc1 and 20.00 onto gc2. The first charge drains gc2 and charges the remaining 10.00 to the credit card. The second charge uses 30.00 from gc1, so its credit-card amount is 0.00.
Example 2
events = ["1,CHARGE,ch1,cust1,12.50,94105"]return = ["12.50"]cust1 has no gift-card balance, so the entire 12.50 charge goes to the credit card.
Example 3
events = ["1,ADD_GIFTCARD,cust1,gc1,25.50,50","2,CHARGE,ch1,cust1,10.25,10000","3,CHARGE,ch2,cust1,20.00,10000"]return = ["","0.00,gc1:10.25","4.75,gc1:15.25"]The first charge uses 10.25 from gc1, leaving 15.25. The next charge drains that balance and puts the remaining 4.75 on the credit card.
Constraints
- Source-wide: events are in chronological order by
timestamp. - Source-wide: all event lines are well-formed.
- Source-wide decimal places: all amounts are non-negative values with at most two decimal places. Surcharge rates are chosen such that all intermediate and final monetary calculations also produce values with at most two decimal places. No rounding is required.
- Source-wide:
charge_idvalues are unique acrossCHARGEevents. - Source-wide:
REFUNDevents always reference a priorCHARGEevent. - Source-wide: each
charge_idwill receive at most oneREFUNDevent. - Source-wide:
card_idvalues fromADD_GIFTCARDevents are unique. - Source-wide:
surcharge_ratescontains non-overlapping, valid ZIP-code ranges. - Source-wide:
zip_codevalues are five-digit numeric strings. - Part 1:
1 <= events.length <= 10^5. - Part 1: test cases contain only
ADD_GIFTCARDandCHARGEevents. - Part 1: each customer has at most one active gift card at a time.
- FastPrep execution assumption: events with equal timestamps are processed in input-array order.
- FastPrep execution assumption: every running balance fits in a signed 64-bit integer number of cents.
- FastPrep execution assumption: identifiers contain no commas.
- Part 1: the
valid_beforeandzip_codefields are syntactically valid but do not affect this part; expiration, prioritization, surcharge, and refund behavior belongs to later parts.