public LoanWrapper(final LoanDescriptor original) { super(original); this.loan = original.item(); }
@Override public Stream<RecommendedLoan> recommend(final Collection<LoanDescriptor> loans, final PortfolioOverview portfolio, final Restrictions restrictions) { if (!Util.isAcceptable(strategy, portfolio)) { return Stream.empty(); } // split available marketplace into buckets per rating final Map<Rating, List<LoanDescriptor>> splitByRating = Util.sortByRating(strategy.getApplicableLoans(loans), d -> d.item().getRating()); // and now return recommendations in the order in which investment should be attempted final BigDecimal balance = portfolio.getCzkAvailable(); final InvestmentSizeRecommender recommender = new InvestmentSizeRecommender(strategy, restrictions); return Util.rankRatingsByDemand(strategy, splitByRating.keySet(), portfolio) .peek(rating -> Decisions.report(logger -> logger.trace("Processing rating {}.", rating))) .flatMap(rating -> splitByRating.get(rating).stream().sorted(COMPARATOR)) .peek(d -> Decisions.report(logger -> logger.trace("Evaluating {}.", d.item()))) .flatMap(d -> { // recommend amount to invest per strategy final int recommendedAmount = recommender.apply(d.item(), balance.intValue()); if (recommendedAmount > 0) { return d.recommend(recommendedAmount, needsConfirmation(d)) .map(Stream::of) .orElse(Stream.empty()); } else { return Stream.empty(); } }); } }
private static boolean isActionable(final LoanDescriptor loanDescriptor) { final OffsetDateTime now = DateUtil.offsetNow(); return loanDescriptor.getLoanCaptchaProtectionEndDateTime() .map(d -> d.isBefore(now)) .orElse(true); }
private static LoanDescriptor mockLoanDescriptor() { final Loan loan = RecommendedLoanTest.mockLoan(); return new LoanDescriptor(loan); }
@Test void constructorForCaptchaLess() { final Loan mockedLoan = LoanDescriptorTest.mockLoan(Rating.AAAAA); final LoanDescriptor ld = new LoanDescriptor(mockedLoan); assertSoftly(softly -> { softly.assertThat(ld.item()).isSameAs(mockedLoan); softly.assertThat(ld.getLoanCaptchaProtectionEndDateTime()).isEmpty(); }); }
private static RecommendedLoan recommendedLoan() { final Loan loan = Loan.custom().setNonReservedRemainingInvestment(2000).build(); return new LoanDescriptor(loan).recommend(200).orElse(null); }
public Optional<RecommendedLoan> recommend(final int toInvest) { return recommend(toInvest, false); }
@Test void equalsSelf() { final Loan mockedLoan = LoanDescriptorTest.mockLoan(); final LoanDescriptor ld = new LoanDescriptor(mockedLoan); assertThat(ld) .isNotEqualTo(null) .isEqualTo(ld); final LoanDescriptor ld2 = new LoanDescriptor(mockedLoan); assertThat(ld).isEqualTo(ld2); }
@Disabled("Looks like CAPTCHA is disabled for now. Let's wait and see if it comes back.") @Test void constructorForCaptcha() { final Loan mockedLoan = LoanDescriptorTest.mockLoan(); final LoanDescriptor ld = new LoanDescriptor(mockedLoan); assertSoftly(softly -> { softly.assertThat(ld.item()).isSameAs(mockedLoan); softly.assertThat(ld.getLoanCaptchaProtectionEndDateTime()) .isPresent() .contains(mockedLoan.getDatePublished().plus(Settings.INSTANCE.getCaptchaDelay())); }); }
@Test void recommendWrongAmount() { final Loan mockedLoan = LoanDescriptorTest.mockLoan(); final LoanDescriptor ld = new LoanDescriptor(mockedLoan); final Optional<RecommendedLoan> r = ld.recommend(BigDecimal.valueOf(mockedLoan.getNonReservedRemainingInvestment() + 1)); assertThat(r).isEmpty(); } }
public Optional<RecommendedLoan> recommend(final int toInvest) { return recommend(toInvest, false); }
public LoanWrapper(final LoanDescriptor original) { super(original); this.loan = original.item(); }
@Test void conditions() { final DefaultPortfolio portfolio = DefaultPortfolio.PROGRESSIVE; final ParsedStrategy strategy = new ParsedStrategy(portfolio); // test for default values assertThat(strategy.getApplicableLoans(Collections.emptyList())).isEmpty(); // add loan; without filters, should be applicable final Loan loan = ParsedStrategyTest.mockLoan(2); final LoanDescriptor ld = new LoanDescriptor(loan); assertThat(strategy.getApplicableLoans(Collections.singletonList(ld))).contains(ld); // now add a filter and see no loans applicable final MarketplaceFilter f = mock(MarketplaceFilter.class); when(f.test(eq(Wrapper.wrap(ld)))).thenReturn(true); final ParsedStrategy strategy2 = new ParsedStrategy(portfolio, Collections.singleton(f)); assertThat(strategy2.getApplicableLoans(Collections.singletonList(ld))).isEmpty(); }
@Override public Stream<RecommendedLoan> recommend(final Collection<LoanDescriptor> loans, final PortfolioOverview portfolio, final Restrictions restrictions) { if (!Util.isAcceptable(strategy, portfolio)) { return Stream.empty(); } // split available marketplace into buckets per rating final Map<Rating, List<LoanDescriptor>> splitByRating = Util.sortByRating(strategy.getApplicableLoans(loans), d -> d.item().getRating()); // and now return recommendations in the order in which investment should be attempted final BigDecimal balance = portfolio.getCzkAvailable(); final InvestmentSizeRecommender recommender = new InvestmentSizeRecommender(strategy, restrictions); return Util.rankRatingsByDemand(strategy, splitByRating.keySet(), portfolio) .peek(rating -> Decisions.report(logger -> logger.trace("Processing rating {}.", rating))) .flatMap(rating -> splitByRating.get(rating).stream().sorted(COMPARATOR)) .peek(d -> Decisions.report(logger -> logger.trace("Evaluating {}.", d.item()))) .flatMap(d -> { // recommend amount to invest per strategy final int recommendedAmount = recommender.apply(d.item(), balance.intValue()); if (recommendedAmount > 0) { return d.recommend(recommendedAmount, needsConfirmation(d)) .map(Stream::of) .orElse(Stream.empty()); } else { return Stream.empty(); } }); } }
@Test void recommendAmount() { final Loan mockedLoan = LoanDescriptorTest.mockLoan(); final LoanDescriptor ld = new LoanDescriptor(mockedLoan); final Optional<RecommendedLoan> r = ld.recommend(200); assertThat(r).isPresent(); final RecommendedLoan recommendation = r.get(); assertSoftly(softly -> { softly.assertThat(recommendation.descriptor()).isSameAs(ld); softly.assertThat(recommendation.amount()).isEqualTo(BigDecimal.valueOf(200)); softly.assertThat(recommendation.isConfirmationRequired()).isFalse(); }); }
@Override public Optional<RecommendedLoan> recommend(final BigDecimal toInvest) { return recommend(toInvest.intValue()); } }
private static boolean isActionable(final LoanDescriptor loanDescriptor) { final OffsetDateTime now = DateUtil.offsetNow(); return loanDescriptor.getLoanCaptchaProtectionEndDateTime() .map(d -> d.isBefore(now)) .orElse(true); }
@Test void unacceptablePortfolioDueToLowBalance() { final ParsedStrategy p = new ParsedStrategy(DefaultPortfolio.EMPTY); final InvestmentStrategy s = new NaturalLanguageInvestmentStrategy(p); final PortfolioOverview portfolio = mock(PortfolioOverview.class); when(portfolio.getCzkAvailable()).thenReturn(BigDecimal.valueOf(p.getMinimumBalance() - 1)); final Stream<RecommendedLoan> result = s.recommend(Collections.singletonList(new LoanDescriptor(mockLoan(2))), portfolio, new Restrictions()); assertThat(result).isEmpty(); }