Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OP-1197 | Validate ward Inventory #1456

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a6eafc3
Add new column on medicalinventory
JantBogard Nov 19, 2024
c9e61e9
add validate ward inventory row function
JantBogard Nov 20, 2024
fda7889
Merge commit '9de0c494352aad72afe1a381ed5a1e41fdd99a14' into OP-1193_…
JantBogard Nov 20, 2024
95768bb
Merge branch 'develop' into OP-1193_OP-1194_OP-1197
JantBogard Nov 20, 2024
e9441a5
Remove uneccessary format code
JantBogard Nov 20, 2024
eaa06f4
Remove uneccessary format code
JantBogard Nov 20, 2024
2fe89dd
Write united test for validateWardinventory
JantBogard Nov 22, 2024
65e2238
Merge branch 'develop' into OP-1193_OP-1194_OP-1197
JantBogard Nov 22, 2024
efb091e
Add the standard license header block
JantBogard Nov 25, 2024
cb7d385
Merge branch 'develop' into OP-1193_OP-1194_OP-1197
JantBogard Nov 27, 2024
6b9925f
Remove reason attribut
JantBogard Nov 27, 2024
6d2e1e9
Add actualize inventory row function
JantBogard Nov 28, 2024
23c35f5
Merge branch 'develop' into OP-1193_OP-1194_OP-1197
JantBogard Nov 29, 2024
10c2d3d
update validateMedicalWardInventoryRow function
JantBogard Dec 3, 2024
7a71250
Merge branch 'develop' into OP-1193_OP-1194_OP-1197
JantBogard Dec 3, 2024
5892e90
update validateMedicalWardInventoryRow function
JantBogard Dec 3, 2024
f01faa7
Update src/main/java/org/isf/medicalinventory/manager/MedicalInventor…
JantBogard Dec 9, 2024
5415bf9
Update src/main/java/org/isf/medicalinventory/manager/MedicalInventor…
JantBogard Dec 9, 2024
1d9750e
Update src/main/java/org/isf/medicalinventory/manager/MedicalInventor…
JantBogard Dec 9, 2024
51f2974
Applying suggestion for change
JantBogard Dec 9, 2024
07881cd
Fix test coverage
JantBogard Dec 10, 2024
24489e4
Update test validation medical ward inventory row
JantBogard Dec 12, 2024
66a1579
Update test validation medical ward inventory row
JantBogard Dec 12, 2024
6569133
Merge branch 'develop' into OP-1193_OP-1194_OP-1197
JantBogard Dec 12, 2024
a3084ae
Add actualize inventory row test
JantBogard Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
import org.isf.medstockmovtype.model.MovementType;
import org.isf.supplier.manager.SupplierBrowserManager;
import org.isf.supplier.model.Supplier;
import org.isf.medicalstockward.manager.MovWardBrowserManager;
import org.isf.medicalstockward.model.MedicalWard;
import org.isf.medicalstockward.model.MovementWard;
import org.isf.utils.exception.OHDataValidationException;
import org.isf.utils.exception.OHServiceException;
import org.isf.utils.exception.model.OHExceptionMessage;
Expand Down Expand Up @@ -74,20 +77,23 @@ public class MedicalInventoryManager {
private final SupplierBrowserManager supplierManager;

private final WardBrowserManager wardManager;

protected Map<String, String> statusHashMap;

private MovWardBrowserManager movWardBrowserManager;

public MedicalInventoryManager(MedicalInventoryIoOperation medicalInventoryIoOperation, MedicalInventoryRowManager medicalInventoryRowManager,
MedicalDsrStockMovementTypeBrowserManager medicalDsrStockMovementTypeBrowserManager,
SupplierBrowserManager supplierManager, MovStockInsertingManager movStockInsertingManager, WardBrowserManager wardManager,
MovBrowserManager movBrowserManager) {
MedicalDsrStockMovementTypeBrowserManager medicalDsrStockMovementTypeBrowserManager,
SupplierBrowserManager supplierManager, MovStockInsertingManager movStockInsertingManager, WardBrowserManager wardManager,
MovBrowserManager movBrowserManager, MovWardBrowserManager movWardBrowserManager) {
this.ioOperations = medicalInventoryIoOperation;
this.medicalInventoryRowManager = medicalInventoryRowManager;
this.medicalDsrStockMovementTypeBrowserManager = medicalDsrStockMovementTypeBrowserManager;
this.supplierManager = supplierManager;
this.movStockInsertingManager = movStockInsertingManager;
this.wardManager = wardManager;
this.movBrowserManager = movBrowserManager;
this.movWardBrowserManager = movWardBrowserManager;
}

/**
Expand Down Expand Up @@ -360,6 +366,101 @@ public void validateMedicalInventoryRow(MedicalInventory inventory, List<Medical
}
}

/**
* Validate the Inventory rows of inventory ward.
*
* @param inventory the {@link MedicalInventory}
* @param inventoryRowSearchList the list of {@link MedicalInventory}
* @throws OHServiceException
*/
public void validateMedicalWardInventoryRow(MedicalInventory inventory, List<MedicalInventoryRow> inventoryRowSearchList) throws OHServiceException {
LocalDateTime movFrom = inventory.getInventoryDate();
LocalDateTime movTo = TimeTools.getNow();
StringBuilder medDescriptionForLotUpdated = new StringBuilder("\n"); // initial new line
StringBuilder medDescriptionForNewLot = new StringBuilder("\n"); // initial new line
StringBuilder medDescriptionForNewMedical = new StringBuilder("\n"); // initial new line
boolean lotUpdated = false;
boolean lotAdded = false;
boolean medicalAdded = false;

List<MovementWard> movementWards = new ArrayList<>(movWardBrowserManager.getMovementWard(inventory.getWard(), movFrom, movTo));
List<Movement> movementToWards = new ArrayList<>(movBrowserManager.getMovements(inventory.getWard(), movFrom, movTo));
List<Medical> inventoryMedicalsList = inventoryRowSearchList.stream().map(MedicalInventoryRow::getMedical).distinct().toList();

// Get all the lots from ward movements
List<Lot> lotOfMovements = new ArrayList<>(movementWards.stream().map(MovementWard::getLot).toList());
// Get all the lots from main store movements
lotOfMovements.addAll(movementToWards.stream().map(Movement::getLot).toList());
// Remove duplicates by converting the list to a set
Set<Lot> uniqueLots = new HashSet<>(lotOfMovements);
// Convert the set back to a list
List<Lot> uniqueLotList = new ArrayList<>(uniqueLots);
// Cycle fetched movements to see if they impact inventoryRowSearchList
for (Lot lot : uniqueLotList) {
String lotCode = lot.getCode();
String lotExpiringDate = TimeTools.formatDateTime(lot.getDueDate(), TimeTools.DD_MM_YYYY);
String lotInfo = GeneralData.AUTOMATICLOT_IN ? lotExpiringDate : lotCode;
Medical medical = lot.getMedical();
String medicalDesc = medical.getDescription();

Optional<MedicalWard> optMedicalWard = movWardBrowserManager.getMedicalsWard(inventory.getWard(), medical.getCode(), false).stream()
.filter(m -> m.getLot().getCode().equals(lotCode)).findFirst();

double wardStoreQty = optMedicalWard.isPresent() ? optMedicalWard.get().getQty() : 0.0;

// Search for the specific Lot and Medical in inventoryRowSearchList
Optional<MedicalInventoryRow> matchingRow = inventoryRowSearchList.stream()
.filter(row -> row.getLot().getCode().equals(lotCode)).findFirst();

if (matchingRow.isPresent()) {
MedicalInventoryRow medicalInventoryRow = matchingRow.get();
double theoQty = medicalInventoryRow.getTheoreticQty();
if (wardStoreQty != theoQty) {
lotUpdated = true;
medDescriptionForLotUpdated
.append("\n")
.append(MessageBundle.formatMessage("angal.inventory.theoreticalqtyhavebeenupdatedforsomemedical.detail.fmt.msg",
medicalDesc, lotInfo, theoQty, wardStoreQty, wardStoreQty - theoQty));
}
} else {
// TODO: to decide if to give control to the user about this
if (!inventoryMedicalsList.contains(medical)) {
// New medical
medicalAdded = true;
medDescriptionForNewMedical
.append("\n")
.append(MessageBundle.formatMessage("angal.inventory.newmedicalshavebeenfound.detail.fmt.msg",
medicalDesc, lotInfo, wardStoreQty));
} else {
// New Lot
lotAdded = true;
medDescriptionForNewLot
.append("\n")
.append(MessageBundle.formatMessage("angal.inventory.newlotshavebeenaddedforsomemedical.detail.fmt.msg",
medicalDesc, lotInfo, wardStoreQty));
}
}
}
List<OHExceptionMessage> errors = new ArrayList<>();
JantBogard marked this conversation as resolved.
Show resolved Hide resolved
if (lotUpdated) {
errors.add(new OHExceptionMessage(MessageBundle.getMessage("angal.inventory.validate.btn"),
JantBogard marked this conversation as resolved.
Show resolved Hide resolved
MessageBundle.formatMessage("angal.inventory.theoreticalqtyhavebeenupdatedforsomemedicalward.fmt.msg", medDescriptionForLotUpdated),
OHSeverityLevel.INFO));
}
if (lotAdded) {
errors.add(new OHExceptionMessage(MessageBundle.getMessage("angal.inventory.validate.btn"),
MessageBundle.formatMessage("angal.inventory.newlotshavebeenaddedforsomemedicalward.fmt.msg", medDescriptionForNewLot),
OHSeverityLevel.INFO));
}
if (medicalAdded) {
errors.add(new OHExceptionMessage(MessageBundle.getMessage("angal.inventory.validate.btn"),
MessageBundle.formatMessage("angal.inventory.newmedicalshavebeenfoundward.fmt.msg", medDescriptionForNewMedical), OHSeverityLevel.INFO));
}
if (!errors.isEmpty()) {
throw new OHDataValidationException(errors);
}
}

/**
* Marks an inventory as deleted by changing its status.
*
Expand Down Expand Up @@ -519,7 +620,7 @@ public MedicalInventory actualizeMedicalInventoryRow(MedicalInventory inventory)
}
return this.updateMedicalInventory(inventory, true);
}

private void buildStatusHashMap() {
statusHashMap = new HashMap<>(4);
statusHashMap.put("canceled", MessageBundle.getMessage("angal.inventory.status.canceled.txt"));
Expand All @@ -545,7 +646,7 @@ public List<String> getStatusList() {
statusList.sort(new DefaultSorter(MessageBundle.getMessage("angal.inventory.status.draft.txt")));
return statusList;
}

/**
* Return a value of the key on statusHashMap.
* @param key - the key of status
Expand All @@ -562,4 +663,61 @@ public String getStatusByKey(String key) {
}
return "";
}

/**
* Actualize the {@link MedicalInventory}'s ward.
*
* @param inventory the {@link MedicalInventory}
* @return {@link MedicalInventory}. It could be {@code null}.
* @throws OHServiceException
*/
public MedicalInventory actualizeMedicalWardInventoryRow(MedicalInventory inventory) throws OHServiceException {
JantBogard marked this conversation as resolved.
Show resolved Hide resolved
LocalDateTime movFrom = inventory.getInventoryDate();
LocalDateTime movTo = TimeTools.getNow();

List<MovementWard> movementWards = new ArrayList<>(movWardBrowserManager.getMovementWard(inventory.getWard(), movFrom, movTo));
List<Movement> movementToWards = new ArrayList<>(movBrowserManager.getMovements(inventory.getWard(), movFrom, movTo));
List<MedicalInventoryRow> inventoryRowList = medicalInventoryRowManager.getMedicalInventoryRowByInventoryId(inventory.getId());

// Get all the lots from the ward movements
List<Lot> lotOfMovements = new ArrayList<>(movementWards.stream().map(MovementWard::getLot).toList());
// Get all the lots from the main store movements
lotOfMovements.addAll(movementToWards.stream().map(Movement::getLot).toList());
// Remove duplicates by converting the list to a set
Set<Lot> uniqueLots = new HashSet<>(lotOfMovements);
// Convert the set back to a list
List<Lot> uniqueLotList = new ArrayList<>(uniqueLots);
// Cycle fetched movements to see if they impact inventoryRowSearchList
for (Lot lot : uniqueLotList) {
String lotCode = lot.getCode();
Medical medical = lot.getMedical();
Integer medicalCode = medical.getCode();
// Fetch also empty lots because some movements may have discharged them completely
Optional<MedicalWard> optMedicalWard = movWardBrowserManager.getMedicalsWard(inventory.getWard(), medical.getCode(), false).stream()
.filter(m -> m.getLot().getCode().equals(lotCode)).findFirst();
double wardStoreQty = optMedicalWard.isPresent() ? optMedicalWard.get().getQty() : 0.0;

// Search for the specific Lot and Medical in inventoryRowSearchList (Lot should be enough)
Optional<MedicalInventoryRow> matchingRow = inventoryRowList.stream()
.filter(row -> row.getLot().getCode().equals(lotCode) && row.getMedical().getCode().equals(medicalCode))
.findFirst();

if (matchingRow.isPresent()) {
MedicalInventoryRow medicalInventoryRow = matchingRow.get();
double theoQty = medicalInventoryRow.getTheoreticQty();
if (wardStoreQty != theoQty) {
// Update Lot
medicalInventoryRow.setTheoreticQty(wardStoreQty);
medicalInventoryRow.setRealqty(wardStoreQty);
medicalInventoryRowManager.updateMedicalInventoryRow(medicalInventoryRow);
}
} else {
// TODO: to decide if to give control to the user about this
double realQty = wardStoreQty;
MedicalInventoryRow newMedicalInventoryRow = new MedicalInventoryRow(null, wardStoreQty, realQty, inventory, medical, lot);
medicalInventoryRowManager.newMedicalInventoryRow(newMedicalInventoryRow);
}
}
return this.updateMedicalInventory(inventory, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Open Hospital (www.open-hospital.org)
* Copyright © 2006-2024 Informatici Senza Frontiere ([email protected])
*
* Open Hospital is a free and open source software for healthcare data management.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* https://www.gnu.org/licenses/gpl-3.0-standalone.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.isf.medicalsinventory;
JantBogard marked this conversation as resolved.
Show resolved Hide resolved

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.within;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

import org.isf.medicalinventory.model.InventoryStatus;
import org.isf.medicalinventory.model.InventoryType;
import org.isf.medicalinventory.model.MedicalInventory;
import org.isf.utils.exception.OHException;
import org.isf.utils.time.TimeTools;
import org.isf.ward.model.Ward;

public class TestMedicalWardInventory {
private int id = 1;
private String status = InventoryStatus.draft.toString();
private LocalDateTime inventoryDate = TimeTools.getNow();
private String user = "admin";
private String inventoryReference = "REFERENCE";
private String inventoryType = InventoryType.ward.toString();
private String ward = "Z";

public MedicalInventory setup(Ward ward, boolean usingSet) throws OHException {
MedicalInventory medicalInventory;

if (usingSet) {
medicalInventory = new MedicalInventory();
setParameters(medicalInventory);
} else {
// create MedicalInventory with all parameters
medicalInventory = new MedicalInventory(id, status, inventoryDate, user, inventoryReference, inventoryType, ward.getCode());
}
return medicalInventory;
}

public void setParameters(MedicalInventory medicalInventory) {
medicalInventory.setId(id);
medicalInventory.setStatus(status);
medicalInventory.setInventoryDate(inventoryDate);
medicalInventory.setUser(user);
medicalInventory.setInventoryReference(inventoryReference);
medicalInventory.setInventoryType(inventoryType);
medicalInventory.setWard(ward);
}

public void check(MedicalInventory medicalInventory, int id) {
assertThat(medicalInventory.getId()).isEqualTo(id);
assertThat(medicalInventory.getStatus()).isEqualTo(status);
assertThat(medicalInventory.getInventoryDate()).isCloseTo(inventoryDate, within(1, ChronoUnit.SECONDS));
assertThat(medicalInventory.getUser()).isEqualTo(user);
assertThat(medicalInventory.getInventoryReference()).isEqualTo(inventoryReference);
assertThat(medicalInventory.getInventoryType()).isEqualTo(inventoryType);
assertThat(medicalInventory.getWard()).isEqualTo(ward);
}
}
Loading
Loading