Войти Регистрация
Код-ревью

23. Кешбэк по категориям: неочевидные баги

Сложная

Java · 33 строк

Метод считает кешбэк клиента за текущий месяц. Премиальным клиентам — повышенные ставки в категориях по MCC, в остальных категориях и всем прочим клиентам — 1 %. Кешбэк по каждой операции округляется вниз до копейки, возврат покупки вычитает её кешбэк.

getClientId() и getId() возвращают Long, getDate() — java.util.Date. Калькулятор вызывается из многих потоков. Код компилируется. Отметьте строки с ошибками.

В работе: Ежемесячное начисление кешбэка: миллионы клиентов, каждая копейка видна в приложении.

Как проверяем Нажмите на строку с ошибкой и коротко напишите, что не так. Баг засчитан, если отмечена хотя бы одна его строка. Зачёт — найдено не меньше 60 % багов с учётом серьёзности (критичный весит 3, обычный 2, мелкий 1), а лишних отметок не больше, чем багов в коде. Пустые строки, скобки и комментарии лишними не считаем. Ответ один на подход: после него показываем разбор.
BigDecimalавтоупаковкаSimpleDateFormatокругление

Источник: обзор транскриптов интервью: Альфа-Банк, код с неочевидными багами. Условие пересказано своими словами.

Давали на собеседовании? Ответов пока мало — ваш поможет.
  1. public class CashbackCalculator {
  2. private static final SimpleDateFormat MONTH = new SimpleDateFormat("yyyy-MM");
  3. private static final Map<String, BigDecimal> RATES = new HashMap<>();
  4. static {
  5. RATES.put("5411", new BigDecimal("0.05"));
  6. RATES.put("5812", new BigDecimal("0.10"));
  7. RATES.put("5541", new BigDecimal("0.03"));
  8. }
  9. public BigDecimal calculate(Client client, List<Transaction> txs) {
  10. BigDecimal total = BigDecimal.ZERO;
  11. for (Transaction tx : txs) {
  12. if (tx.getClientId() != client.getId()) {
  13. continue;
  14. }
  15. if (!MONTH.format(tx.getDate()).equals(client.getCurrentMonth())) {
  16. continue;
  17. }
  18. BigDecimal rate = client.isPremium() ? RATES.get(tx.getMcc()) : BigDecimal.ONE.divide(new BigDecimal(100));
  19. BigDecimal cashback = tx.getAmount().multiply(rate);
  20. if (tx.getStatus() == Status.REFUND) {
  21. total.subtract(cashback);
  22. } else {
  23. total = total.add(cashback);
  24. }
  25. }
  26. if (total.equals(BigDecimal.ZERO)) {
  27. return BigDecimal.ZERO;
  28. }
  29. return total.setScale(2, RoundingMode.HALF_UP).min(client.getCashbackLimit());
  30. }
  31. }