PracHub
QuestionsCoachesLearningGuidesInterview Prep

Quick Overview

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.

  • medium
  • Stripe
  • Coding & Algorithms
  • Software Engineer

Implement multi-part cost calculator

Company: Stripe

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

You are given a price catalog and a list of orders. Implement the following in any language (Python examples acceptable): Inputs - price_catalog: mapping from sku (string) -> unit_price (float). - orders: list of orders; each order has: - order_id (string) - items: list of { sku: string, qty: integer } Part 1 — Basic totals - For each order, compute total_cost = sum(qty * unit_price) over its valid items. - Validations and corner cases: - If an item's sku is not in price_catalog, skip that item and record it in a per-order "missing_skus" list. - If qty is non-numeric, non-integer, <= 0, or overflows type limits, treat it as invalid; skip and record in a per-order "invalid_items" list. - Do not crash on malformed input; return both results and an "errors" structure. - Output: list of { order_id, total_cost } sorted by order_id ascending. In Python, show the lambda used for sorting; in other languages, provide the equivalent. Part 2 — Discounts and tax - Extend inputs to support optional per-item discounts: discounts: mapping sku -> discount_rate (0.0–1. 0), and optional per-order tax_rate (0.0–1. 0). - Compute total_cost = (sum over items of qty * unit_price * (1 - discount_rate))) * (1 + tax_rate). - Validate numeric ranges for discount_rate and tax_rate; out-of-range values should be treated as invalid and reported. - Allow the caller to choose sorting: by "order_id" or by "total_cost", ascending or descending (demonstrate the sort key/compare function; in Python show the lambda). Part 3 — Multi-currency and rounding - Extend orders with optional currency code (e.g., "USD", "EUR"). Given a rates mapping base->target (e.g., usd_per_unit: mapping currency -> rate), convert each order’s total into a target_currency parameter (default "USD"). - Validate that required conversion rates exist and are numeric; report missing or invalid rates. - Round monetary outputs to two decimals with banker's rounding (or specify the rounding mode you choose and apply it consistently). Complexity and robustness - State the time and space complexity of your implementation for each part, and discuss how you would handle very large inputs (streaming, batching, or memory constraints). - Provide a brief test plan that covers normal cases, missing_skus, invalid qty, extreme numeric values, discount/tax edge cases, sorting correctness, and currency conversion failures.

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

Given a price catalog mapping SKU strings to unit prices and a list of orders, compute the total cost of each order. Each order has an order_id and an items list. Each item has a sku and qty. Only valid items contribute to the total. If an item SKU is missing from the catalog, skip it and report it in that order's missing_skus list. If qty is non-numeric, non-integer, <= 0, boolean, or greater than 10^12, skip it and report it in invalid_items. Return totals sorted by order_id ascending. The intended Python sort is results.sort(key=lambda row: row['order_id']).

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

  1. Separate validation from arithmetic so invalid data never reaches the multiplication step.
  2. Collect per-order errors while scanning items, then sort only the final results list.

Part 2: Order Totals with Discounts, Tax, and Custom Sorting

Extend the basic order total calculator with optional per-item discounts and optional per-order tax. discounts maps SKU to discount_rate, where a valid rate is in [0.0, 1.0]. Each order may include tax_rate, also valid only in [0.0, 1.0]. The pre-tax item cost is qty * unit_price * (1 - discount_rate). Invalid discounts are reported and ignored, meaning the item is charged with no discount. Invalid tax rates are reported and treated as 0 tax. The caller chooses sorting by order_id or total_cost and ascending or descending order.

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

  1. Apply discounts before tax, and apply tax once to the order subtotal.
  2. For deterministic sorting by total_cost, include order_id as a secondary key.

Part 3: Multi-Currency Order Totals with Banker's Rounding

Extend the order calculator to support order currencies and conversion to a requested target currency. Each order may include currency; missing currency defaults to USD. rates maps a currency code to the value of one unit of that currency in a common base currency, such as USD per unit. To convert an amount from source currency to target currency, use amount * rates[source] / rates[target]. If source and target are the same, no conversion rate is required. Apply optional per-SKU discounts and optional per-order tax as in Part 2, then convert, then round monetary outputs to two decimals using banker's rounding, also called ROUND_HALF_EVEN. If a required rate is missing or invalid, that order's total_cost is None and the rate problem is reported.

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

  1. Use decimal arithmetic or carefully specified rounding; binary float round-off can change half-cent cases.
  2. Compute in this order: validate items, apply discounts, apply tax, convert currency, then round.
Last updated: Jun 22, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Assign Reviewers from Changed Files - Stripe (medium)
  • Generate Account Email Notifications - Stripe (medium)
  • Calculate Transaction Fees - Stripe (medium)
  • Build an Account Transfer Ledger - Stripe (medium)
  • Implement Validation and String Compression - Stripe (hard)