ReplaceWarehouseUseCase.java
package com.fulfilment.application.monolith.warehouses.domain.usecases;
import com.fulfilment.application.monolith.warehouses.domain.models.Warehouse;
import com.fulfilment.application.monolith.warehouses.domain.ports.ReplaceWarehouseOperation;
import com.fulfilment.application.monolith.warehouses.domain.ports.WarehouseStore;
import jakarta.enterprise.context.ApplicationScoped;
import com.fulfilment.application.monolith.exception.HttpStatus;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.WebApplicationException;
import java.time.LocalDateTime;
import org.jboss.logging.Logger;
/**
* Replaces an active warehouse with a new one using the same Business Unit Code.
*
* <p>The replacement process:
* <ol>
* <li>Find the existing active warehouse by businessUnitCode</li>
* <li>Validate the new warehouse can accommodate the old stock (Capacity Accommodation)</li>
* <li>Validate the new warehouse stock matches the old warehouse stock (Stock Matching)</li>
* <li>Archive the old warehouse (soft delete via archivedAt timestamp)</li>
* <li>Create the new warehouse with the same businessUnitCode</li>
* </ol>
*
* <p>Both archive and create happen within the same transaction (managed by the caller)
* to guarantee atomicity — if create fails, the archive is rolled back.
*/
@ApplicationScoped
public class ReplaceWarehouseUseCase implements ReplaceWarehouseOperation {
private static final Logger LOGGER = Logger.getLogger(ReplaceWarehouseUseCase.class.getName());
private final WarehouseStore warehouseStore;
public ReplaceWarehouseUseCase(WarehouseStore warehouseStore) {
this.warehouseStore = warehouseStore;
}
@Override
public void replace(Warehouse newWarehouse) {
LOGGER.debugf("Attempting to replace warehouse with businessUnitCode: '%s'",
newWarehouse.businessUnitCode);
// 1. Find the existing active warehouse by businessUnitCode
Warehouse oldWarehouse = warehouseStore.findByBusinessUnitCode(newWarehouse.businessUnitCode);
if (oldWarehouse == null) {
LOGGER.warnf("No active warehouse found with businessUnitCode '%s'",
newWarehouse.businessUnitCode);
throw new NotFoundException(
"Warehouse with business unit code '" + newWarehouse.businessUnitCode + "' not found.");
}
// 2. Capacity Accommodation — new warehouse must be able to hold the old stock
if (newWarehouse.capacity < oldWarehouse.stock) {
LOGGER.warnf(
"New warehouse capacity %d cannot accommodate old warehouse stock %d",
newWarehouse.capacity, oldWarehouse.stock);
throw new WebApplicationException(
"New warehouse capacity (" + newWarehouse.capacity
+ ") cannot accommodate the stock of the warehouse being replaced ("
+ oldWarehouse.stock + ").", HttpStatus.UNPROCESSABLE_ENTITY);
}
// 3. Stock Matching — new warehouse stock must equal old warehouse stock
if (!newWarehouse.stock.equals(oldWarehouse.stock)) {
LOGGER.warnf(
"Stock mismatch — new warehouse stock %d does not match old warehouse stock %d",
newWarehouse.stock, oldWarehouse.stock);
throw new WebApplicationException(
"New warehouse stock (" + newWarehouse.stock
+ ") must match the stock of the warehouse being replaced ("
+ oldWarehouse.stock + ").", HttpStatus.UNPROCESSABLE_ENTITY);
}
// 4. Archive the old warehouse (soft delete)
oldWarehouse.archivedAt = LocalDateTime.now();
warehouseStore.update(oldWarehouse);
LOGGER.infof("Warehouse '%s' archived at %s", oldWarehouse.businessUnitCode, oldWarehouse.archivedAt);
// 5. Create the new warehouse with the same businessUnitCode
newWarehouse.createdAt = LocalDateTime.now();
warehouseStore.create(newWarehouse);
LOGGER.infof("Replacement warehouse '%s' created successfully at location '%s'",
newWarehouse.businessUnitCode, newWarehouse.location);
}
}