From 278de6f99ffd5ec4063b83cfe7cd6bdc98d954a8 Mon Sep 17 00:00:00 2001 From: Sorin Popteanu Date: Fri, 26 Apr 2024 15:17:04 +0300 Subject: [PATCH] FactoryInventoryController --- .../org/chainoptim/desktop/AppModule.java | 6 + .../FactoryInventoryController.java | 659 +++++++++++++++++- .../dto/CreateFactoryInventoryItemDTO.java | 8 + .../dto/UpdateFactoryInventoryItemDTO.java | 1 + .../factory/model/FactoryInventoryItem.java | 20 +- .../FactoryInventoryItemServiceImpl.java | 2 +- .../FactoryInventoryItemWriteService.java | 4 + .../FactoryInventoryItemWriteServiceImpl.java | 55 +- .../model/SearchOptionsConfiguration.java | 23 +- .../factory/FactoryInventoryView.fxml | 37 +- .../features/supplier/SupplierOrdersView.fxml | 2 +- 11 files changed, 795 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/chainoptim/desktop/AppModule.java b/src/main/java/org/chainoptim/desktop/AppModule.java index 9ef2e42d..2138ca15 100644 --- a/src/main/java/org/chainoptim/desktop/AppModule.java +++ b/src/main/java/org/chainoptim/desktop/AppModule.java @@ -25,6 +25,7 @@ import org.chainoptim.desktop.features.client.model.ClientOrder; import org.chainoptim.desktop.features.client.service.*; import org.chainoptim.desktop.features.factory.model.Factory; +import org.chainoptim.desktop.features.factory.model.FactoryInventoryItem; import org.chainoptim.desktop.features.factory.service.*; import org.chainoptim.desktop.features.product.model.Product; import org.chainoptim.desktop.features.product.service.*; @@ -139,6 +140,8 @@ protected void configure() { bind(FactoryWriteService.class).to(FactoryWriteServiceImpl.class); bind(FactoryStageService.class).to(FactoryStageServiceImpl.class); bind(FactoryStageWriteService.class).to(FactoryStageWriteServiceImpl.class); + bind(FactoryInventoryItemService.class).to(FactoryInventoryItemServiceImpl.class); + bind(FactoryInventoryItemWriteService.class).to(FactoryInventoryItemWriteServiceImpl.class); // - Warehouse bind(WarehouseService.class).to(WarehouseServiceImpl.class); @@ -196,6 +199,9 @@ protected void configure() { bind(new TypeLiteral>>() {}) .to(new TypeLiteral>>() {}) .in(Singleton.class); + bind(new TypeLiteral>>() {}) + .to(new TypeLiteral>>() {}) + .in(Singleton.class); bind(new TypeLiteral>>() {}) .to(new TypeLiteral>>() {}) .in(Singleton.class); diff --git a/src/main/java/org/chainoptim/desktop/features/factory/controller/FactoryInventoryController.java b/src/main/java/org/chainoptim/desktop/features/factory/controller/FactoryInventoryController.java index fb7463f6..c0164c01 100644 --- a/src/main/java/org/chainoptim/desktop/features/factory/controller/FactoryInventoryController.java +++ b/src/main/java/org/chainoptim/desktop/features/factory/controller/FactoryInventoryController.java @@ -1,15 +1,672 @@ package org.chainoptim.desktop.features.factory.controller; +import org.chainoptim.desktop.core.context.TenantContext; +import org.chainoptim.desktop.core.user.model.User; +import org.chainoptim.desktop.features.client.model.ClientOrder; import org.chainoptim.desktop.features.factory.model.Factory; +import org.chainoptim.desktop.features.factory.model.FactoryInventoryItem; +import org.chainoptim.desktop.features.factory.service.FactoryInventoryItemService; +import org.chainoptim.desktop.features.factory.service.FactoryInventoryItemWriteService; +import org.chainoptim.desktop.features.product.model.Product; +import org.chainoptim.desktop.features.productpipeline.model.Component; +import org.chainoptim.desktop.features.factory.dto.CreateFactoryInventoryItemDTO; +import org.chainoptim.desktop.features.factory.dto.UpdateFactoryInventoryItemDTO; +import org.chainoptim.desktop.shared.confirmdialog.controller.GenericConfirmDialogController; +import org.chainoptim.desktop.shared.confirmdialog.controller.RunnableConfirmDialogActionListener; +import org.chainoptim.desktop.shared.confirmdialog.model.ConfirmDialogInput; +import org.chainoptim.desktop.shared.enums.Feature; +import org.chainoptim.desktop.shared.enums.OperationOutcome; +import org.chainoptim.desktop.shared.enums.OrderStatus; +import org.chainoptim.desktop.shared.fallback.FallbackManager; +import org.chainoptim.desktop.shared.httphandling.Result; +import org.chainoptim.desktop.shared.search.controller.PageSelectorController; +import org.chainoptim.desktop.shared.search.model.PaginatedResults; +import org.chainoptim.desktop.shared.search.model.SearchOptions; +import org.chainoptim.desktop.shared.search.model.SearchOptionsConfiguration; +import org.chainoptim.desktop.shared.search.model.SearchParams; +import org.chainoptim.desktop.shared.table.TableToolbarController; +import org.chainoptim.desktop.shared.table.edit.cell.ComboBoxEditableCell; +import org.chainoptim.desktop.shared.table.edit.cell.DateTimePickerCell; +import org.chainoptim.desktop.shared.table.edit.cell.EditableCell; +import org.chainoptim.desktop.shared.table.model.TableData; +import org.chainoptim.desktop.shared.table.util.SelectProductLoader; +import org.chainoptim.desktop.shared.table.util.TableConfigurer; +import org.chainoptim.desktop.shared.table.util.SelectComponentLoader; +import org.chainoptim.desktop.shared.toast.controller.ToastManager; +import org.chainoptim.desktop.shared.toast.model.ToastInfo; import org.chainoptim.desktop.shared.util.DataReceiver; +import org.chainoptim.desktop.shared.util.resourceloader.CommonViewsLoader; + +import com.google.inject.Inject; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.MapChangeListener; +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.scene.layout.StackPane; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.function.Consumer; public class FactoryInventoryController implements DataReceiver { + // Services + private final FactoryInventoryItemService factoryInventoryItemService; + private final FactoryInventoryItemWriteService factoryInventoryItemWriteService; + private final CommonViewsLoader commonViewsLoader; + private final ToastManager toastManager; + + // Controllers + private TableToolbarController tableToolbarController; + private PageSelectorController pageSelectorController; + private final SelectComponentLoader selectComponentLoader; + private final SelectProductLoader selectProductLoader; + private GenericConfirmDialogController> confirmFactoryInventoryItemUpdateController; + private GenericConfirmDialogController> confirmFactoryInventoryItemDeleteController; + private GenericConfirmDialogController> confirmFactoryInventoryItemCreateController; + + // State + private final FallbackManager fallbackManager; + private final SearchParams searchParams; + private Factory factory; + private final List statusOptions = Arrays.asList(OrderStatus.values()); + private long totalRowsCount; + private int newInventoryItemCount = 0; + private final List selectedRowsIndices = new ArrayList<>(); + private final SimpleIntegerProperty selectedCount = new SimpleIntegerProperty(0); + private final BooleanProperty isEditMode = new SimpleBooleanProperty(false); + private final SimpleBooleanProperty isNewOrderMode = new SimpleBooleanProperty(false); + + // Confirm Dialog Listeners + private RunnableConfirmDialogActionListener> confirmDialogUpdateListener; + private RunnableConfirmDialogActionListener> confirmDialogDeleteListener; + private RunnableConfirmDialogActionListener> confirmDialogCreateListener; + + // FXML + @FXML + private StackPane tableToolbarContainer; + @FXML + private ScrollPane factoryInventoryScrollPane; + @FXML + private TableView> tableView; + @FXML + private TableColumn, Boolean> selectRowColumn; + @FXML + private TableColumn, Integer> inventoryIdColumn; + @FXML + private TableColumn, String> companyIdColumn; + @FXML + private TableColumn, String> factoryNameColumn; + @FXML + private TableColumn, String> componentNameColumn; + @FXML + private TableColumn, String> productNameColumn; + @FXML + private TableColumn, Float> quantityColumn; + @FXML + private TableColumn, Float> minimumRequiredQuantityColumn; + @FXML + private TableColumn, LocalDateTime> createdAtColumn; + @FXML + private TableColumn, LocalDateTime> updatedAtColumn; + @FXML + private StackPane pageSelectorContainer; + @FXML + private StackPane confirmUpdateDialogContainer; + @FXML + private StackPane confirmDeleteDialogContainer; + @FXML + private StackPane confirmCreateDialogContainer; + + + @Inject + public FactoryInventoryController(FactoryInventoryItemService factoryInventoryItemService, + FactoryInventoryItemWriteService factoryInventoryItemWriteService, + CommonViewsLoader commonViewsLoader, + SelectComponentLoader selectComponentLoader, + SelectProductLoader selectProductLoader, + ToastManager toastManager, + FallbackManager fallbackManager, + SearchParams searchParams) { + this.factoryInventoryItemService = factoryInventoryItemService; + this.factoryInventoryItemWriteService = factoryInventoryItemWriteService; + this.commonViewsLoader = commonViewsLoader; + this.toastManager = toastManager; + this.selectComponentLoader = selectComponentLoader; + this.selectProductLoader = selectProductLoader; + this.fallbackManager = fallbackManager; + this.searchParams = searchParams; + } @Override public void setData(Factory factory) { this.factory = factory; - System.out.println("Factory received in inventory: " + factory.getName()); + + searchParams.setItemsPerPage(20); + SearchOptions searchOptions = SearchOptionsConfiguration.getSearchOptions(Feature.FACTORY_INVENTORY); + if (searchOptions == null) { + throw new IllegalArgumentException("Search options not found"); + } + + tableToolbarController = commonViewsLoader.initializeTableToolbar(tableToolbarContainer); + tableToolbarController.initialize( + searchParams, + searchOptions.getFilterOptions(), + searchOptions.getSortOptions(), + () -> loadFactoryInventoryItems(factory.getId())); + pageSelectorController = commonViewsLoader.loadPageSelector(pageSelectorContainer); + selectComponentLoader.initialize(); + selectProductLoader.initialize(); + + TableConfigurer.configureTableView(tableView, selectRowColumn); + configureTableColumns(); + setUpListeners(); + loadConfirmDialogs(); + + loadFactoryInventoryItems(factory.getId()); + } + + // Loading + private void loadConfirmDialogs() { + confirmFactoryInventoryItemCreateController = commonViewsLoader.loadConfirmDialog(confirmCreateDialogContainer); + confirmFactoryInventoryItemCreateController.setActionListener(confirmDialogCreateListener); + closeConfirmCreateDialog(); + + confirmFactoryInventoryItemUpdateController = commonViewsLoader.loadConfirmDialog(confirmUpdateDialogContainer); + confirmFactoryInventoryItemUpdateController.setActionListener(confirmDialogUpdateListener); + closeConfirmUpdateDialog(); + + confirmFactoryInventoryItemDeleteController = commonViewsLoader.loadConfirmDialog(confirmDeleteDialogContainer); + confirmFactoryInventoryItemDeleteController.setActionListener(confirmDialogDeleteListener); + closeConfirmDeleteDialog(); + } + + // Configuration + // - Table columns + private void configureTableColumns() { + // Bind columns to data + selectRowColumn.setCellValueFactory(data -> data.getValue().isSelectedProperty()); + inventoryIdColumn.setCellValueFactory(data -> new SimpleObjectProperty<>(data.getValue().getData().getId())); + companyIdColumn.setCellValueFactory(data -> new SimpleObjectProperty<>(data.getValue().getData().getCompanyId() != null ? data.getValue().getData().getCompanyId() : "N/A")); + factoryNameColumn.setCellValueFactory(data -> new SimpleObjectProperty<>(this.factory.getName())); + componentNameColumn.setCellValueFactory(data -> { + Component component = data.getValue().getData().getComponent(); + String componentName = component != null ? component.getName() : "N/A"; + return new SimpleObjectProperty<>(componentName); + }); + productNameColumn.setCellValueFactory(data -> { + Product product = data.getValue().getData().getProduct(); + String productName = product != null ? product.getName() : "N/A"; + return new SimpleObjectProperty<>(productName); + }); + quantityColumn.setCellValueFactory(data -> new SimpleObjectProperty<>(data.getValue().getData().getQuantity())); + minimumRequiredQuantityColumn.setCellValueFactory(data -> new SimpleObjectProperty<>(data.getValue().getData().getMinimumRequiredQuantity())); + createdAtColumn.setCellValueFactory(data -> new SimpleObjectProperty<>(data.getValue().getData().getCreatedAt())); + updatedAtColumn.setCellValueFactory(data -> new SimpleObjectProperty<>(data.getValue().getData().getUpdatedAt())); + + configureColumnCellFactories(); + } + + private void configureColumnCellFactories() { + companyIdColumn.setCellFactory(column -> new EditableCell, String>( + isEditMode, selectedRowsIndices, String::toString) { + @Override + protected void commitChange(TableData item, String newValue) { + item.getData().setCompanyId(newValue); + } + }); + quantityColumn.setCellFactory(column -> new EditableCell, Float>( + isEditMode, selectedRowsIndices, Float::parseFloat) { + @Override + protected void commitChange(TableData item, Float newValue) { + item.getData().setQuantity(newValue); + } + }); + minimumRequiredQuantityColumn.setCellFactory(column -> new EditableCell, Float>( + isEditMode, selectedRowsIndices, Float::parseFloat) { + @Override + protected void commitChange(TableData item, Float newValue) { + item.getData().setQuantity(newValue); + } + }); + createdAtColumn.setCellFactory(column -> new DateTimePickerCell, LocalDateTime>( + isEditMode, selectedRowsIndices, false){}); + + updatedAtColumn.setCellFactory(column -> new DateTimePickerCell, LocalDateTime>( + isEditMode, selectedRowsIndices, false){}); + + componentNameColumn.setCellFactory(column -> new ComboBoxEditableCell, String>( + isEditMode, selectedRowsIndices, null, selectComponentLoader.getComponentsName()) { + @Override + protected void commitChange(TableData item, String newValue) { + Component component = new Component(); + component.setId(selectComponentLoader.getComponentIdByName(newValue)); + component.setName(newValue); + item.getData().setComponent(component); + } + }); + productNameColumn.setCellFactory(column -> new ComboBoxEditableCell, String>( + isEditMode, selectedRowsIndices, null, selectProductLoader.getProductsName()) { + @Override + protected void commitChange(TableData item, String newValue) { + Product product = new Product(); + product.setId(selectProductLoader.getProductIdByName(newValue)); + product.setName(newValue); + item.getData().setProduct(product); + } + }); + } + + // - Listeners + private void setUpListeners() { + setUpSearchListeners(); + setUpTableToolbarListeners(); + setUpConfirmDialogListeners(); + } + + private void setUpSearchListeners() { + searchParams.getPageProperty().addListener((observable, oldPage, newPage) -> loadFactoryInventoryItems(factory.getId())); + searchParams.getSortOptionProperty().addListener((observable, oldValue, newValue) -> loadFactoryInventoryItems(factory.getId())); + searchParams.getAscendingProperty().addListener((observable, oldValue, newValue) -> loadFactoryInventoryItems(factory.getId())); + searchParams.getSearchQueryProperty().addListener((observable, oldValue, newValue) -> loadFactoryInventoryItems(factory.getId())); + searchParams.getFiltersProperty().addListener((MapChangeListener.Change change) -> { + if (searchParams.getFiltersProperty().entrySet().size() == 1) { // Allow only one filter at a time + loadFactoryInventoryItems(factory.getId()); + } + }); + } + + private void setUpTableToolbarListeners() { + selectedCount.addListener((obs, oldCount, newCount) -> { + boolean isAnyRowSelected = newCount.intValue() > 0; + tableToolbarController.toggleButtonVisibilityOnSelection(isAnyRowSelected); + }); + + // Listen to the toolbar buttons + tableToolbarController.getCancelRowSelectionButton().setOnAction(e -> cancelSelectionsAndEdit()); + tableToolbarController.getEditSelectedRowsButton().setOnAction(e -> editSelectedRows()); + tableToolbarController.getSaveChangesButton().setOnAction(e -> { + if (isNewOrderMode.get()) { + openConfirmCreateDialog(); + } else { + openConfirmUpdateDialog(selectedRowsIndices); + } + }); + tableToolbarController.getDeleteSelectedRowsButton().setOnAction(e -> openConfirmDeleteDialog(selectedRowsIndices));; + tableToolbarController.getCreateNewOrderButton().setOnAction(e -> addNewOrder()); + } + + private void setUpConfirmDialogListeners() { + Consumer> onConfirmDelete = this::handleDeleteOrders; + Runnable onCancelDelete = this::closeConfirmDeleteDialog; + confirmDialogDeleteListener = new RunnableConfirmDialogActionListener<>(onConfirmDelete, onCancelDelete); + + Consumer> onConfirmUpdate = this::handleUpdateOrders; + Runnable onCancelUpdate = this::closeConfirmUpdateDialog; + confirmDialogUpdateListener = new RunnableConfirmDialogActionListener<>(onConfirmUpdate, onCancelUpdate); + + Consumer> onConfirmCreate = this::handleCreateOrders; + Runnable onCancelCreate = this::closeConfirmCreateDialog; + confirmDialogCreateListener = new RunnableConfirmDialogActionListener<>(onConfirmCreate, onCancelCreate); + } + + private void setUpRowListeners(TableData FactoryInventoryItem) { + // Add listener to the selectedProperty + FactoryInventoryItem.isSelectedProperty().addListener((obs, wasSelected, isSelected) -> { + if (Boolean.TRUE.equals(isSelected)) { + selectedRowsIndices.add(tableView.getItems().indexOf(FactoryInventoryItem)); + } else { + selectedRowsIndices.remove(Integer.valueOf(tableView.getItems().indexOf(FactoryInventoryItem))); + } + selectedCount.set(selectedRowsIndices.size()); + }); + } + + // Data loading + private void loadFactoryInventoryItems(Integer factoryId) { + fallbackManager.reset(); + fallbackManager.setLoading(true); + + User currentUser = TenantContext.getCurrentUser(); + if (currentUser == null) { + fallbackManager.setLoading(false); + return; + } + + factoryInventoryItemService.getFactoryInventoryItemsByFactoryIdAdvanced(factoryId, searchParams) + .thenApply(this::handleOrdersResponse) + .exceptionally(this::handleOrdersException); + } + + private Result> handleOrdersResponse(Result> result) { + Platform.runLater(() -> { + if (result.getError() != null) { + fallbackManager.setErrorMessage("No items found"); + return; + } + PaginatedResults paginatedResults = result.getData(); + fallbackManager.setLoading(false); + + totalRowsCount = paginatedResults.getTotalCount(); + pageSelectorController.initialize(searchParams, totalRowsCount); + + tableView.getItems().clear(); + if (paginatedResults.results.isEmpty()) { + fallbackManager.setNoResults(true); + return; + } + + for (FactoryInventoryItem factoryInventoryItem : paginatedResults.results) { + FactoryInventoryItem oldData = new FactoryInventoryItem(factoryInventoryItem); + TableData tableRow = new TableData<>(factoryInventoryItem, oldData, new SimpleBooleanProperty(false)); + setUpRowListeners(tableRow); + tableView.getItems().add(tableRow); + } + }); + + return result; + } + + private Result> handleOrdersException(Throwable ex) { + Platform.runLater(() -> fallbackManager.setErrorMessage("Failed to load factory items.")); + return new Result<>(); + } + + // UI Actions + private void addNewOrder() { + isNewOrderMode.set(true); + tableToolbarController.toggleButtonVisibilityOnCreate(isNewOrderMode.get()); + + FactoryInventoryItem newOrder = new FactoryInventoryItem(); + TableData newOrderRow = new TableData<>(newOrder, newOrder, new SimpleBooleanProperty(false)); + tableView.getItems().addFirst(newOrderRow); + newOrderRow.setSelected(true); + + selectedRowsIndices.clear(); + for (int i = 0; i <= newInventoryItemCount; i++) { + selectedRowsIndices.add(i); + } + newInventoryItemCount++; + isEditMode.set(true); + selectRowColumn.setEditable(false); + tableView.refresh(); + } + + private void editSelectedRows() { + tableToolbarController.toggleButtonVisibilityOnEdit(true); + isEditMode.set(true); + for (Integer index : selectedRowsIndices) { + TableData tableRow = tableView.getItems().get(index); + FactoryInventoryItem oldOrder = new FactoryInventoryItem(tableRow.getData()); + oldOrder.setComponent(new Component(tableRow.getData().getComponent())); + tableRow.setOldData(oldOrder); + } + selectRowColumn.setEditable(false); + tableView.refresh(); + } + + private void cancelSelectionsAndEdit() { + isEditMode.set(false); + tableView.getSelectionModel().clearSelection(); + + tableToolbarController.toggleButtonVisibilityOnCancel(); + + // Deselect all rows and clear recording array + List indicesToClear = new ArrayList<>(selectedRowsIndices); + for (Integer rowIndex : indicesToClear) { + TableData tableRow = tableView.getItems().get(rowIndex); + tableRow.setData(tableRow.getOldData()); + tableRow.setSelected(false); + } + selectedRowsIndices.clear(); + + // Delete created new items + if (isNewOrderMode.get()) { + for (int i = 0; i < newInventoryItemCount; i++) { + tableView.getItems().removeFirst(); + } + isNewOrderMode.set(false); + newInventoryItemCount = 0; + } + selectRowColumn.setEditable(true); + tableView.refresh(); + } + + // Confirm Dialogs + private void openConfirmCreateDialog() { + ConfirmDialogInput confirmDialogInput = new ConfirmDialogInput( + "Confirm Factory Orders Create", + "Are you sure you want to create new items?", + null); + List selectedItems = new ArrayList<>(); + for (Integer index : selectedRowsIndices) { + selectedItems.add(tableView.getItems().get(index).getData()); + } + confirmFactoryInventoryItemCreateController.setData(selectedItems, confirmDialogInput); + toggleDialogVisibility(confirmCreateDialogContainer, true); + } + + private void closeConfirmCreateDialog() { + toggleDialogVisibility(confirmCreateDialogContainer, false); + } + + private void openConfirmUpdateDialog(List selectedRowsIndices) { + ConfirmDialogInput confirmDialogInput = new ConfirmDialogInput( + "Confirm Factory Orders Update", + "Are you sure you want to update selected items?", + null); + List selectedItems = new ArrayList<>(); + for (Integer index : selectedRowsIndices) { + selectedItems.add(tableView.getItems().get(index).getData()); + } + confirmFactoryInventoryItemUpdateController.setData(selectedItems, confirmDialogInput); + toggleDialogVisibility(confirmUpdateDialogContainer, true); + } + + private void closeConfirmUpdateDialog() { + toggleDialogVisibility(confirmUpdateDialogContainer, false); + } + + private void openConfirmDeleteDialog(List selectedRowsIndices) { + ConfirmDialogInput confirmDialogInput = new ConfirmDialogInput( + "Confirm Factory Orders Delete", + "Are you sure you want to delete selected items?", + null); + List selectedItems = new ArrayList<>(); + for (Integer index : selectedRowsIndices) { + selectedItems.add(tableView.getItems().get(index).getData()); + } + confirmFactoryInventoryItemDeleteController.setData(selectedItems, confirmDialogInput); + toggleDialogVisibility(confirmDeleteDialogContainer, true); + } + + private void closeConfirmDeleteDialog() { + toggleDialogVisibility(confirmDeleteDialogContainer, false); + } + + private void toggleDialogVisibility(StackPane dialogContainer, boolean isVisible) { + dialogContainer.setVisible(isVisible); + dialogContainer.setManaged(isVisible); + } + + // Backend calls + // - Create + private void handleCreateOrders(List FactoryInventoryItems) { + List createFactoryInventoryItemDTOs = new ArrayList<>(); + for (FactoryInventoryItem item : FactoryInventoryItems) { + CreateFactoryInventoryItemDTO createFactoryInventoryItemDTO = getCreateFactoryInventoryItemDTO(item); + + createFactoryInventoryItemDTOs.add(createFactoryInventoryItemDTO); + } + + fallbackManager.reset(); + fallbackManager.setLoading(true); + + factoryInventoryItemWriteService.createFactoryInventoryItemsInBulk(createFactoryInventoryItemDTOs) + .thenApply(this::handleCreateFactoryInventoryItemsResponse) + .exceptionally(this::handleCreateFactoryInventoryItemsException); + } + + private CreateFactoryInventoryItemDTO getCreateFactoryInventoryItemDTO(FactoryInventoryItem item) { + CreateFactoryInventoryItemDTO createFactoryInventoryItemDTO = new CreateFactoryInventoryItemDTO(); + if (factory == null || factory.getOrganizationId() == null) { + throw new IllegalArgumentException("Factory Organization ID is missing"); + } + createFactoryInventoryItemDTO.setOrganizationId(factory.getOrganizationId()); + createFactoryInventoryItemDTO.setFactoryId(factory.getId()); + createFactoryInventoryItemDTO.setProductId(item.getProduct().getId()); + createFactoryInventoryItemDTO.setComponentId(item.getComponent().getId()); + createFactoryInventoryItemDTO.setQuantity(item.getQuantity()); + createFactoryInventoryItemDTO.setMinimumRequiredQuantity(item.getMinimumRequiredQuantity()); + createFactoryInventoryItemDTO.setCompanyId(item.getCompanyId()); + + return createFactoryInventoryItemDTO; + } + + private Result> handleCreateFactoryInventoryItemsResponse(Result> result) { + Platform.runLater(() -> { + fallbackManager.setLoading(false); + if (result.getError() != null) { + ToastInfo toastInfo = new ToastInfo("Error", "There was an error creating the Factory Orders.", OperationOutcome.ERROR); + toastManager.addToast(toastInfo); + return; + } + isNewOrderMode.set(false); + closeConfirmCreateDialog(); + updateUIOnSuccessfulOperation(); + ToastInfo toastInfo = new ToastInfo("Success", "Factory Orders created successfully.", OperationOutcome.SUCCESS); + toastManager.addToast(toastInfo); + }); + return result; + } + + private Result> handleCreateFactoryInventoryItemsException(Throwable throwable) { + Platform.runLater(() -> { + ToastInfo toastInfo = new ToastInfo("Error", "There was an error creating the Factory Orders.", OperationOutcome.ERROR); + toastManager.addToast(toastInfo); + }); + return new Result<>(); + } + + private void handleUpdateOrders(List FactoryInventoryItems) { + List updateFactoryInventoryItemDTOs = new ArrayList<>(); + + for (FactoryInventoryItem item : FactoryInventoryItems) { + UpdateFactoryInventoryItemDTO updateFactoryInventoryItemDTO = getUpdateFactoryInventoryItemDTO(item); + + updateFactoryInventoryItemDTOs.add(updateFactoryInventoryItemDTO); + } + + fallbackManager.reset(); + fallbackManager.setLoading(true); + + factoryInventoryItemWriteService.updateFactoryInventoryItemsInBulk(updateFactoryInventoryItemDTOs) + .thenApply(this::handleUpdateFactoryInventoryItemsResponse) + .exceptionally(this::handleUpdateFactoryInventoryItemsException); + } + + private UpdateFactoryInventoryItemDTO getUpdateFactoryInventoryItemDTO(FactoryInventoryItem item) { + UpdateFactoryInventoryItemDTO updateFactoryInventoryItemDTO = new UpdateFactoryInventoryItemDTO(); + updateFactoryInventoryItemDTO.setId(item.getId()); + updateFactoryInventoryItemDTO.setComponentId(item.getComponent().getId()); + updateFactoryInventoryItemDTO.setProductId(item.getProduct().getId()); + updateFactoryInventoryItemDTO.setQuantity(item.getQuantity()); + updateFactoryInventoryItemDTO.setMinimumRequiredQuantity(item.getMinimumRequiredQuantity()); + updateFactoryInventoryItemDTO.setCompanyId(item.getCompanyId()); + + return updateFactoryInventoryItemDTO; + } + + private Result> handleUpdateFactoryInventoryItemsResponse(Result> result) { + Platform.runLater(() -> { + fallbackManager.setLoading(false); + + if (result.getError() != null) { + ToastInfo toastInfo = new ToastInfo("Error", "There was an error updating the Factory Orders.", OperationOutcome.ERROR); + toastManager.addToast(toastInfo); + return; + } + + isNewOrderMode.set(false); + closeConfirmUpdateDialog(); + updateUIOnSuccessfulOperation(); + ToastInfo toastInfo = new ToastInfo("Success", "Factory Orders updated successfully.", OperationOutcome.SUCCESS); + toastManager.addToast(toastInfo); + }); + return result; + } + + private Result> handleUpdateFactoryInventoryItemsException(Throwable throwable) { + Platform.runLater(() -> { + ToastInfo toastInfo = new ToastInfo("Error", "There was an error updating the Factory Orders.", OperationOutcome.ERROR); + toastManager.addToast(toastInfo); + }); + return new Result<>(); + } + + private void handleDeleteOrders(List FactoryInventoryItems) { + List itemsToRemoveIds = new ArrayList<>(); + for (FactoryInventoryItem item : FactoryInventoryItems) { + itemsToRemoveIds.add(item.getId()); + } + + fallbackManager.reset(); + fallbackManager.setLoading(true); + + factoryInventoryItemWriteService.deleteFactoryInventoryItemsInBulk(itemsToRemoveIds) + .thenApply(this::handleDeleteFactoryInventoryItemsResponse) + .exceptionally(this::handleDeleteFactoryInventoryItemsException); + } + + private Result> handleDeleteFactoryInventoryItemsResponse(Result> result) { + Platform.runLater(() -> { + fallbackManager.setLoading(false); + + if (result.getError() != null) { + ToastInfo toastInfo = new ToastInfo("Error", "There was an error deleting the Factory Orders.", OperationOutcome.ERROR); + toastManager.addToast(toastInfo); + return; + } + + tableView.getItems().removeIf(tableData -> result.getData().contains(tableData.getData().getId())); + + closeConfirmDeleteDialog(); + isEditMode.set(false); + tableView.refresh(); + selectedRowsIndices.clear(); + ToastInfo toastInfo = new ToastInfo("Success", "Factory Orders deleted successfully.", OperationOutcome.SUCCESS); + toastManager.addToast(toastInfo); + }); + return result; + } + + private Result> handleDeleteFactoryInventoryItemsException(Throwable throwable) { + Platform.runLater(() -> { + ToastInfo toastInfo = new ToastInfo("Error", "There was an error deleting the Factory Orders.", OperationOutcome.ERROR); + toastManager.addToast(toastInfo); + }); + return new Result<>(); + } + + private void updateUIOnSuccessfulOperation() { + isEditMode.set(false); + newInventoryItemCount = 0; + tableView.getSelectionModel().clearSelection(); + tableToolbarController.toggleButtonVisibilityOnCancel(); + + List indicesToClear = new ArrayList<>(selectedRowsIndices); + for (Integer rowIndex : indicesToClear) { + TableData tableRow = tableView.getItems().get(rowIndex); + tableRow.setSelected(false); + } + + selectRowColumn.setEditable(true); + selectedRowsIndices.clear(); + tableView.refresh(); } } diff --git a/src/main/java/org/chainoptim/desktop/features/factory/dto/CreateFactoryInventoryItemDTO.java b/src/main/java/org/chainoptim/desktop/features/factory/dto/CreateFactoryInventoryItemDTO.java index bb132ba6..8baac685 100644 --- a/src/main/java/org/chainoptim/desktop/features/factory/dto/CreateFactoryInventoryItemDTO.java +++ b/src/main/java/org/chainoptim/desktop/features/factory/dto/CreateFactoryInventoryItemDTO.java @@ -1,8 +1,15 @@ package org.chainoptim.desktop.features.factory.dto; +import org.chainoptim.desktop.features.product.model.Product; +import org.chainoptim.desktop.features.productpipeline.model.Component; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; +import java.time.LocalDateTime; @Data +@AllArgsConstructor +@NoArgsConstructor public class CreateFactoryInventoryItemDTO { private Integer factoryId; @@ -11,4 +18,5 @@ public class CreateFactoryInventoryItemDTO { private Integer componentId; private Float quantity; private Float minimumRequiredQuantity; + private String companyId; } diff --git a/src/main/java/org/chainoptim/desktop/features/factory/dto/UpdateFactoryInventoryItemDTO.java b/src/main/java/org/chainoptim/desktop/features/factory/dto/UpdateFactoryInventoryItemDTO.java index aa4e61b9..d161d1e2 100644 --- a/src/main/java/org/chainoptim/desktop/features/factory/dto/UpdateFactoryInventoryItemDTO.java +++ b/src/main/java/org/chainoptim/desktop/features/factory/dto/UpdateFactoryInventoryItemDTO.java @@ -11,4 +11,5 @@ public class UpdateFactoryInventoryItemDTO { private Integer componentId; private Float quantity; private Float minimumRequiredQuantity; + private String companyId; } diff --git a/src/main/java/org/chainoptim/desktop/features/factory/model/FactoryInventoryItem.java b/src/main/java/org/chainoptim/desktop/features/factory/model/FactoryInventoryItem.java index b57588de..faf2ec55 100644 --- a/src/main/java/org/chainoptim/desktop/features/factory/model/FactoryInventoryItem.java +++ b/src/main/java/org/chainoptim/desktop/features/factory/model/FactoryInventoryItem.java @@ -13,18 +13,24 @@ public class FactoryInventoryItem { private Integer id; - private Integer factoryId; - + private String companyId; private Component component; - private Product product; - private LocalDateTime createdAt; - private LocalDateTime updatedAt; - private Float quantity; - private Float minimumRequiredQuantity; + + public FactoryInventoryItem(FactoryInventoryItem nweFactoryInventoryItem) { + this.id = nweFactoryInventoryItem.getId(); + this.factoryId = nweFactoryInventoryItem.getFactoryId(); + this.companyId = nweFactoryInventoryItem.getCompanyId(); + this.component = nweFactoryInventoryItem.getComponent(); + this.product = nweFactoryInventoryItem.getProduct(); + this.createdAt = nweFactoryInventoryItem.getCreatedAt(); + this.updatedAt = nweFactoryInventoryItem.getUpdatedAt(); + this.quantity = nweFactoryInventoryItem.getQuantity(); + this.minimumRequiredQuantity = nweFactoryInventoryItem.getMinimumRequiredQuantity(); + } } diff --git a/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemServiceImpl.java b/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemServiceImpl.java index 03472021..116a1dfa 100644 --- a/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemServiceImpl.java +++ b/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemServiceImpl.java @@ -39,7 +39,7 @@ public FactoryInventoryItemServiceImpl(CachingService>> getFactoryInventoryItemsByOrganizationId(Integer organizationId) { - String routeAddress = "http://localhost:8080/api/v1/factory-inventory-items/organization/" + organizationId.toString(); + String routeAddress = "http://localhost:8080/api/v1/factory-inventory-items/factory/" + organizationId.toString(); HttpRequest request = requestBuilder.buildReadRequest(routeAddress, tokenManager.getToken()); if (request == null) return requestHandler.getParsingErrorResult(); diff --git a/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteService.java b/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteService.java index 3a220b4b..818bd96a 100644 --- a/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteService.java +++ b/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteService.java @@ -5,6 +5,7 @@ import org.chainoptim.desktop.features.factory.model.FactoryInventoryItem; import org.chainoptim.desktop.shared.httphandling.Result; +import java.util.List; import java.util.concurrent.CompletableFuture; public interface FactoryInventoryItemWriteService { @@ -12,4 +13,7 @@ public interface FactoryInventoryItemWriteService { CompletableFuture> createFactoryInventoryItem(CreateFactoryInventoryItemDTO orderDTO); CompletableFuture> updateFactoryInventoryItem(UpdateFactoryInventoryItemDTO orderDTO); CompletableFuture> deleteFactoryInventoryItem(Integer orderId); + CompletableFuture>> createFactoryInventoryItemsInBulk(List itemDTOs); + CompletableFuture>> updateFactoryInventoryItemsInBulk(List itemDTOs); + CompletableFuture>> deleteFactoryInventoryItemsInBulk(List itemIds); } diff --git a/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteServiceImpl.java b/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteServiceImpl.java index 26f45c03..05c69df6 100644 --- a/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteServiceImpl.java +++ b/src/main/java/org/chainoptim/desktop/features/factory/service/FactoryInventoryItemWriteServiceImpl.java @@ -1,50 +1,58 @@ package org.chainoptim.desktop.features.factory.service; import org.chainoptim.desktop.core.user.service.TokenManager; +import org.chainoptim.desktop.features.client.dto.CreateClientOrderDTO; +import org.chainoptim.desktop.features.client.model.ClientOrder; import org.chainoptim.desktop.features.factory.dto.CreateFactoryInventoryItemDTO; import org.chainoptim.desktop.features.factory.dto.UpdateFactoryInventoryItemDTO; import org.chainoptim.desktop.features.factory.model.FactoryInventoryItem; +import org.chainoptim.desktop.shared.caching.CachingService; import org.chainoptim.desktop.shared.httphandling.HttpMethod; import org.chainoptim.desktop.shared.httphandling.RequestBuilder; import org.chainoptim.desktop.shared.httphandling.RequestHandler; import org.chainoptim.desktop.shared.httphandling.Result; +import org.chainoptim.desktop.shared.search.model.PaginatedResults; import com.fasterxml.jackson.core.type.TypeReference; import com.google.inject.Inject; import java.net.http.HttpRequest; +import java.util.List; import java.util.concurrent.CompletableFuture; public class FactoryInventoryItemWriteServiceImpl implements FactoryInventoryItemWriteService { + private final CachingService> cachingService; private final RequestHandler requestHandler; private final RequestBuilder requestBuilder; private final TokenManager tokenManager; @Inject - public FactoryInventoryItemWriteServiceImpl(RequestHandler requestHandler, - RequestBuilder requestBuilder, - TokenManager tokenManager) { +public FactoryInventoryItemWriteServiceImpl(CachingService> cachingService, + RequestHandler requestHandler, + RequestBuilder requestBuilder, + TokenManager tokenManager) { + this.cachingService = cachingService; this.requestHandler = requestHandler; this.requestBuilder = requestBuilder; this.tokenManager = tokenManager; } - public CompletableFuture> createFactoryInventoryItem(CreateFactoryInventoryItemDTO orderDTO) { + public CompletableFuture> createFactoryInventoryItem(CreateFactoryInventoryItemDTO itemDTO) { String routeAddress = "http://localhost:8080/api/v1/factory-inventory-items/create"; HttpRequest request = requestBuilder.buildWriteRequest( - HttpMethod.POST, routeAddress, tokenManager.getToken(), orderDTO); + HttpMethod.POST, routeAddress, tokenManager.getToken(), itemDTO); if (request == null) return requestHandler.getParsingErrorResult(); return requestHandler.sendRequest(request, new TypeReference() {}); } - public CompletableFuture> updateFactoryInventoryItem(UpdateFactoryInventoryItemDTO orderDTO) { + public CompletableFuture> updateFactoryInventoryItem(UpdateFactoryInventoryItemDTO itemDTO) { String routeAddress = "http://localhost:8080/api/v1/factory-inventory-items/update"; HttpRequest request = requestBuilder.buildWriteRequest( - HttpMethod.PUT, routeAddress, tokenManager.getToken(), orderDTO); + HttpMethod.PUT, routeAddress, tokenManager.getToken(), itemDTO); if (request == null) return requestHandler.getParsingErrorResult(); return requestHandler.sendRequest(request, new TypeReference() {}); @@ -59,4 +67,37 @@ public CompletableFuture> deleteFactoryInventoryItem(Integer ord return requestHandler.sendRequest(request, new TypeReference() {}); } + + public CompletableFuture>> createFactoryInventoryItemsInBulk(List itemDTOs) { + String routeAddress = "http://localhost:8080/api/v1/factory-inventory-items/create/bulk"; + + HttpRequest request = requestBuilder.buildWriteRequest( + HttpMethod.POST, routeAddress, tokenManager.getToken(), itemDTOs); + + return requestHandler.sendRequest(request, new TypeReference>() {}, orders -> { + cachingService.clear(); // Invalidate cache + }); + } + + public CompletableFuture>> updateFactoryInventoryItemsInBulk(List itemDTOs) { + String routeAddress = "http://localhost:8080/api/v1/factory-inventory-items/update/bulk"; + + HttpRequest request = requestBuilder.buildWriteRequest( + HttpMethod.PUT, routeAddress, tokenManager.getToken(), itemDTOs); + + return requestHandler.sendRequest(request, new TypeReference>() {}, orders -> { + cachingService.clear(); // Invalidate cache + }); + } + + public CompletableFuture>> deleteFactoryInventoryItemsInBulk(List itemIds) { + String routeAddress = "http://localhost:8080/api/v1/factory-inventory-items/delete/bulk"; + + HttpRequest request = requestBuilder.buildWriteRequest( + HttpMethod.DELETE, routeAddress, tokenManager.getToken(), itemIds); + + return requestHandler.sendRequest(request, new TypeReference>() {}, ids -> { + cachingService.clear(); // Invalidate cache + }); + } } diff --git a/src/main/java/org/chainoptim/desktop/shared/search/model/SearchOptionsConfiguration.java b/src/main/java/org/chainoptim/desktop/shared/search/model/SearchOptionsConfiguration.java index 56dfdc1d..a8ee5e3e 100644 --- a/src/main/java/org/chainoptim/desktop/shared/search/model/SearchOptionsConfiguration.java +++ b/src/main/java/org/chainoptim/desktop/shared/search/model/SearchOptionsConfiguration.java @@ -40,8 +40,29 @@ private SearchOptionsConfiguration() { ) ); + private static final SearchOptions FACTORY_INVENTORY_OPTIONS = new SearchOptions( + List.of( + new FilterOption( + new UIItem("Created At Start", "createdAtStart"), + new ArrayList<>(), + FilterType.DATE + ), + new FilterOption( + new UIItem("Quantity", "greaterThanQuantity"), + new ArrayList<>(), + FilterType.NUMBER + ) + ), + Map.of( + "createdAt", "Created At", + "updatedAt", "Updated At", + "quantity", "Quantity" + ) + ); + private static final Map SEARCH_OPTIONS_MAP = Map.of( - Feature.SUPPLIER_ORDER, SUPPLIER_ORDER_OPTIONS + Feature.SUPPLIER_ORDER, SUPPLIER_ORDER_OPTIONS, + Feature.FACTORY_INVENTORY, FACTORY_INVENTORY_OPTIONS ); public static SearchOptions getSearchOptions(Feature feature) { diff --git a/src/main/resources/org/chainoptim/desktop/features/factory/FactoryInventoryView.fxml b/src/main/resources/org/chainoptim/desktop/features/factory/FactoryInventoryView.fxml index 956aae3a..00cf90e8 100644 --- a/src/main/resources/org/chainoptim/desktop/features/factory/FactoryInventoryView.fxml +++ b/src/main/resources/org/chainoptim/desktop/features/factory/FactoryInventoryView.fxml @@ -1,9 +1,38 @@ + + - + fx:controller="org.chainoptim.desktop.features.factory.controller.FactoryInventoryController"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/src/main/resources/org/chainoptim/desktop/features/supplier/SupplierOrdersView.fxml b/src/main/resources/org/chainoptim/desktop/features/supplier/SupplierOrdersView.fxml index b784b576..6daf8961 100644 --- a/src/main/resources/org/chainoptim/desktop/features/supplier/SupplierOrdersView.fxml +++ b/src/main/resources/org/chainoptim/desktop/features/supplier/SupplierOrdersView.fxml @@ -15,7 +15,7 @@ - +