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(); }
@Nonnull protected Aggregate aggregatePresentationModel() final Money budget = project.getBudget(); final Money earnings = project.getEarnings(); final Money invoicedEarnings = project.getInvoicedEarnings(); .with("Client", (Displayable) () -> ((CustomerSpi)project.getCustomer()).getName()) .with("Status", (Displayable) () -> project.getStatus().name()) .with("#", (Displayable) () -> project.getNumber()) .with("Name", (Displayable) () -> project.getName()) .with("Start Date", (Displayable) () -> DATE_FORMATTER.format(project.getStartDate()), new DefaultStyleable("right-aligned")) .with("Due Date", (Displayable) () -> DATE_FORMATTER.format(project.getEndDate()), new DefaultStyleable("right-aligned")) .with("Notes", (Displayable) () -> project.getNotes()) .with("Budget", (Displayable) () -> MONEY_FORMATTER.format(budget), 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),
@CheckForNull private static Object safeGet (final @Nonnull Field field, final @Nonnull Object object) { try { Object value = field.get(object); if (value instanceof Customer) { value = ((CustomerSpi)value).getName(); } else if (value instanceof Project) { value = ((ProjectSpi)value).getName(); } return value; } catch (IllegalArgumentException | IllegalAccessException e) { throw new RuntimeException(e); } } }
@Test(dataProvider = "projects", dataProviderClass = ScenarioFactory.class) public void must_properly_generate_report (final @Nonnull String scenarioName, final @Nonnull ProjectSpi project) throws IOException { final Path expectedResultsFolder = Paths.get("src/test/resources/expected-results"); final Path testFolder = Paths.get("target/test-results"); Files.createDirectories(testFolder); final String name = scenarioName + "-" + project.getName() + ".txt"; final Path actualResult = testFolder.resolve(name); final Path expectedResult = expectedResultsFolder.resolve(name); final HourlyReport report = new DefaultHourlyReportGenerator(project).createReport(); try (final PrintWriter pw = new PrintWriter(actualResult.toFile())) { pw.print(report.asString()); } FileComparisonUtils.assertSameContents(expectedResult.toFile(), actualResult.toFile()); } }