FastPrepSplit Tender Payments with Expiration and Refunds

Split Tender Payments with Expiration and Refunds

Stripe logoStripe● HardFULLTIMEINTERNOAPHONE SCREEN
Learn

Problem statement

Process a chronological stream of split-tender payment events. Pay each purchase from the customer's available gift cards first, then charge the remaining principal plus the applicable regional surcharge to a credit card. Track gift-card expiration, deterministic spending order and refunds.

Inputs

events contains comma-separated lines in input order:

timestamp,ADD_GIFTCARD,customer_id,card_id,amount,valid_before
timestamp,CHARGE,charge_id,customer_id,amount,zip_code
timestamp,REFUND,charge_id,refund_amount

surchargeRates contains non-overlapping inclusive ZIP-code ranges formatted as start_zip-end_zip:rate, such as 90000-99999:0.05. ZIP codes are five-digit strings. Every monetary amount is a non-negative integer number of cents; rates are decimal fractions. Each surcharge is guaranteed to be a whole number of cents, so no rounding is needed.

Gift Cards and Charges

  • ADD_GIFTCARD creates the named customer's gift card with its own balance and expiration timestamp.
  • At charge timestamp T, a finite-expiration card is valid only when T < valid_before. At or after expiration its remaining balance is permanently voided.
  • Spend valid cards in ascending expiration order, breaking equal-expiration ties by lexicographic card ID. Never-expiring cards follow every valid finite-expiration card. Completely drain one card before using the next.
  • After gift-card deductions, apply the matching ZIP-code surcharge only to the remaining credit-card principal. The rate is zero when no range matches.

Refunds

Each REFUND refers to an earlier charge and occurs at most once for that charge. Its amount does not exceed the total originally paid, including any surcharge. Refund the credit card first up to the actual credit-card amount charged, including its surcharge. Return any remainder as a new never-expiring gift card named REFUND_{charge_id} for the original customer. That card participates in later purchases under the same spending rules.

Output

Return one string for every input event in the same order:

  • ADD_GIFTCARD: an empty string.
  • CHARGE: CC_CHARGE_AMOUNT, followed by ,CARD_ID:AMOUNT_USED for each positively debited card. Sort these card entries lexicographically by ID, independently of their spending order. When no card is used, return only the credit-card amount.
  • REFUND: CC_REFUND,GC_REFUND.

For this exercise, assume equal-timestamp events retain input order, supplied gift cards have finite non-negative expiration timestamps, and user-supplied card IDs cannot collide with the reserved REFUND_ prefix. Refund-created cards are the never-expiring cards in this finite event adapter.

Function

processEvents(events: String[], surchargeRates: String[]) → String[]

Examples

Example 1

events = ["1,ADD_GIFTCARD,cust1,gc1,5000,10","2,ADD_GIFTCARD,cust2,gc2,2000,15","3,CHARGE,chg1,cust2,3000,10000","4,CHARGE,chg2,cust1,3000,10000"]surchargeRates = []return = ["","","1000,gc2:2000","0,gc1:3000"]

The first purchase drains gc2 and charges 1000 cents to the credit card. The second consumes 3000 cents from gc1.

Example 2

events = ["1,ADD_GIFTCARD,cust1,gc1,5000,10","2,ADD_GIFTCARD,cust1,gc2,4000,5","3,CHARGE,chg1,cust1,6000,10000","11,CHARGE,chg2,cust1,1000,10000"]surchargeRates = []return = ["","","0,gc1:2000,gc2:4000","1000"]

gc2 expires first and is drained before gc1; output card IDs are sorted independently. At timestamp 11 the remaining gc1 balance is expired.

Example 3

events = ["1,ADD_GIFTCARD,cust1,gc1,5000,10","2,CHARGE,chg1,cust1,15000,90210"]surchargeRates = ["80000-89999:0.02","90000-99999:0.05"]return = ["","10500,gc1:5000"]

The gift card covers 5000 cents. The 10000 cent credit-card principal receives a 500 cent surcharge.

Example 4

events = ["1,ADD_GIFTCARD,cust1,gc1,5000,10","2,CHARGE,chg1,cust1,15000,90210","3,REFUND,chg1,12000"]surchargeRates = ["90000-99999:0.05"]return = ["","10500,gc1:5000","10500,1500"]

The refund first returns all 10500 cents actually charged to the credit card. The remaining 1500 cents create the never-expiring REFUND_chg1 card.

Constraints

  • 1 <= events.length <= 100000 and 0 <= surchargeRates.length <= 10000.
  • Events are well-formed and timestamps are nondecreasing; timestamps and finite expirations are integers from 0 to 10^9.
  • Amounts are integer cents from 0 to 10^9. Running balances and all intermediate money arithmetic fit signed 64-bit integers.
  • Customer, card and charge IDs contain letters, digits or underscores and have length from 1 to 64. User-supplied card IDs do not begin with REFUND_.
  • Charge IDs are unique, supplied card IDs are unique, refunds reference a prior charge and each charge has at most one refund.
  • Surcharge ranges are valid, inclusive and non-overlapping; rates are between 0 and 1 with at most six fractional digits. Credit-card principal multiplied by its rate is an integer.

More Stripe problems

See Stripe hiring insights
public String[] processEvents(String[] events, String[] surchargeRates) {
    // write your code here
}
events["1,ADD_GIFTCARD,cust1,gc1,5000,10","2,ADD_GIFTCARD,cust2,gc2,2000,15","3,CHARGE,chg1,cust2,3000,10000","4,CHARGE,chg2,cust1,3000,10000"]
surchargeRates[]
expected["", "", "1000,gc2:2000", "0,gc1:3000"]
Checking account…