Java · 55 строк
Клиент заполняет анкету на кредит до 5 млн ₽ под 19,9 % годовых. Контроллер проверяет возраст 21–70 лет и что аннуитетный платёж не больше половины дохода, отсекает повторную анкету за 30 дней и зовёт скоринг.
CreditForm содержит ФИО, серию и номер паспорта, дату рождения, доход, сумму и срок; toString() сгенерирован Lombok. Зарплатные клиенты поле дохода не заполняют — его подтягивают из зарплатного проекта. Скоринг отвечает 2–8 секунд, пул Hikari — 20 соединений. Отметьте строки с ошибками.
В работе: Онлайн-заявка на кредит в СберБанк Онлайн: пик — вечер пятницы и дни зарплаты.
Как проверяем
Нажмите на строку с ошибкой и коротко напишите, что не так. Баг засчитан, если отмечена хотя бы одна его строка. Зачёт — найдено не меньше 60 % багов с учётом серьёзности (критичный весит 3, обычный 2, мелкий 1), а лишних отметок не больше, чем багов в коде. Пустые строки, скобки и комментарии лишними не считаем. Ответ один на подход: после него показываем разбор.
Источник: наша задача на данных Сбера: кредитная анкета и скоринг. Условие пересказано своими словами.
Давали на собеседовании?
@RestController@RequestMapping("/api/credit")public class CreditApplicationController {private static final Logger log = LoggerFactory.getLogger(CreditApplicationController.class);private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000000");private static final double ANNUAL_RATE = 0.199;private final DataSource dataSource;private final ScoringClient scoring;public CreditApplicationController(DataSource dataSource, ScoringClient scoring) {this.dataSource = dataSource;this.scoring = scoring;}@PostMapping("/apply")public ResponseEntity<String> apply(@RequestBody CreditForm form) throws SQLException {log.info("Новая анкета: {}", form);int age = LocalDate.now().getYear() - form.getBirthDate().getYear();if (age < 21 || age > 70) {return ResponseEntity.badRequest().body("Возраст вне диапазона 21–70 лет");}if (form.getAmount().compareTo(MAX_AMOUNT) > 0) {return ResponseEntity.badRequest().body("Сумма больше 5 млн ₽");}BigDecimal payment = monthlyPayment(form.getAmount(), form.getTermMonths());if (payment.compareTo(form.getIncome().multiply(new BigDecimal("0.5"))) > 0) {return ResponseEntity.ok("Отказ: платёж больше половины дохода");}Connection conn = dataSource.getConnection();Statement st = conn.createStatement();ResultSet rs = st.executeQuery("SELECT count(*) FROM applications WHERE passport = '"+ form.getPassport() + "' AND created_at > now() - interval '30 days'");rs.next();if (rs.getInt(1) > 0) {return ResponseEntity.ok("Анкета уже на рассмотрении");}ScoreResult score = scoring.check(form);PreparedStatement ins = conn.prepareStatement("INSERT INTO applications(passport, amount, term, score) VALUES (?, ?, ?, ?)");ins.setString(1, form.getPassport());ins.setBigDecimal(2, form.getAmount());ins.setInt(3, form.getTermMonths());ins.setInt(4, score.getValue());ins.executeUpdate();return ResponseEntity.ok(score.getValue() >= 600 ? "Предварительно одобрено" : "Отказ");}private BigDecimal monthlyPayment(BigDecimal amount, int months) {double r = ANNUAL_RATE;double k = r * Math.pow(1 + r, months) / (Math.pow(1 + r, months) - 1);return new BigDecimal(amount.doubleValue() * k);}}