@Nonnull public Money getMoney (final @Nonnull String key) { return new Money(delegate.getBigDecimal(key).round(ROUNDING), "EUR"); }
@Nonnull public String format (final @Nonnull Money amount) { final String currency = amount.getCurrency(); return String.format("%s %s", Money.getFormat().format(amount.getAmount()), CURRENCY_SYMBOL_MAP.getOrDefault(currency, currency)); } }
public boolean isEqualTo (final @Nonnull Money other) { return compareTo(other) == 0; }
@Nonnull public Money subtract (final @Nonnull Money other) { checkCurrencies(other); return new Money(amount.subtract(other.amount), currency); }
@Test public void greaterThan_and_lowerThan_must_work_at_the_opposite() { final Money greater = new Money(349, "EUR"); final Money lower = new Money(130, "EUR"); assertThat(greater.greaterThan(lower), is(true)); assertThat(greater.lowerThan(lower) , is(false)); assertThat(lower.greaterThan(greater), is(false)); assertThat(lower.lowerThan(greater), is(true)); }
final LocalDate lastDate = lastEvent.getStartDateTime().toLocalDate(); final double earnings = timedEventsSubList.stream() .collect(Collectors.summingDouble(ev -> ev.getEarnings().getAmount().doubleValue())); final double taxRate = 0.20d; .withDate(lastDate) .withDueDate(lastDate.plusMonths(2)) .withEarnings(new Money(new BigDecimal(earnings), "EUR")) .withJobEvents(eventsSubList) .withNumber(prefix + (i + 1)) .withProject(project) .withTax(new Money(new BigDecimal(earnings * taxRate), "EUR")) .create();
@Test public void isEqualTo_must_work() { final Money m1 = new Money(349, "EUR"); final Money m2 = new Money(349, "EUR"); final Money m3 = new Money(495, "EUR"); assertThat(m1.isEqualTo(m2), is(true)); assertThat(m2.isEqualTo(m1), is(true)); assertThat(m1.isEqualTo(m3), is(false)); assertThat(m3.isEqualTo(m1), is(false)); }
.with("Budget", (Displayable) () -> MONEY_FORMATTER.format(budget), new DefaultStyleable("right-aligned", budget.isEqualTo(Money.ZERO) ? "alerted" : "")) .with("Earnings", (Displayable) () -> MONEY_FORMATTER.format(earnings), new DefaultStyleable("right-aligned", earnings.greaterThan(budget) ? "alerted" : "", earnings.isEqualTo(budget) ? "green" : "")) .with("Time", (Displayable) () -> DURATION_FORMATTER.format(project.getDuration()), new DefaultStyleable("right-aligned")) .with("Invoiced", (Displayable) () -> MONEY_FORMATTER.format(invoicedEarnings), new DefaultStyleable("right-aligned", invoicedEarnings.greaterThan(earnings) ? "alerted" : "", invoicedEarnings.isEqualTo(earnings) ? "green" : "")) .create();
@Override @Nonnull public Collection<String> getStyles() { return Arrays.asList(moneySupplier.get().getAmount().compareTo(BigDecimal.ZERO) >= 0 ? "" : "red"); } }
private void makeReport (final @Nonnull Writer w) { final PrintWriter pw = new PrintWriter(w); System.err.println("CREATE REPORT " + project); pw.printf(SEPARATOR + "\n"); pw.printf(PATTERN, "Date", "Description", "Time", "Cost"); pw.printf(SEPARATOR + "\n"); // TODO: quick and dirty - refactor with visitor, lambdas final List<JobEventSpi> jobEvents = new ArrayList<>(); addAll(jobEvents, project.findChildren().results()); jobEvents.stream().sorted(comparing(JobEventSpi::getDateTime)) .forEach(event -> pw.printf(PATTERN2, DATE_FORMATTER.format(event.getDateTime()), event.getName(), DURATION_FORMATTER.format(event.getDuration()), MONEY_FORMATTER.format(event.getEarnings()))); pw.printf(SEPARATOR + "\n"); pw.printf(PATTERN3, "", "", DURATION_FORMATTER.format(project.getDuration()), MONEY_FORMATTER.format(project.getEarnings())); // FIXME: rename getAmount() -> getBudget() // FIXME: introduce getBudgetDuration() final Duration duration = Duration.ofHours((long)project.getBudget().divided(project.getHourlyRate())); pw.printf("BUDGET: %s\n", MONEY_FORMATTER.format(project.getBudget())); pw.printf("HOURLY RATE: %s\n", MONEY_FORMATTER.format(project.getHourlyRate())); pw.printf("DURATION: %s\n", DURATION_FORMATTER.format(duration)); pw.printf("REMAINING BUDGET: %s\n", MONEY_FORMATTER.format(project.getBudget().subtract(project.getEarnings()))); pw.printf("REMAINING TIME: %s\n", DURATION_FORMATTER.format(duration.minus(project.getDuration()))); pw.flush(); }
@Override @Nonnull public String marshal (final @Nonnull Money money) { return money.toString(); } }
.withDate(configuration.getDate("date")) .withDueDate(configuration.getDate("dueDate")) .withEarnings(earnings.subtract(tax)) .withTax(tax) .withProject(project)
@Test public void greaterThan_and_lowerThan_must_be_false_when_equality() { final Money m1 = new Money(349, "EUR"); final Money m2 = new Money(349, "EUR"); assertThat(m1.greaterThan(m2), is(false)); assertThat(m1.lowerThan(m2), is(false)); assertThat(m2.greaterThan(m1), is(false)); assertThat(m2.lowerThan(m1), is(false)); } }
@Nonnull private static List<JobEvent> createJobEvents (final @Nonnull LocalDate startDate, final @Nonnull LocalDate endDate, final @Nonnull Money rate) { final List<JobEvent> result = new ArrayList<>(); final long days = startDate.until(endDate, ChronoUnit.DAYS); for (int i = 1; i <= days; i++) { final LocalDateTime s = startDate.plusDays(i - 1).atTime(8, 0).plusMinutes(i * 3); final LocalDateTime e = s.plusMinutes(60 + i * 4); final double hours = s.until(e, ChronoUnit.MINUTES) / 60.0; final BigDecimal earnings = rate.getAmount().multiply(new BigDecimal(hours)); result.add(JobEvent.builder().withId(new Id("" + nextId++)) .withName("Event #" + i) .withDescription("Description of Event #" + i) .withType(JobEvent.Type.TIMED) .withEarnings(new Money(earnings, "EUR")) .withStartDateTime(s) .withEndDateTime(e) .withHourlyRate(rate) .create()); } return result; }
@Nonnull public Money add (final @Nonnull Money other) { checkCurrencies(other); return new Money(amount.add(other.amount), currency); }
@Test public void toString_for_ZERO_must_be_properly_computed() { assertThat(Money.ZERO.toString(), is("0.00 EUR")); }
public boolean greaterThan (final @Nonnull Money other) { return compareTo(other) > 0; }