From aaaa45039eceaa41ffd214e5d8f388c9564b4c04 Mon Sep 17 00:00:00 2001 From: Notmoo Date: Thu, 17 Aug 2017 23:51:58 +0200 Subject: [PATCH] =?UTF-8?q?Module=20Client,=20=C3=A9cran=20stock=20:=20ajo?= =?UTF-8?q?ut=20des=20classes=20de=20l'=C3=A9cran=20stocks;=20diverses=20m?= =?UTF-8?q?odifications=20annexes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gui/modules/stock_screen/StockScreen.java | 5 +- .../stock_screen/StockScreenController.java | 30 ++- .../modules/stock_screen/StockScreenView.java | 78 ++++++- .../ProductManagerScreen.java | 56 +++++ .../ProductManagerScreenController.java | 93 ++++++++ .../ProductManagerScreenFactory.java | 17 ++ .../ProductManagerScreenModel.java | 100 ++++++++ .../ProductManagerScreenView.java | 213 ++++++++++++++++++ .../pqt/client/module/sale/SaleBuilder.java | 39 +++- .../com/pqt/client/module/stock/StockDao.java | 8 +- .../pqt/client/module/stock/StockService.java | 33 ++- .../client/src/main/resources/dark-theme.css | 9 + 12 files changed, 650 insertions(+), 31 deletions(-) create mode 100644 Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreen.java create mode 100644 Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenController.java create mode 100644 Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenFactory.java create mode 100644 Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenModel.java create mode 100644 Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenView.java diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreen.java index 3d9d298c..64f4e145 100644 --- a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreen.java +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreen.java @@ -1,6 +1,8 @@ package com.pqt.client.gui.modules.stock_screen; import com.pqt.client.gui.modules.IGuiModule; +import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreen; +import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreenFactory; import com.pqt.client.module.stock.StockService; import javafx.scene.layout.Pane; @@ -11,9 +13,10 @@ public class StockScreen implements IGuiModule { public StockScreen(StockService stockService) { StockScreenModel model = new StockScreenModel(stockService); StockScreenController ctrl = new StockScreenController(model); - view = new StockScreenView(ctrl); + view = new StockScreenView(ctrl, new ProductManagerScreenFactory(stockService)); ctrl.setView(view); + ctrl.refreshView(); } @Override diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenController.java index a0847c7b..2d85f01d 100644 --- a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenController.java +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenController.java @@ -3,6 +3,8 @@ package com.pqt.client.gui.modules.stock_screen; import com.pqt.client.gui.modules.stock_screen.listeners.IStockItemEventListener; import com.pqt.client.gui.modules.stock_screen.listeners.IStockScreenModelListener; +import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreen; +import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener; import com.pqt.client.gui.ressources.strings.GUIStringTool; import com.pqt.core.entities.product.Product; @@ -24,11 +26,33 @@ class StockScreenController implements IStockScreenModelListener{ } void onDetailProductRequest() { - detailProduct(view.getSelectedProduct()); + if(view.getSelectedProduct()!=null) + detailProduct(view.getSelectedProduct()); } private void detailProduct(Product product){ - //TODO à faire + view.switchToDetailMode(product); + } + + IValidatorComponentListener getDetailScreenValidationListener(){ + return new IValidatorComponentListener() { + @Override + public void onValidationEvent() { + if(view.isDetailScreenCreationPossible()) { + if (view.hasDetailScreenInitialValue()){ + modifyProduct(view.getDetailScreenInitialValue(), view.getDetailScreenCreation()); + }else{ + addProduct(view.getDetailScreenCreation()); + } + view.switchToGeneralMode(); + } + } + + @Override + public void onCancelEvent() { + view.switchToGeneralMode(); + } + }; } void onDeleteProductRequest() { @@ -55,7 +79,7 @@ class StockScreenController implements IStockScreenModelListener{ return this::detailProduct; } - private void refreshView(){ + void refreshView(){ view.display(model.getProductCollection()); } diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenView.java index bb167158..c3a16606 100644 --- a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenView.java +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/StockScreenView.java @@ -1,6 +1,9 @@ package com.pqt.client.gui.modules.stock_screen; +import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreen; +import com.pqt.client.gui.modules.stock_screen.product_manager_screen.ProductManagerScreenFactory; import com.pqt.client.gui.ressources.components.generics.IFXComponent; +import com.pqt.client.gui.ressources.css.GUICssTool; import com.pqt.client.gui.ressources.strings.GUIStringTool; import com.pqt.client.gui.ressources.strings.IObjectStringRenderer; import com.pqt.core.entities.product.Product; @@ -10,34 +13,37 @@ import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; +import javafx.scene.Node; import javafx.scene.control.*; import javafx.scene.input.KeyCode; import javafx.scene.input.MouseButton; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Priority; +import javafx.scene.layout.*; import javafx.util.Callback; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; class StockScreenView implements IFXComponent { private StockScreenController ctrl; - private Pane mainPane; + private StackPane mainPane; + private BorderPane mainPaneContent; private TableView stockTableView; + private ProductManagerScreenFactory productManagerScreenFactory; + private ProductManagerScreen currentDetailScreen; - StockScreenView(StockScreenController ctrl) { + StockScreenView(StockScreenController ctrl, ProductManagerScreenFactory productManagerScreenFactory) { this.ctrl = ctrl; + this.productManagerScreenFactory = productManagerScreenFactory; initGui(); } private void initGui() { - mainPane = new Pane(); - mainPane.getStyleClass().add("main-module-pane"); - BorderPane mainPaneContent = new BorderPane(); + mainPane = new StackPane(); + mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass()); + mainPaneContent = new BorderPane(); mainPane.getChildren().add(mainPaneContent); mainPaneContent.prefWidthProperty().bind(mainPane.widthProperty()); mainPaneContent.prefHeightProperty().bind(mainPane.heightProperty()); @@ -46,7 +52,9 @@ class StockScreenView implements IFXComponent { addProductButton.setOnMouseClicked(event -> ctrl.onAddProductRequest()); Button detailProductButton = new Button(GUIStringTool.getDetailButtonLabel()); detailProductButton.setOnMouseClicked(event -> ctrl.onDetailProductRequest()); + detailProductButton.setDisable(true); Button removeProductButton = new Button(GUIStringTool.getRemoveButtonLabel()); + removeProductButton.setDisable(true); removeProductButton.setOnMouseClicked(event -> ctrl.onDeleteProductRequest()); Button refreshProductButton = new Button(GUIStringTool.getRefreshButtonLabel()); refreshProductButton.setOnMouseClicked(event -> ctrl.onRefreshProductsRequest()); @@ -75,6 +83,10 @@ class StockScreenView implements IFXComponent { return row; }); stockTableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + stockTableView.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal)->{ + detailProductButton.setDisable(newVal==null); + removeProductButton.setDisable(newVal==null); + }); List> columns = new ArrayList<>(); columns.add(createNewTableColumn(String.class, @@ -99,7 +111,7 @@ class StockScreenView implements IFXComponent { )); columns.add(createNewTableColumn(Double.class, GUIStringTool.getProductPriceColumnHeader(), - param -> new SimpleDoubleProperty(param.getValue().getAmountSold()).asObject(), + param -> new SimpleDoubleProperty(param.getValue().getPrice()).asObject(), GUIStringTool.getPriceRenderer() )); columns.add(createNewTableColumn(Boolean.class, @@ -154,4 +166,50 @@ class StockScreenView implements IFXComponent { Product getSelectedProduct() { return stockTableView.getSelectionModel().getSelectedItem(); } + + void switchToDetailMode(Product product) { + if(currentDetailScreen==null){ + currentDetailScreen = productManagerScreenFactory.create(product); + currentDetailScreen.addListener(ctrl.getDetailScreenValidationListener()); + Pane separator = new Pane(); + separator.getStyleClass().add(GUICssTool.getIntermediaryPaneStyleClass()); + Platform.runLater(()->mainPane.getChildren().addAll(separator, currentDetailScreen.getPane())); + } + } + + void switchToGeneralMode() { + if(currentDetailScreen!=null){ + List toRemove = mainPane.getChildren() + .stream() + .filter(node->!node.equals(mainPaneContent)) + .collect(Collectors.toList()); + Platform.runLater(()->{ + mainPane.getChildren().removeAll(toRemove); + currentDetailScreen = null; + }); + } + } + + boolean isDetailScreenCreationPossible() { + System.out.println("test creation possible : "); + return currentDetailScreen!=null && currentDetailScreen.isCreationPossible(); + } + + boolean hasDetailScreenInitialValue() { + return currentDetailScreen!=null && currentDetailScreen.hasInitialValue(); + } + + Product getDetailScreenInitialValue() { + if(currentDetailScreen!=null) + return currentDetailScreen.getInitialValueSnapshot(); + else + return null; + } + + Product getDetailScreenCreation() { + if(currentDetailScreen!=null) + return currentDetailScreen.create(); + else + return null; + } } diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreen.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreen.java new file mode 100644 index 00000000..d5aee803 --- /dev/null +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreen.java @@ -0,0 +1,56 @@ +package com.pqt.client.gui.modules.stock_screen.product_manager_screen; + +import com.pqt.client.gui.ressources.components.generics.creators.IFXCreatorComponent; +import com.pqt.client.gui.ressources.components.generics.validators.IFXValidatorComponent; +import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener; +import com.pqt.client.module.stock.StockService; +import com.pqt.core.entities.product.Product; +import javafx.scene.layout.Pane; + +public class ProductManagerScreen implements IFXCreatorComponent, IFXValidatorComponent { + + private ProductManagerScreenView view; + private ProductManagerScreenModel model; + private ProductManagerScreenController ctrl; + + public ProductManagerScreen(Product initialData, StockService stockService){ + model = new ProductManagerScreenModel(initialData, stockService); + ctrl = new ProductManagerScreenController(model); + view = new ProductManagerScreenView(ctrl); + ctrl.setView(view); + ctrl.updateView(); + } + + @Override + public Product create() { + return model.create(); + } + + @Override + public boolean isCreationPossible() { + return model.isProductCreationPossible(); + } + + @Override + public Pane getPane() { + return view.getPane(); + } + + @Override + public void addListener(IValidatorComponentListener l) { + ctrl.addListener(l); + } + + @Override + public void removeListener(IValidatorComponentListener l) { + ctrl.removeListener(l); + } + + public boolean hasInitialValue(){ + return model.hasInitialData(); + } + + public Product getInitialValueSnapshot(){ + return new Product(model.getInitialData()); + } +} diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenController.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenController.java new file mode 100644 index 00000000..b948bf82 --- /dev/null +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenController.java @@ -0,0 +1,93 @@ +package com.pqt.client.gui.modules.stock_screen.product_manager_screen; + +import com.pqt.client.gui.ressources.components.generics.validators.listeners.IValidatorComponentListener; +import com.pqt.core.entities.product.Category; +import com.pqt.core.entities.product.Product; +import javafx.beans.value.ChangeListener; + +import javax.swing.event.EventListenerList; +import java.util.Arrays; + +class ProductManagerScreenController { + + private EventListenerList listenerList; + private ProductManagerScreenModel model; + private ProductManagerScreenView view; + + ProductManagerScreenController(ProductManagerScreenModel model) { + listenerList = new EventListenerList(); + this.model = model; + } + + void setView(ProductManagerScreenView view){ + this.view = view; + } + + ChangeListener getProductComponentSelectionListener() { + return (obs, oldValue, newValue)->{ + if(newValue!=null) { + if (model.isComponent(newValue)) + model.removeComponent(newValue); + else + model.addComponent(newValue); + updateView(); + } + }; + } + + void updateView() { + view.setProduct(model.getActualProductState()); + view.setCategoryCollection(model.getCategoryCollection()); + view.setProductCollection(model.getEligibleComponentList()); + } + + IValidatorComponentListener getValidatorListener() { + return new IValidatorComponentListener() { + @Override + public void onValidationEvent() { + Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class)).forEach(IValidatorComponentListener::onValidationEvent); + } + + @Override + public void onCancelEvent() { + Arrays.stream(listenerList.getListeners(IValidatorComponentListener.class)).forEach(IValidatorComponentListener::onCancelEvent); + } + }; + } + + public void addListener(IValidatorComponentListener l) { + listenerList.add(IValidatorComponentListener.class, l); + } + + public void removeListener(IValidatorComponentListener l) { + listenerList.remove(IValidatorComponentListener.class, l); + } + + boolean isProductHighlighted(Product product) { + return model.getActualProductState().getComponents().contains(product); + } + + void onNameChanged(String oldVal, String newVal) { + model.changeName(newVal); + } + + void onPriceChanged(double oldVal, double newVal) { + model.changePrice(newVal); + } + + void onCategoryChanged(Category oldVal, Category newVal) { + model.changeCategory(newVal); + } + + void onAmountRemainingChanged(int oldVal, int newVal) { + model.changeAmountRemaining(newVal); + } + + void onAmountSoldChanged(int oldVal, int newVal) { + model.changeAmountSold(newVal); + } + + void onSellableStateChanged(boolean oldVal, boolean newVal) { + model.setSellable(newVal); + } +} diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenFactory.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenFactory.java new file mode 100644 index 00000000..c583115c --- /dev/null +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenFactory.java @@ -0,0 +1,17 @@ +package com.pqt.client.gui.modules.stock_screen.product_manager_screen; + +import com.pqt.client.module.stock.StockService; +import com.pqt.core.entities.product.Product; + +public final class ProductManagerScreenFactory { + + private StockService stockService; + + public ProductManagerScreenFactory(StockService stockService) { + this.stockService = stockService; + } + + public ProductManagerScreen create(Product product){ + return new ProductManagerScreen(product, stockService); + } +} diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenModel.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenModel.java new file mode 100644 index 00000000..962390fb --- /dev/null +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenModel.java @@ -0,0 +1,100 @@ +package com.pqt.client.gui.modules.stock_screen.product_manager_screen; + +import com.pqt.client.gui.ressources.strings.GUIStringTool; +import com.pqt.client.module.stock.StockService; +import com.pqt.core.entities.product.Category; +import com.pqt.core.entities.product.LightweightProduct; +import com.pqt.core.entities.product.Product; + +import java.util.*; +import java.util.stream.Collectors; + +class ProductManagerScreenModel { + + private StockService stockService; + private Product initialData; + private Product currentData; + + ProductManagerScreenModel(Product initialData, StockService stockService) { + this.stockService = stockService; + this.initialData = initialData; + if(initialData==null) + currentData = new Product(); + else + currentData = new Product(initialData); + } + + List getEligibleComponentList() { + return stockService.getProductsExcluding(currentData); + } + + Product getActualProductState(){ + return currentData; + } + + Product create() { + if(isProductCreationPossible()) + return currentData; + else + return null; + } + + boolean isProductCreationPossible() { + return (initialData!=null && !currentData.equals(initialData)) + && !currentData.getName().isEmpty() + && currentData.getCategory()!=null + && currentData.getPrice()>=0; + } + + void addComponent(Product product) { + currentData.getComponents().add(product); + } + + void removeComponent(Product product) { + currentData.getComponents().remove(product); + } + + void changeCategory(Category category){ + this.currentData.setCategory(category); + } + + void changePrice(double price){ + this.currentData.setPrice(price); + } + + void changeName(String name){ + this.currentData.setName(name); + } + + void changeAmountRemaining(int amount){ + this.currentData.setAmountRemaining(amount); + } + + void changeAmountSold(int amount){ + this.currentData.setAmountSold(amount); + } + + void setSellable(boolean sellable){ + this.currentData.setSellable(sellable); + } + + Collection getCategoryCollection() { + return stockService.getProducts() + .stream() + .map(Product::getCategory) + .distinct() + .collect(Collectors.toList()); + } + + boolean isComponent(Product product) { + return currentData.getComponents().contains(product); + } + + boolean hasInitialData(){ + return initialData!=null; + } + + Product getInitialData(){ + return initialData; + } +} diff --git a/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenView.java b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenView.java new file mode 100644 index 00000000..3ece4942 --- /dev/null +++ b/Workspace/client/src/main/java/com/pqt/client/gui/modules/stock_screen/product_manager_screen/ProductManagerScreenView.java @@ -0,0 +1,213 @@ +package com.pqt.client.gui.modules.stock_screen.product_manager_screen; + +import com.pqt.client.gui.ressources.components.SimpleValidator; +import com.pqt.client.gui.ressources.components.generics.IFXComponent; +import com.pqt.client.gui.ressources.components.generics.javafx_override.CssEnabledGridPane; +import com.pqt.client.gui.ressources.components.generics.javafx_override.HighlightListCell; +import com.pqt.client.gui.ressources.css.GUICssTool; +import com.pqt.client.gui.ressources.strings.GUIStringTool; +import com.pqt.core.entities.product.Category; +import com.pqt.core.entities.product.Product; +import javafx.application.Platform; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Collection; + +class ProductManagerScreenView implements IFXComponent { + + private ProductManagerScreenController ctrl; + + private int gridLines; + private StackPane mainPane; + private BorderPane mainPaneContent; + private TextField productNameTextField, + productAmountRemainingTextField, + productAmountSoldTextField, + productPriceTextField; + private ComboBox productCategoryComboBox; + private CheckBox productSellableCheckBox; + private ListView productComponentsListView; + + ProductManagerScreenView(ProductManagerScreenController ctrl) { + this.ctrl = ctrl; + initGui(); + } + + private void initGui() { + mainPane = new StackPane(); + mainPane.getStyleClass().add(GUICssTool.getMainModulePaneCssClass()); + + mainPaneContent = new BorderPane(); + + GridPane mainPaneCenterContent = new CssEnabledGridPane(); + mainPaneCenterContent.setAlignment(Pos.CENTER); + gridLines = 0; + NumberFormat priceFormat = NumberFormat.getNumberInstance(); + NumberFormat intFormat = NumberFormat.getIntegerInstance(); + + Label productNameLabel = new Label(GUIStringTool.getProductNameLabel()); + productNameTextField = new TextField(); + productNameTextField.textProperty().addListener((obs, oldVal, newVal)->ctrl.onNameChanged(oldVal,newVal)); + addLineToGrid(mainPaneCenterContent, productNameLabel, productNameTextField); + + Label productCategoryLabel = new Label(GUIStringTool.getProductCategoryLabel()); + productCategoryComboBox = new ComboBox<>(); + productCategoryComboBox.setEditable(true); + productCategoryComboBox.setConverter(GUIStringTool.getCategoryStringConverter()); + productCategoryComboBox.valueProperty().addListener((obs, oldVal, newVal)->ctrl.onCategoryChanged(oldVal, newVal)); + addLineToGrid(mainPaneCenterContent, productCategoryLabel, productCategoryComboBox); + + Label productAmountRemainingLabel = new Label(GUIStringTool.getProductAmountRemainingLabel()); + productAmountRemainingTextField = getNumberOnlyTextField(intFormat); + productAmountRemainingTextField.textProperty().addListener((obs, oldVal, newVal)->{ + try{ + int oldInt = oldVal.isEmpty()?0:Integer.parseInt(oldVal); + int newInt = newVal.isEmpty()?0:Integer.parseInt(newVal); + ctrl.onAmountRemainingChanged(oldInt, newInt); + }catch(NumberFormatException e){ + e.printStackTrace(); + } + }); + addLineToGrid(mainPaneCenterContent, productAmountRemainingLabel, productAmountRemainingTextField); + + Label productAmountSoldLabel = new Label(GUIStringTool.getProductAmountSoldLabel()); + productAmountSoldTextField = getNumberOnlyTextField(intFormat); + productAmountSoldTextField.textProperty().addListener((obs, oldVal, newVal)->{ + try{ + int oldInt = oldVal.isEmpty()?0:Integer.parseInt(oldVal); + int newInt = newVal.isEmpty()?0:Integer.parseInt(newVal); + ctrl.onAmountSoldChanged(oldInt, newInt); + }catch(NumberFormatException e){ + e.printStackTrace(); + } + }); + addLineToGrid(mainPaneCenterContent, productAmountSoldLabel, productAmountSoldTextField); + + Label productSellableLabel = new Label(GUIStringTool.getProductSellableLabel()); + productSellableCheckBox = new CheckBox(); + productSellableCheckBox.selectedProperty().addListener((obs, oldVal, newVal)->ctrl.onSellableStateChanged(oldVal,newVal)); + addLineToGrid(mainPaneCenterContent, productSellableLabel, productSellableCheckBox); + + Label productPriceLabel = new Label(GUIStringTool.getProductPriceLabel()); + productPriceTextField = getNumberOnlyTextField(priceFormat); + productPriceTextField.textProperty().addListener((obs, oldVal, newVal)->{ + try{ + ctrl.onPriceChanged((oldVal.isEmpty()?-1:Double.parseDouble(oldVal)), (newVal.isEmpty()?-1:Double.parseDouble(newVal))); + }catch(NumberFormatException e){ + e.printStackTrace(); + } + }); + addLineToGrid(mainPaneCenterContent, productPriceLabel, productPriceTextField); + + mainPaneContent.setCenter(mainPaneCenterContent); + + VBox mainPaneRightContent = new VBox(); + mainPaneRightContent.getStyleClass().add(GUICssTool.getContainerStyleClass()); + mainPaneRightContent.setAlignment(Pos.CENTER); + Label title = new Label(GUIStringTool.getComponentListTitleLabel()); + title.setAlignment(Pos.CENTER); + title.getStyleClass().add(GUICssTool.getTitleTextStyleClass()); + productComponentsListView = new ListView<>(); + productComponentsListView.setCellFactory(listView->new HighlightListCell(){ + @Override + protected void updateItem(Product item, boolean empty) { + super.updateItem(item, empty); + if(item==null || empty){ + setText(null); + setGraphic(null); + }else{ + setText(GUIStringTool.getSimpleProductStringRenderer().render(item)); + if(ctrl.isProductHighlighted(item)){ + if(!isHightlighted()) { + setHighLight(true); + applyCss(); + } + }else { + if (isHightlighted()) { + setHighLight(false); + applyCss(); + } + } + } + } + }); + productComponentsListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + productComponentsListView.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue)->{ + this.ctrl.getProductComponentSelectionListener().changed(obs, oldValue, newValue); + if(newValue!=null) + Platform.runLater(()->productComponentsListView.getSelectionModel().clearSelection(productComponentsListView.getSelectionModel().getSelectedIndex())); + }); + + mainPaneRightContent.getChildren().addAll(title, productComponentsListView); + mainPaneContent.setRight(mainPaneRightContent); + + HBox mainPaneBottomContent = new HBox(); + HBox separator = new HBox(); + SimpleValidator validator = new SimpleValidator(); + validator.addListener(ctrl.getValidatorListener()); + mainPaneBottomContent.getChildren().addAll(separator, validator.getPane()); + HBox.setHgrow(separator, Priority.ALWAYS); + + mainPaneContent.setBottom(mainPaneBottomContent); + mainPane.getChildren().add(mainPaneContent); + } + + private void addLineToGrid(GridPane grid, Node... nodes){ + gridLines++; + int columnIndex = 0; + for(Node node : nodes){ + grid.add(node, columnIndex, gridLines); + columnIndex++; + } + } + + private TextField getNumberOnlyTextField(NumberFormat format){ + TextField textField = new TextField(); + textField.textProperty().addListener((obs, oldValue, newValue)->{ + if(!newValue.matches("^[-+]?[0-9]+[.,]?[0-9]*$")) + Platform.runLater(()->textField.setText(oldValue)); + }); + return textField; + } + + @Override + public Pane getPane() { + return mainPane; + } + + void setProduct(Product product){ + if(product!=null){ + Platform.runLater(()->{ + productNameTextField.setText(product.getName()); + productCategoryComboBox.setValue(product.getCategory()); + productAmountRemainingTextField.setText(Integer.toString(product.getAmountRemaining())); + productAmountRemainingTextField.setEditable(product.getComponents().isEmpty()); + productAmountSoldTextField.setText(Integer.toString(product.getAmountSold())); + productComponentsListView.getItems().clear(); + productComponentsListView.getItems().addAll(product.getComponents()); + productSellableCheckBox.setSelected(product.isSellable()); + productPriceTextField.setText(Double.toString(product.getPrice())); + }); + } + + } + + void setCategoryCollection(Collection categoryCollection){ + Platform.runLater(()->{ + productCategoryComboBox.getItems().clear(); + productCategoryComboBox.getItems().addAll(categoryCollection); + }); + } + + void setProductCollection(Collection productCollection){ + Platform.runLater(()->{ + productComponentsListView.getItems().clear(); + productComponentsListView.getItems().addAll(productCollection); + }); + } +} diff --git a/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java b/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java index 4c550960..a70bac00 100644 --- a/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java +++ b/Workspace/client/src/main/java/com/pqt/client/module/sale/SaleBuilder.java @@ -1,5 +1,6 @@ package com.pqt.client.module.sale; +import com.pqt.client.module.stock.StockDao; import com.pqt.core.entities.members.Client; import com.pqt.core.entities.product.Product; import com.pqt.core.entities.sale.Sale; @@ -7,9 +8,7 @@ import com.pqt.core.entities.sale.SaleStatus; import com.pqt.core.entities.sale.SaleType; import com.pqt.core.entities.user_account.Account; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; +import java.util.*; //TODO écrire javadoc public class SaleBuilder { @@ -26,18 +25,40 @@ public class SaleBuilder { } public SaleBuilder addProduct(Product product) { - if(products.containsKey(product)){ - //Check for sufficient stock - if(product.getAmountRemaining() rank0Products = new HashMap<>(); + collectRank0Products(newProduct, requiredAmount, rank0Products); + products.keySet().forEach(oldProduct->collectRank0Products(oldProduct, products.get(oldProduct), rank0Products)); + + return rank0Products.keySet() + .stream() + .filter(rank0Product->rank0Product.getAmountRemaining() collector){ + if(rootProduct.getComponents().isEmpty()){ + if(collector.containsKey(rootProduct)) + collector.replace(rootProduct, collector.get(rootProduct)+rootProductAmount); + else + collector.put(rootProduct, rootProductAmount); + }else{ + rootProduct.getComponents().forEach(product->collectRank0Products(product, rootProductAmount, collector)); + } + } + public SaleBuilder removeProduct(Product product) { if(products.containsKey(product)) { if (products.get(product) == 1) diff --git a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java index d682f84f..08439d66 100644 --- a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java +++ b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockDao.java @@ -33,12 +33,8 @@ public class StockDao { } public synchronized Product getProduct(final int id) { - Optional match = products.stream().filter((product->product.getId()==id)).findFirst(); - if(match.isPresent()) - return match.get(); - - return null; - } + return products.stream().filter((product->product.getId()==id)).findFirst().orElse(null); + } public void refreshProductList() { QueryExecutor.INSTANCE.execute(QueryFactory.newStockQuery(), new IStockQueryCallback() { diff --git a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java index 559fa0ae..8c2e67aa 100644 --- a/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java +++ b/Workspace/client/src/main/java/com/pqt/client/module/stock/StockService.java @@ -39,7 +39,8 @@ public class StockService { /** * Accesseur de la liste des produits actuellement en vente. *

- * La liste peut être obsolète, voir {@link #getLastRefreshTimestamp()} pour la date du dernier refresh et {@link #refreshProductList()} pour la mettre à jour. + * La liste peut être obsolète, voir {@link #getLastRefreshTimestamp()} pour la date du dernier refresh et + * {@link #refreshProductList()} pour la mettre à jour. * * @return Liste des produits en vente. */ @@ -47,6 +48,35 @@ public class StockService { return dao.getProducts(); } + /** + * Récupère la liste des produits n'étant pas {@code product} et n'étant pas composé de {@code product}. + * Les composants sont récursivements vérifiés pour que ces derniers valident aussi ces deux conditions. + *

+ * La liste peut être obsolète, voir {@link #getLastRefreshTimestamp()} pour la date du dernier refresh et + * {@link #refreshProductList()} pour la mettre à jour. + * + * @param product produit à exclure des résultats. + * @return Liste de produit n'étant pas et ne contenant pas {@code product}. + */ + public List getProductsExcluding(Product product) { + return dao.getProducts(); + } + + private boolean contains(Product container, Product contained){ + if(container==null || contained==null) + return false; + if(container.equals(contained)) + return true; + + if(container.getComponents()!=null) + return container.getComponents() + .stream() + .filter(component->contains(component, contained)) + .count()>0; + + return false; + } + /** * Accesseur récupérant un unique produit présent dans les stocks en se basant sur son id. * @@ -100,5 +130,4 @@ public class StockService { public void removeListener(IStockListener listener) { dao.removeListener(listener); } - } diff --git a/Workspace/client/src/main/resources/dark-theme.css b/Workspace/client/src/main/resources/dark-theme.css index 273b47a2..b71e5642 100644 --- a/Workspace/client/src/main/resources/dark-theme.css +++ b/Workspace/client/src/main/resources/dark-theme.css @@ -43,6 +43,9 @@ .list-view:focused .list-cell:filled:focused:selected { -fx-background-color: -fx-focus-color; } +.list-cell-highlighted{ + -fx-background-color: #4d4d4d; +} .table-view { -fx-base: #1d1d1d; @@ -231,6 +234,7 @@ -fx-padding: 5 5 5 5; -fx-background-radius: 0; -fx-background-insets: 0 0 0 0, 0, 1, 2; +} .toast-text{ -fx-font: 50px "Impact"; @@ -245,4 +249,9 @@ -fx-border-radius: 6px; -fx-padding: 25px; } + +.pqt-container { + -fx-border-width: 2px; + -fx-border-color: whitesmoke; + -fx-padding: 5 5 5 5; } \ No newline at end of file