AllocationServiceImpl.java
/*
* Copyright 2005-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openwms.wms.inventory.allocation.impl;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.ameba.annotation.Measured;
import org.ameba.annotation.TxService;
import org.openwms.core.units.api.Measurable;
import org.openwms.wms.inventory.PackagingUnit;
import org.openwms.wms.inventory.PackagingUnitService;
import org.openwms.wms.inventory.ProductService;
import org.openwms.wms.inventory.Reservation;
import org.openwms.wms.inventory.allocation.Allocation;
import org.openwms.wms.inventory.allocation.AllocationException;
import org.openwms.wms.inventory.allocation.AllocationService;
import org.openwms.wms.inventory.allocation.spi.AllocationRule;
import org.openwms.wms.inventory.allocation.spi.Allocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import static org.openwms.wms.InventoryLoggerCategories.ALLOCATION;
/**
* A AllocationServiceImpl.
*
* @author Heiko Scherrer
*/
@Validated
@TxService
class AllocationServiceImpl implements AllocationService {
private static final Logger ALLOCATION_LOGGER = LoggerFactory.getLogger(ALLOCATION);
private final ProductService productService;
private final PackagingUnitService packagingUnitService;
private final Allocator allocation;
AllocationServiceImpl(ProductService productService, PackagingUnitService packagingUnitService, Allocator allocation) {
this.productService = productService;
this.packagingUnitService = packagingUnitService;
this.allocation = allocation;
}
/**
* {@inheritDoc}
*/
@Measured
@Override
public List<Allocation> allocate(@NotNull Measurable amount, @NotBlank String sku,
List<String> sourceLocationGroupNames) {
if (ALLOCATION_LOGGER.isDebugEnabled()) {
ALLOCATION_LOGGER.debug("Trying to allocate an mount of [{}] for product [{}] in LocationGroups {}",
amount, sku, sourceLocationGroupNames);
}
var product = productService.findBySKUorThrow(sku);
try {
List<PackagingUnit> packagingUnits = allocation.allocate(new AllocationRule(amount, product, sourceLocationGroupNames));
if (ALLOCATION_LOGGER.isDebugEnabled()) {
ALLOCATION_LOGGER.debug("Found [{}] number of PackagingUnits for allocation", packagingUnits.size());
}
return packagingUnits.stream()
.filter(pu -> !pu.getQtyAvailable().isZero() && !pu.getQtyAvailable().isNegative())
.map(pu -> {
Measurable qtyReserved;
if (pu.getQtyAvailable().compareTo(amount) <= 0) {
qtyReserved = pu.getQtyAvailable();
} else {
qtyReserved = amount;
}
var reservation = new Reservation(qtyReserved, UUID.randomUUID().toString());
reservation.setPackagingUnit(pu);
ALLOCATION_LOGGER.debug("On PU [{}] the qtyAvailable is [{}], reservation has been added [{}]", pu.getPersistentKey(), pu.getQtyAvailable(), reservation);
pu.addReservation(reservation);
packagingUnitService.save(pu);
var builder = Allocation.AllocationBuilder.anAllocation()
.product(pu.getProduct())
.qtyAvailable(qtyReserved)
.reservationId(reservation.getReservedBy());
if (pu.hasLoadUnit()) {
builder.transportUnit(pu.getLoadUnit().getTransportUnit())
.loadUnit(pu.getLoadUnit())
.actualLocation(pu.getLoadUnit().getTransportUnit().getActualLocation());
} else {
builder.actualLocation(pu.getActualLocation());
}
return builder.build();
})
.toList();
} catch (AllocationException e) {
ALLOCATION_LOGGER.error(e.getMessage(), e);
return Collections.emptyList();
}
}
}