From cc873a3811758600bd5977115fa3497416ea5646 Mon Sep 17 00:00:00 2001 From: Diogo Severiano Date: Fri, 15 Nov 2024 14:23:51 +0000 Subject: [PATCH] update on alert, item and inventory model --- src/main/java/model/AuditEntity.java | 2 ++ src/main/java/model/Inventory.java | 17 +++++++--- src/main/java/model/Item.java | 12 +++++++ src/main/java/model/Supplier.java | 2 ++ .../java/records/InventoryManualRequest.java | 6 ++-- src/main/java/records/ItemRequest.java | 5 ++- src/main/java/service/AggregatorService.java | 33 ++++++++++++------- src/main/java/service/AlertService.java | 3 +- src/main/java/service/InventoryService.java | 22 ++++++++++--- src/main/java/service/ItemService.java | 17 +++++++++- src/main/java/service/SupplierService.java | 27 ++++++++++++++- 11 files changed, 118 insertions(+), 28 deletions(-) diff --git a/src/main/java/model/AuditEntity.java b/src/main/java/model/AuditEntity.java index e4a629d..b2b8353 100644 --- a/src/main/java/model/AuditEntity.java +++ b/src/main/java/model/AuditEntity.java @@ -4,12 +4,14 @@ import io.quarkus.security.User; import jakarta.persistence.Column; import jakarta.persistence.MappedSuperclass; +import lombok.Setter; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import java.sql.Timestamp; @MappedSuperclass +@Setter public class AuditEntity extends PanacheEntity { @Column(updatable = false) diff --git a/src/main/java/model/Inventory.java b/src/main/java/model/Inventory.java index ab5246f..f2eb206 100644 --- a/src/main/java/model/Inventory.java +++ b/src/main/java/model/Inventory.java @@ -39,17 +39,24 @@ public class Inventory extends AuditEntity implements Serializable { @Column(nullable = false) private double quantity = 0.0; - @ManyToOne(optional = false, fetch = FetchType.LAZY) - private Unit unit; - @Column(nullable = false) private BigDecimal costPrice = BigDecimal.ZERO; - private BigDecimal salePrice = BigDecimal.ZERO; - private String notes; @Column(name = "entry_date") private Date entryDate; + // TODO PENSAR BEM NESTA TEMATICA DA VALIDADE, PORQUE SE EXPIRA DEVERIAMOS ALERTAR, PENSAR COMO!!! + private Date expirationDate; + + @Override + public void setCreatedBy(String createdBy) { + super.setCreatedBy(createdBy); + } + + @Override + public void setModifiedBy(String modifiedBy) { + super.setModifiedBy(modifiedBy); + } } diff --git a/src/main/java/model/Item.java b/src/main/java/model/Item.java index 5036e2c..095055e 100644 --- a/src/main/java/model/Item.java +++ b/src/main/java/model/Item.java @@ -6,6 +6,8 @@ import java.io.Serial; import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; @Entity @Table @@ -30,6 +32,9 @@ public class Item extends AuditEntity implements Serializable { //e.g. Cereal, Beer, Keg, etc. private ItemCategory category; + @ManyToOne(optional = false, fetch = FetchType.LAZY) + private Unit unit; + @Column(name = "item_type") private ItemType itemType; @@ -46,6 +51,13 @@ public class Item extends AuditEntity implements Serializable { private boolean alertLowStock = false; + //this contains the last used cost price (merely indicative) + private BigDecimal indicativeCostPrice = BigDecimal.ZERO; + + private BigDecimal salePrice = BigDecimal.ZERO; + + private BigDecimal retailPrice = BigDecimal.ZERO; + private boolean deprecated = false; } diff --git a/src/main/java/model/Supplier.java b/src/main/java/model/Supplier.java index de8748d..83e0c89 100644 --- a/src/main/java/model/Supplier.java +++ b/src/main/java/model/Supplier.java @@ -61,4 +61,6 @@ public class Supplier extends AuditEntity implements Serializable { @Column(nullable = false) private boolean isActive = true; + private boolean isDummy = false; + } diff --git a/src/main/java/records/InventoryManualRequest.java b/src/main/java/records/InventoryManualRequest.java index 1998c56..6142987 100644 --- a/src/main/java/records/InventoryManualRequest.java +++ b/src/main/java/records/InventoryManualRequest.java @@ -9,7 +9,7 @@ import java.util.Date; public record InventoryManualRequest(Integer itemId, Supplier supplier, Warehouse warehouse, - InventoryType inventoryType, double quantity, Integer unitId, - BigDecimal costPrice, String notes, String batch, BigDecimal salePrice, - @NotNull Date entryDate) { + InventoryType inventoryType, double quantity, + BigDecimal costPrice, String notes, String batch, @NotNull Date entryDate, + BigDecimal retailPrice, BigDecimal salePrice) { } diff --git a/src/main/java/records/ItemRequest.java b/src/main/java/records/ItemRequest.java index 587e124..e4007fa 100644 --- a/src/main/java/records/ItemRequest.java +++ b/src/main/java/records/ItemRequest.java @@ -1,8 +1,11 @@ package records; import enums.ItemType; +import model.Unit; + +import java.math.BigDecimal; public record ItemRequest(String code, String name, Integer categoryId, String brand, String description, String notes, ItemType itemType, double quantity, double minQuantity, boolean alertLowStock, - boolean deprecated) { + BigDecimal salePrice, BigDecimal retailPrice, Unit unit, boolean deprecated) { } diff --git a/src/main/java/service/AggregatorService.java b/src/main/java/service/AggregatorService.java index 841f3f1..0781743 100644 --- a/src/main/java/service/AggregatorService.java +++ b/src/main/java/service/AggregatorService.java @@ -32,7 +32,7 @@ public class AggregatorService { public List getStatisticsForInventoryPage() { return List.of( - createStatisticCard("Inventory Items", getTotalNumberOfItems(), "ri-box-1-fill", "primary", false), + createStatisticCard("Inventory Entries", getTotalNumberOfItems(), "ri-box-1-fill", "primary", false), createStatisticCard("Purchase Orders (Pendind Delivery)", getTotalNumberOfPurchaseOrdersPendingDelivery(), "ri-ship-2-line", "info", false), createStatisticCard("(Average) Inventory Price", getInventoryTotalPrice(), "ri-money-euro-circle-line", "primary", true), createStatisticCard("Total Amount of Cereal", getTotalWeightOfCereal(), "ri-scales-line", "warning", false), @@ -42,7 +42,7 @@ public List getStatisticsForInventoryPage() { public List getStatisticsForStockPage() { return List.of( - createStatisticCard("Stock (Beer) Items", getTotalNumberOfFinishedProducts(), "ri-beer-line", "success", false), + createStatisticCard("Stock Entries", getTotalNumberOfFinishedProducts(), "ri-beer-line", "success", false), createStatisticCard("Stock Price", getStockPrice(), "ri-money-euro-circle-line", "info", true), createStatisticCard("Potential Profit", getPotentialProfit(), "ri-money-euro-circle-line", "warning", true), createStatisticCard("Stock Alerts", getTotalNumberOfStockAlerts(), "ri-alert-line", "error", false) @@ -95,8 +95,12 @@ private String getTotalNumberOfInventoryAlerts() { return "" + 0L; } - //#TODO :: IMPLEMENT SERVICE private String getTotalNumberOfStockAlerts() { + if (warehouseService.getDefaultWarehouse().isPresent()) { + return "" + (long) alertService.findAllAlertsFromWarehouse(AlertType.STOCK, + warehouseService.getDefaultWarehouse().get()).size(); + } + return "" + 0L; } @@ -104,7 +108,9 @@ private String getTotalNumberOfStockAlerts() { private String getInventoryTotalPrice() { if (warehouseService.getDefaultWarehouse().isPresent()) { // Step 1: Get all inventories from the inventory service - List allInventories = inventoryService.findAll(); + List allInventories = inventoryService.findAll() + .stream().filter(x -> x.getItem().getItemType().equals(ItemType.INVENTORY)) + .toList(); // Step 2: Group positive inventory entries by item code and calculate average cost price Map itemCodeToAvgCostPrice = new HashMap<>(); @@ -166,40 +172,43 @@ private String getInventoryTotalPrice() { } // Step 5: Return the total cost of inventory - return totalInventoryCost.setScale(2, RoundingMode.HALF_UP).toString(); + return totalInventoryCost.setScale(2, RoundingMode.HALF_UP).compareTo(BigDecimal.ZERO) <= 0 ? + "0.00" : totalInventoryCost.setScale(2, RoundingMode.HALF_UP).toString(); } - return "0"; // Return "0" if no default warehouse is found + return "0.00"; // Return "0" if no default warehouse is found } private String getStockPrice() { if (warehouseService.getDefaultWarehouse().isPresent()) { - return "" + inventoryService.findAll().stream() + BigDecimal amount = inventoryService.findAll().stream() .filter(inventory -> inventory.getInventoryType().equals(InventoryType.FINISHED_PRODUCT)) .map(inventory -> inventory.getCostPrice() .multiply(BigDecimal.valueOf(inventory.getQuantity())) .setScale(2, RoundingMode.HALF_UP)) .reduce(BigDecimal.ZERO, BigDecimal::add) .setScale(2, RoundingMode.HALF_UP); + return amount.compareTo(BigDecimal.ZERO) <= 0 ? "0.00" : amount.toString(); } - return "0"; + return "0.00"; } private String getPotentialProfit() { if (warehouseService.getDefaultWarehouse().isPresent()) { - return "" + inventoryService.findAll().stream() + BigDecimal amount = inventoryService.findAll().stream() .filter(inventory -> inventory.getInventoryType().equals(InventoryType.FINISHED_PRODUCT) && - inventory.getSalePrice() != null) - .map(inventory -> inventory.getSalePrice() + inventory.getItem().getSalePrice() != null) + .map(inventory -> inventory.getItem().getSalePrice() .multiply(BigDecimal.valueOf(inventory.getQuantity())) .setScale(2, RoundingMode.HALF_UP)) .reduce(BigDecimal.ZERO, BigDecimal::add) .setScale(2, RoundingMode.HALF_UP); + return amount.compareTo(BigDecimal.ZERO) <= 0 ? "0.00" : amount.toString(); } - return "0"; + return "0.00"; } private String getTotalWeightOfCereal() { diff --git a/src/main/java/service/AlertService.java b/src/main/java/service/AlertService.java index 52818bb..56263a0 100644 --- a/src/main/java/service/AlertService.java +++ b/src/main/java/service/AlertService.java @@ -1,5 +1,6 @@ package service; +import enums.ItemType; import enums.alerts.AlertAction; import enums.alerts.AlertTitle; import enums.alerts.AlertType; @@ -48,7 +49,7 @@ public void createLowInventoryAlert(Inventory inventory) { .action(AlertAction.BUY) .code(item.getCode()) .warehouse(inventory.getWarehouse()) - .alertType(AlertType.INVENTORY) + .alertType(item.getItemType().equals(ItemType.INVENTORY) ? AlertType.INVENTORY : AlertType.STOCK) .content(String.format("Existing Quantity: %s - Minimum Quantity Set: %s", item.getQuantity(), item.getMinQuantity())) .isResolved(false) diff --git a/src/main/java/service/InventoryService.java b/src/main/java/service/InventoryService.java index 44e11ee..6941c16 100644 --- a/src/main/java/service/InventoryService.java +++ b/src/main/java/service/InventoryService.java @@ -1,5 +1,6 @@ package service; +import context.UserContext; import enums.InventoryType; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -8,7 +9,6 @@ import records.InventoryManualRequest; import java.util.Comparator; -import java.util.Date; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -27,29 +27,43 @@ public class InventoryService { @Inject WarehouseService warehouseService; + @Inject + SupplierService supplierService; + @Inject AlertService alertService; + @Inject + UserContext userContext; + @Transactional public boolean createManualEntryOnInventory(InventoryManualRequest request) { if (Objects.isNull(request.entryDate())) throw new IllegalArgumentException("Invalid Entry Date!"); Inventory newEntry = Inventory.builder() - .salePrice(request.salePrice()) - .supplier(request.supplier().id == -1 ? null : request.supplier()) .batch(request.batch()) .warehouse(request.warehouse()) .item(itemService.findById(request.itemId())) .inventoryType(request.inventoryType()) - .unit(unitService.findById(request.unitId())) .quantity(request.quantity()) .costPrice(request.costPrice()) .entryDate(request.entryDate()) .build(); + newEntry.setCreatedBy(userContext.getCurrentUsername()); + newEntry.setModifiedBy(userContext.getCurrentUsername()); + + if (Objects.nonNull(request.supplier()) && request.supplier().id != null && request.supplier().id != -1) { + newEntry.setSupplier(request.supplier()); + } else { + newEntry.setSupplier(supplierService.getDummySupplier()); + } + + System.out.println(newEntry); newEntry.persistAndFlush(); itemService.updateQuantity(newEntry); + itemService.updateCosts(newEntry, request.retailPrice(), request.salePrice()); //we only create alerts if the entry is to remove from the inventory if (request.quantity() < 0) diff --git a/src/main/java/service/ItemService.java b/src/main/java/service/ItemService.java index f34ca56..df93fb8 100644 --- a/src/main/java/service/ItemService.java +++ b/src/main/java/service/ItemService.java @@ -10,6 +10,7 @@ import model.Item; import records.ItemRequest; +import java.math.BigDecimal; import java.util.List; @ApplicationScoped @@ -29,12 +30,15 @@ public boolean createItem(@NotNull ItemRequest item) { .name(item.name()) .brand(item.brand()) .category(itemCategoryService.findById(item.categoryId())) + .unit(item.unit()) .description(item.description()) .notes(item.notes()) .deprecated(item.deprecated()) .minQuantity(item.minQuantity()) .quantity(item.quantity()) .alertLowStock(item.alertLowStock()) + .retailPrice(item.retailPrice()) + .salePrice(item.salePrice()) .build().persistAndFlush(); return true; @@ -43,7 +47,18 @@ public boolean createItem(@NotNull ItemRequest item) { @Transactional public void updateQuantity(Inventory inventory) { inventory.getItem().setQuantity(inventory.getItem().getQuantity() + inventory.getQuantity()); - inventory.getItem().persistAndFlush(); + inventory.getItem().persist(); + } + + @Transactional + public void updateCosts(Inventory inventory, BigDecimal retailPrice, BigDecimal salePrice) { + Item item = inventory.getItem(); + if (retailPrice != null) + item.setRetailPrice(retailPrice); + if (salePrice != null) + item.setSalePrice(salePrice); + item.setIndicativeCostPrice(inventory.getCostPrice()); + item.persist(); } public List findAllInventory() { diff --git a/src/main/java/service/SupplierService.java b/src/main/java/service/SupplierService.java index 4005fbd..7ca0cd3 100644 --- a/src/main/java/service/SupplierService.java +++ b/src/main/java/service/SupplierService.java @@ -9,6 +9,8 @@ import records.SupplierRequest; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @ApplicationScoped public class SupplierService { @@ -34,13 +36,19 @@ public boolean createSupplier(@NotNull SupplierRequest supplier) { .contactPersonEmail(supplier.contactPersonEmail()) .contactPersonPhone(supplier.contactPersonPhone()) .currency(supplier.currency() == null ? Defaults.DEFAULT_CURRENCY : supplier.currency()) + .isDummy(false) .isActive(true).build().persistAndFlush(); return true; } public List findAll() { - return Supplier.findAll().list(); + return Supplier.findAll() + .list() + .stream() + .map(w -> (Supplier) w) + .filter(w -> !w.isDummy()) + .collect(Collectors.toList()); } public boolean existsById(@NotNull Integer id) { @@ -52,4 +60,21 @@ public void deleteSupplierById(@NotNull Integer id) { Supplier.deleteById(id); } + @Transactional + public Supplier getDummySupplier() { + Optional dummy = Supplier.find("isDummy", true).firstResultOptional(); + if (dummy.isPresent()) + return dummy.get(); + else { + Supplier.builder() + .code("DUMMY") + .currency("EUR") + .nif(-1L) + .notes("DUMMY SUPPLIER FOR INTERNAL STOCK") + .isDummy(true) + .name("DUMMY") + .build().persistAndFlush(); + return getDummySupplier(); + } + } }