Implement multi-part cost calculator
Company: Stripe
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's ability to implement robust data-processing and numeric computation logic for a multi-part cost calculator, covering input validation, per-item discounts and tax, sorting semantics, multi-currency conversion, and precise monetary rounding.
Part 1: Basic Order Totals with Validation
Constraints
- 0 <= number of orders <= 100000
- 0 <= total number of items across all orders <= 500000
- SKU and order_id values are strings in well-formed inputs
- A valid qty is an int or integer-valued float in the range [1, 10^12]; bool is invalid
- Unit prices should be finite numeric values; invalid catalog prices are reported as invalid_price items
Examples
Input: ({'A': 10.0, 'B': 2.5}, [{'order_id': 'o2', 'items': [{'sku': 'A', 'qty': 2}, {'sku': 'X', 'qty': 5}]}, {'order_id': 'o1', 'items': [{'sku': 'B', 'qty': 4}, {'sku': 'A', 'qty': 0}, {'sku': 'B', 'qty': '3'}]}])
Expected Output: {'results': [{'order_id': 'o1', 'total_cost': 10.0}, {'order_id': 'o2', 'total_cost': 20.0}], 'errors': {'o2': {'missing_skus': ['X']}, 'o1': {'invalid_items': [{'sku': 'A', 'qty': 0, 'reason': 'invalid_qty'}, {'sku': 'B', 'qty': '3', 'reason': 'invalid_qty'}]}}}
Explanation: o1 totals only 4 * 2.5. o2 totals only 2 * 10.0. Results are sorted by order_id.
Input: ({'A': 1.0}, [])
Expected Output: {'results': [], 'errors': {}}
Explanation: Edge case: no orders produces no results and no errors.
Input: ({'A': 3.0}, [{'order_id': 'solo', 'items': []}])
Expected Output: {'results': [{'order_id': 'solo', 'total_cost': 0.0}], 'errors': {}}
Explanation: An order with no items has total 0.
Input: ({'A': 1.0}, [{'order_id': 'o1', 'items': [{'sku': 'A', 'qty': 1000000000000}, {'sku': 'A', 'qty': 1000000000001}, {'sku': 'A', 'qty': 1.5}, {'sku': 'A', 'qty': True}]}])
Expected Output: {'results': [{'order_id': 'o1', 'total_cost': 1000000000000.0}], 'errors': {'o1': {'invalid_items': [{'sku': 'A', 'qty': 1000000000001, 'reason': 'invalid_qty'}, {'sku': 'A', 'qty': 1.5, 'reason': 'invalid_qty'}, {'sku': 'A', 'qty': True, 'reason': 'invalid_qty'}]}}}
Explanation: The maximum allowed qty is valid. Overflow-like, fractional, and boolean quantities are invalid.
Hints
- Separate validation from arithmetic so invalid data never reaches the multiplication step.
- Collect per-order errors while scanning items, then sort only the final results list.
Part 2: Order Totals with Discounts, Tax, and Custom Sorting
Constraints
- 0 <= number of orders <= 100000
- 0 <= total number of items across all orders <= 500000
- Valid qty is an int or integer-valued float in the range [1, 10^12]; bool is invalid
- Valid discount_rate and tax_rate values are finite numbers in [0.0, 1.0]
- sort_by must be order_id or total_cost; otherwise order_id is used
Examples
Input: ({'A': 10.0, 'B': 5.0}, [{'order_id': 'o2', 'tax_rate': 0.1, 'items': [{'sku': 'A', 'qty': 2}]}, {'order_id': 'o1', 'items': [{'sku': 'B', 'qty': 4}]}], {'A': 0.2}, 'order_id', False)
Expected Output: {'results': [{'order_id': 'o1', 'total_cost': 20.0}, {'order_id': 'o2', 'total_cost': 17.6}], 'errors': {}}
Explanation: o2 gets a 20 percent discount on A before 10 percent tax. Results are sorted by order_id.
Input: ({'A': 100.0, 'B': 50.0}, [{'order_id': 'o1', 'tax_rate': -0.1, 'items': [{'sku': 'A', 'qty': 1}, {'sku': 'B', 'qty': 2}, {'sku': 'X', 'qty': 1}]}, {'order_id': 'o2', 'tax_rate': 0.2, 'items': [{'sku': 'B', 'qty': '2'}, {'sku': 'A', 'qty': 1}]}], {'A': 1.2, 'B': 0.5}, 'total_cost', True)
Expected Output: {'results': [{'order_id': 'o1', 'total_cost': 150.0}, {'order_id': 'o2', 'total_cost': 120.0}], 'errors': {'o1': {'missing_skus': ['X'], 'invalid_discounts': [{'sku': 'A', 'discount_rate': 1.2}], 'invalid_tax_rate': -0.1}, 'o2': {'invalid_items': [{'sku': 'B', 'qty': '2', 'reason': 'invalid_qty'}], 'invalid_discounts': [{'sku': 'A', 'discount_rate': 1.2}]}}}
Explanation: Invalid discount on A is ignored. Invalid tax on o1 is treated as 0. Results are sorted by total_cost descending.
Input: ({'A': 1.0}, [], None, 'order_id', False)
Expected Output: {'results': [], 'errors': {}}
Explanation: Edge case: empty order list.
Input: ({'A': 10.0, 'B': 20.0}, [{'order_id': 'edge', 'tax_rate': 1.0, 'items': [{'sku': 'A', 'qty': 3}, {'sku': 'B', 'qty': 1}]}], {'A': 1.0, 'B': 0.0}, 'total_cost', False)
Expected Output: {'results': [{'order_id': 'edge', 'total_cost': 40.0}], 'errors': {}}
Explanation: A has a full discount, B has no discount, and 100 percent tax doubles the remaining subtotal.
Input: ({'A': 2.0}, [{'order_id': 'b', 'items': [{'sku': 'A', 'qty': 1}]}, {'order_id': 'a', 'items': [{'sku': 'A', 'qty': 3}]}], {}, 'sku', False)
Expected Output: {'results': [{'order_id': 'a', 'total_cost': 6.0}, {'order_id': 'b', 'total_cost': 2.0}], 'errors': {'__global__': {'invalid_sort_by': 'sku'}}}
Explanation: Invalid sort_by is reported and sorting falls back to order_id ascending.
Hints
- Apply discounts before tax, and apply tax once to the order subtotal.
- For deterministic sorting by total_cost, include order_id as a secondary key.
Part 3: Multi-Currency Order Totals with Banker's Rounding
Constraints
- 0 <= number of orders <= 100000
- 0 <= total number of items across all orders <= 500000
- Valid qty is an int or integer-valued float in the range [1, 10^12]; bool is invalid
- Valid discount_rate and tax_rate values are finite numbers in [0.0, 1.0]
- Required currency rates must be finite positive numbers
- Rounded outputs must use ROUND_HALF_EVEN to two decimal places
Examples
Input: ({'A': 10.0, 'B': 5.0}, [{'order_id': 'e1', 'currency': 'EUR', 'items': [{'sku': 'A', 'qty': 1}, {'sku': 'B', 'qty': 2}]}, {'order_id': 'u1', 'currency': 'USD', 'items': [{'sku': 'A', 'qty': 3}]}], {'USD': 1.0, 'EUR': 1.2}, 'USD')
Expected Output: {'results': [{'order_id': 'e1', 'total_cost': 24.0, 'currency': 'USD'}, {'order_id': 'u1', 'total_cost': 30.0, 'currency': 'USD'}], 'errors': {}}
Explanation: e1 totals 20 EUR, converted to 24 USD. u1 is already in USD.
Input: ({'A': 10.0}, [{'order_id': 'd1', 'currency': 'EUR', 'tax_rate': 0.1, 'items': [{'sku': 'A', 'qty': 3}]}], {'USD': 1.0, 'EUR': 1.2}, 'USD', {'A': 0.1})
Expected Output: {'results': [{'order_id': 'd1', 'total_cost': 35.64, 'currency': 'USD'}], 'errors': {}}
Explanation: 3 * 10 with 10 percent discount is 27 EUR. After 10 percent tax it is 29.7 EUR, converted to 35.64 USD.
Input: ({'P': 2.685}, [{'order_id': 'r1', 'currency': 'USD', 'items': [{'sku': 'P', 'qty': 1}]}], {'USD': 1.0}, 'USD')
Expected Output: {'results': [{'order_id': 'r1', 'total_cost': 2.68, 'currency': 'USD'}], 'errors': {}}
Explanation: Banker's rounding sends 2.685 to 2.68 because the hundredths digit 8 is even.
Input: ({'A': 10.0}, [{'order_id': 'e', 'currency': 'EUR', 'items': [{'sku': 'A', 'qty': 1}]}, {'order_id': 'g', 'currency': 'GBP', 'items': [{'sku': 'A', 'qty': 1}]}, {'order_id': 'u', 'currency': 'USD', 'items': [{'sku': 'A', 'qty': 1}]}], {'USD': 1.0, 'EUR': 'bad'}, 'USD')
Expected Output: {'results': [{'order_id': 'e', 'total_cost': None, 'currency': 'USD'}, {'order_id': 'g', 'total_cost': None, 'currency': 'USD'}, {'order_id': 'u', 'total_cost': 10.0, 'currency': 'USD'}], 'errors': {'e': {'invalid_rates': [{'currency': 'EUR', 'rate': 'bad'}]}, 'g': {'missing_rates': ['GBP']}}}
Explanation: EUR has an invalid rate, GBP is missing, and USD needs no conversion.
Input: ({'A': 10.0}, [{'order_id': 'x', 'currency': 'USD', 'tax_rate': 1.5, 'items': [{'sku': 'A', 'qty': 1}, {'sku': 'Z', 'qty': 1}, {'sku': 'A', 'qty': 0}]}], {'USD': 1.0}, 'USD', {'A': -0.2})
Expected Output: {'results': [{'order_id': 'x', 'total_cost': 10.0, 'currency': 'USD'}], 'errors': {'x': {'missing_skus': ['Z'], 'invalid_items': [{'sku': 'A', 'qty': 0, 'reason': 'invalid_qty'}], 'invalid_discounts': [{'sku': 'A', 'discount_rate': -0.2}], 'invalid_tax_rate': 1.5}}}
Explanation: The valid A item is charged without discount or tax because both rates are invalid. Missing SKU and invalid qty are reported.
Hints
- Use decimal arithmetic or carefully specified rounding; binary float round-off can change half-cent cases.
- Compute in this order: validate items, apply discounts, apply tax, convert currency, then round.