/* * Copyright (C) 2014 GG-Net GmbH - Oliver Günther * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.ggnet.dwoss.report; import java.net.URL; import java.text.*; import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.*; import javafx.beans.value.ObservableValue; import javafx.collections.*; import javafx.fxml.*; import javafx.geometry.*; import javafx.scene.Node; import javafx.scene.control.*; import javafx.scene.control.TableColumn.CellDataFeatures; import javafx.scene.control.cell.CheckBoxTableCell; import javafx.scene.layout.*; import javafx.util.Callback; import eu.ggnet.dwoss.common.DesktopUtil; import eu.ggnet.dwoss.report.ReportAgent.ViewReportResult; import eu.ggnet.dwoss.report.ReportAgent.ViewReportResult.Type; import eu.ggnet.dwoss.report.api.ReportExporter; import eu.ggnet.dwoss.report.entity.ReportLine; import eu.ggnet.dwoss.util.DateFormats; import eu.ggnet.saft.api.ui.*; import eu.ggnet.saft.core.Client; import eu.ggnet.saft.core.Ui; import lombok.*; import static eu.ggnet.dwoss.util.DateFormats.ISO; /** * * @author pascal.perau */ @Frame @Title("Report Ansicht : {id}") public class ReportController implements Initializable, FxController, Consumer<ReportController.In> { @Override public void accept(In in) { initReportData(in.reportResult, in.viewmode); } @Value public static class In implements IdSupplier { private final ViewReportResult reportResult; private final boolean viewmode; @Override public String id() { return reportResult.getParameter().getReportName(); } } @Title("Wollen Sie wirklich diesen Report erstellen?") public static class ResultPane extends Pane implements Consumer<ViewReportResult> { private Label l; public ResultPane() { l = new Label(); getChildren().add(l); } @Override public void accept(ViewReportResult reportResult) { String infoLine = "Name: " + reportResult.getParameter().getReportName(); infoLine += "\nStart: " + ISO.format(reportResult.getParameter().getStart()); infoLine += "\nEnde: " + ISO.format(reportResult.getParameter().getEnd()); l.setText(infoLine); } } private class TableSummary { double referencePrice; String referencePricePercentage = ""; double price; double purchasePrice; double margin; String marginPercentage = ""; StringProperty refPriceP = new SimpleStringProperty(); StringProperty priceP = new SimpleStringProperty(); StringProperty purchasePriceP = new SimpleStringProperty(); StringProperty marginP = new SimpleStringProperty(); StringProperty refPricePercentageP = new SimpleStringProperty(); StringProperty marginPercentageP = new SimpleStringProperty(); /** * Updates all properties to represent the value in a readable formated manner. */ public void update() { marginPercentageP.set(marginPercentage); refPricePercentageP.set(referencePricePercentage); marginP.set(NumberFormat.getCurrencyInstance().format(margin)); purchasePriceP.set(NumberFormat.getCurrencyInstance().format(purchasePrice)); priceP.set(NumberFormat.getCurrencyInstance().format(price)); refPriceP.set(NumberFormat.getCurrencyInstance().format(referencePrice)); } /** * Sets all non propertie values to a default. * Call update afterwards for property updates. */ public void clear() { referencePrice = 0; price = 0; purchasePrice = 0; margin = 0; referencePricePercentage = "0"; marginPercentage = "0"; } } private final NumberFormat NF = new DecimalFormat(",##0.00"); @FXML AnchorPane mainPane; @FXML Label nameLabel; @FXML Label fromDateLabel; @FXML Label toDateLabel; @FXML TabPane tabPane; @FXML Button createButton; @FXML Button exportButton; @FXML Button fullExportButton; @Getter private ViewReportResult reportResult; private final Map<TableView<ReportLine>, TableSummary> tableSummarys = new HashMap<>(); private final BooleanProperty viewmode = new SimpleBooleanProperty(true); public ReportController() { } @Override public void initialize(URL location, ResourceBundle resources) { nameLabel.setText("NO REPORT RESULT !! result =" + reportResult); } private List<TableColumn<ReportLine, ?>> getColumnModel() { List<TableColumn<ReportLine, ?>> columns = new ArrayList<>(); TableColumn<ReportLine, Boolean> column = new TableColumn("Report"); column.setCellValueFactory(p -> { p.getValue().addedToReportProperty().addListener((o, ov, nv) -> buildSummary(column.getTableView())); return p.getValue().addedToReportProperty(); }); column.setCellFactory(p -> new CheckBoxTableCell<>()); columns.add(column); columns.addAll( Arrays.asList( toTableLineColumn("Datum", cell -> new ReadOnlyStringWrapper(DateFormats.ISO.format(cell.getValue().getReportingDate())).getReadOnlyProperty()), toTableLineColumn("SopoNr.", cell -> new ReadOnlyStringWrapper(cell.getValue().getRefurbishId()).getReadOnlyProperty()), toTableLineColumn("ArtikelNr.", cell -> new ReadOnlyStringWrapper(cell.getValue().getPartNo()).getReadOnlyProperty()), toTableLineColumn("Bezeichnung", cell -> new ReadOnlyStringWrapper(cell.getValue().getName()).getReadOnlyProperty()), toTableLineColumn("Seriennummer", cell -> new ReadOnlyStringWrapper(cell.getValue().getSerial()).getReadOnlyProperty()), toTableLineColumn("MFGDate", cell -> new ReadOnlyStringWrapper(cell.getValue().getMfgDate() == null ? "" : DateFormats.ISO.format(cell.getValue().getMfgDate())).getReadOnlyProperty()), toCurrencyColumn("Manufacturer CP", cell -> cell.getValue().manufacturerCostPriceProperty()), toCurrencyColumn("Contractor RP", cell -> cell.getValue().contractorReferencePriceProperty()), toCurrencyColumn("VK", cell -> cell.getValue().priceProperty()), toCurrencyColumn("EK", cell -> cell.getValue().purchasePriceProperty()), toCurrencyColumn("Marge", cell -> new ReadOnlyDoubleWrapper(cell.getValue().getPrice() - cell.getValue().getPurchasePrice()).getReadOnlyProperty()), toTableLineColumn("Rechnungsaddresse", cell -> new ReadOnlyStringWrapper(cell.getValue().getInvoiceAddress()).getReadOnlyProperty()), toTableLineColumn("DocumentType", cell -> new ReadOnlyStringWrapper( cell.getValue().getDocumentTypeName() + cell.getValue().getWorkflowStatus().getSign()).getReadOnlyProperty()), toTableLineColumn("Lieferanten ArtikelNr.", cell -> new ReadOnlyStringWrapper(cell.getValue().getContractorPartNo()).getReadOnlyProperty()) )); return columns; } private String formatPercentage(double percentage) { if ( percentage == 0d || Double.isNaN(percentage) ) return "0 %"; return NF.format(percentage * 100) + " %"; } private TableColumn<ReportLine, String> toTableLineColumn(String header, Callback<CellDataFeatures<ReportLine, String>, ObservableValue<String>> callback) { TableColumn tc = new TableColumn(); tc.setText(header); tc.setCellValueFactory(callback); return tc; } private TableColumn<ReportLine, Number> toCurrencyColumn(String header, Callback<CellDataFeatures<ReportLine, Number>, ObservableValue<Number>> callback) { TableColumn tc = new TableColumn(); tc.setText(header); tc.setCellValueFactory(callback); tc.setCellFactory(p -> new CurrencyCell()); return tc; } private ViewReportResult filterRelevantLines() { return reportResult == null ? null : new ViewReportResult( reportResult.getRelevantLines(), reportResult.getParameter()); } /** * Builds the TableSummary for a TableView. * <p> * @param lines the TableView a TableSummary is built for. * @return the TableSummary for a TableView */ private TableSummary buildSummary(TableView<ReportLine> lines) { TableSummary sum = tableSummarys.get(lines) == null ? new TableSummary() : tableSummarys.get(lines); sum.clear(); for (ReportLine line : lines.getItems()) { if ( !line.isAddedToReport() ) continue; sum.referencePrice += line.getManufacturerCostPrice(); sum.purchasePrice += line.getPurchasePrice(); sum.margin += (line.getPrice() - line.getPurchasePrice()); sum.price += line.getPrice(); } if ( sum.price != 0 && sum.referencePrice != 0 ) sum.referencePricePercentage = formatPercentage(sum.price / sum.referencePrice); if ( sum.margin != 0 && sum.purchasePrice != 0 ) sum.marginPercentage = formatPercentage(sum.margin / sum.purchasePrice); sum.update(); return sum; } /** * Builds the GridPane for a summary. * <p> * @param summary the TableSUmmary a GridPane is built for. * @return the GridPane for a summary. */ private GridPane buildSummaryPanel(TableSummary summary) { GridPane grid = new GridPane(); grid.setPadding(new Insets(8)); grid.setAlignment(Pos.BOTTOM_RIGHT); grid.setHgap(20); grid.setVgap(10); Label l = new Label(); l.textProperty().bind(summary.refPriceP); grid.addColumn(0, new Label("Reference Price"), l); l = new Label(); l.textProperty().bind(summary.refPricePercentageP); grid.addColumn(1, new Label("Reference Price Percentage"), l); l = new Label(); l.textProperty().bind(summary.priceP); grid.addColumn(2, new Label("Price"), l); l = new Label(); l.textProperty().bind(summary.purchasePriceP); grid.addColumn(3, new Label("Purchase Price"), l); l = new Label(); l.textProperty().bind(summary.marginP); grid.addColumn(4, new Label("Margin"), l); l = new Label(); l.textProperty().bind(summary.marginPercentageP); grid.addColumn(5, new Label("Margin Percentage"), l); for (Node get : grid.getChildren()) { GridPane.setHalignment(get, HPos.RIGHT); } return grid; } /** * Initialize model data. * <p> * In viewmode only display concerning actions are allowed. Creation of reports is disabled. * <p> * @param reportResult the result containing report data * @param viewmode is this only viewmode or not. */ public void initReportData(ViewReportResult reportResult, boolean viewmode) { this.viewmode.set(viewmode); createButton.disableProperty().bind(this.viewmode); exportButton.setDisable(!Client.hasFound(ReportExporter.class)); this.reportResult = reportResult; nameLabel.setText(reportResult.getParameter().getReportName()); fromDateLabel.setText(DateFormats.ISO.format(reportResult.getParameter().getStart())); toDateLabel.setText(DateFormats.ISO.format(reportResult.getParameter().getEnd())); reportResult.getLines().keySet().stream().map((Type type) -> { for (ReportLine reportLine : reportResult.getLines().get(type)) { reportLine.setAddedToReport(true); } //built tab Tab t = new Tab(type.name()); //built table TableView<ReportLine> table = new TableView<>(FXCollections.observableArrayList(reportResult.getLines().get(type))); table.getColumns().addAll(getColumnModel()); table.setEditable(true); //built summary TableSummary sum = buildSummary(table); GridPane grid = buildSummaryPanel(sum); //map reference tableSummarys.put(table, sum); //add content t.setContent(new BorderPane(table, null, null, grid, null)); return t; }).forEach((t) -> { tabPane.getTabs().add(t); }); } @FXML public void handleCreateButtonAction() { Ui.parent(mainPane) .call(() -> reportResult) .choiceFx(ResultPane.class) .onOk(r -> { Client.lookup(ReportAgent.class).store( reportResult.getParameter().toNewReport(), reportResult.getRelevantLines() .values() .stream() .flatMap(Collection::stream) .map(ReportLine::toStorable) .collect(Collectors.toList()) ); Platform.runLater(() -> viewmode.set(true)); return null; }).exec(); /* String infoLine = "Name: " + reportResult.getParameter().getReportName(); infoLine += "\nStart: " + ISO.format(reportResult.getParameter().getStart()); infoLine += "\nEnde: " + ISO.format(reportResult.getParameter().getEnd()); Pane pane = new Pane(new Label(infoLine)); OkCancelStage<Pane> stage = new OkCancelStage<>("Wollen Sie wirklich diesen Report erstellen?", pane); stage.setWidth(500); stage.showAndWait(); if ( stage.isCancel() ) return; Client.lookup(ReportAgent.class).store( reportResult.getParameter().toNewReport(), reportResult.getRelevantLines() .values() .stream() .flatMap(Collection::stream) .map(ReportLine::toStorable) .collect(Collectors.toList()) ); viewmode.set(true); */ } @FXML public void handleExportButtonAction() { DesktopUtil.open(Client.lookup(ReportExporter.class).toFullXls(filterRelevantLines()).toTemporaryFile()); } @FXML public void handleFullExportButtonAction() { DesktopUtil.open(XlsExporter.toFullXls(filterRelevantLines())); } public static URL loadFxml() { return ReportController.class.getResource("ReportView.fxml"); } }