ProductMapper.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;
import org.mapstruct.Context;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.openwms.wms.CycleAvoidingMappingContext;
import org.openwms.wms.inventory.api.ProductVO;
import org.openwms.wms.inventory.api.UomRelationVO;
import org.openwms.wms.inventory.events.ProductMO;
import org.openwms.wms.location.impl.LocationMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* A ProductMapper.
*
* @author Heiko Scherrer
*/
@Mapper(uses = {DimensionMapper.class, LocationMapper.class})
public abstract class ProductMapper {
protected ProductRepository productRepository;
protected UomRelationService uomRelationService;
protected DimensionMapper dimensionMapper;
protected LocationMapper locationMapper;
@Autowired
public void setProductRepository(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Autowired
public void setUomRelationService(UomRelationService uomRelationService) {
this.uomRelationService = uomRelationService;
}
@Autowired
public void setDimensionMapper(DimensionMapper dimensionMapper) {
this.dimensionMapper = dimensionMapper;
}
@Autowired
public void setLocationMapper(LocationMapper locationMapper) {
this.locationMapper = locationMapper;
}
@Mapping(target = "pKey", source = "persistentKey")
@Mapping(target = "sku", source = "sku")
@Mapping(target = "label", source = "label")
@Mapping(target = "accountId", source = "accountId")
@Mapping(target = "baseUnit", source = "baseUnit")
@Mapping(target = "overbookingAllowed", source = "overbookingAllowed")
@Mapping(target = "description", source = "description")
@Mapping(target = "classification", source = "classification")
@Mapping(target = "group", source = "group")
@Mapping(target = "stockZone", source = "stockZone")
@Mapping(target = "units", source = "units")
@Mapping(target = "details", source = "details")
public abstract ProductMO convertToMO(Product entity);
public String convertTo(UomRelation entity) {
if (entity == null) {
return null;
}
return entity.getLabel();
}
@Mapping(target = "pKey", source = "persistentKey")
@Mapping(target = "quantity", source = "unit")
public abstract UomRelationVO convert(UomRelation eo, @Context CycleAvoidingMappingContext ctx);
public UomRelation convertVO(UomRelationVO vo) {
if (vo == null) {
return null;
}
String pKey = vo.getpKey();
UomRelation uomRelation = pKey == null ? new UomRelation() : uomRelationService.findBypKey(pKey).orElse(new UomRelation());
if (vo.getProduct() != null) {
uomRelation.setProduct(this.convertVO(vo.getProduct()));
}
if (vo.getLabel() != null) {
uomRelation.setLabel(vo.getLabel());
}
if (vo.getCode() != null) {
uomRelation.setCode(vo.getCode());
}
if (vo.getDimension() != null) {
uomRelation.setDimension(dimensionMapper.convertVO(vo.getDimension()));
}
if (vo.getQuantity() != null) {
uomRelation.setUnit(vo.getQuantity());
}
Map<String, String> details = vo.getDetails();
if (details != null) {
uomRelation.setDetails(new HashMap<>(details));
}
return uomRelation;
}
public void copy(Product source, Product target) {
Assert.hasText(source.getSku(), "sku must not be null");
Assert.notNull(source.getBaseUnit(), "baseUnit must not be null");
copyValue(source.getSku(), target.getSku(), target::setSku);
copyValue(source.getLabel(), target.getLabel(), target::setLabel);
copyValue(source.getAccountId(), target.getAccountId(), target::setAccountId);
if (source.getBaseUnit() != target.getBaseUnit()) {
target.setBaseUnit(source.getBaseUnit());
}
target.setOverbookingAllowed(source.isOverbookingAllowed());
copyValue(source.getDescription(), target.getDescription(), target::setDescription);
if (source.getAvailabilityState() != target.getAvailabilityState()) {
target.setAvailabilityState(source.getAvailabilityState());
}
copyValue(source.getClassification(), target.getClassification(), target::setClassification);
copyValue(source.getGroup(), target.getGroup(), target::setGroup);
copyValue(source.getStockZone(), target.getStockZone(), target::setStockZone);
if (source.getUnits() == null && target.getUnits() != null) {
target.setUnits(null);
} else if (source.getUnits() != null) {
target.setUnits(source.getUnits());
}
if (source.getDetails() != null) {
target.setDetails(source.getDetails());
}
target.setDimension(source.getDimension());
target.setNetWeight(source.getNetWeight());
target.setPreferableStorageLocation(source.getPreferableStorageLocation());
target.setDetails(source.getDetails());
}
private void copyValue(String source, String target, Consumer<String> func) {
if (source != null && !source.equals(target)) {
func.accept(source);
}
}
public Product convertVO(ProductVO vo) {
if (vo == null) {
return null;
}
var pKey = vo.getpKey();
var product = pKey == null ? new Product() : productRepository.findBypKey(pKey).orElse(new Product());
if (vo.getAccountId() != null) {
product.setAccountId(vo.getAccountId());
}
if (vo.getAvailabilityState() != null) {
product.setAvailabilityState(vo.getAvailabilityState());
}
if (vo.getClassification() != null) {
product.setClassification(vo.getClassification());
}
if (vo.getGroup() != null) {
product.setGroup(vo.getGroup());
}
if (vo.getLabel() != null) {
product.setLabel(vo.getLabel());
}
if (vo.getDescription() != null) {
product.setDescription(vo.getDescription());
}
if (vo.getSku() != null) {
product.setSku(vo.getSku());
}
if (vo.getStockZone() != null) {
product.setStockZone(vo.getStockZone());
}
if (vo.getBaseUnit() != null) {
product.setBaseUnit(vo.getBaseUnit());
}
if (vo.getOverbookingAllowed() != null) {
product.setOverbookingAllowed(vo.getOverbookingAllowed());
}
if (vo.getDetails() != null) {
product.setDetails(vo.getDetails());
}
if (vo.getDimension() != null) {
product.setDimension(dimensionMapper.convertVO(vo.getDimension()));
}
if (vo.getNetWeight() != null) {
product.setNetWeight(vo.getNetWeight());
}
if (vo.getPreferableStorageLocation() != null) {
product.setPreferableStorageLocation(locationMapper.convertFromId(vo.getPreferableStorageLocation().getLocationId()));
}
if (vo.getUnits() != null) {
product.setUnits(convert(vo.getUnits(), product));
}
return product;
}
public abstract List<Product> convertVO(List<ProductVO> vos);
@Mapping(target = "pKey", source = "persistentKey")
@Mapping(target = "units", source = "units")
@Mapping(target = "stackingRules", source = "stackingRules")
public abstract ProductVO convert(Product entity, @Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
public abstract List<ProductVO> convert(List<Product> entities, @Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
private List<UomRelation> convert(List<UomRelationVO> units, Product product) {
return units.stream().map(vo -> {
var uomRelation = vo.pKey == null ? new UomRelation() : uomRelationService.findBypKey(vo.pKey).orElse(new UomRelation());
if (uomRelation.getProduct() == null) {
uomRelation.setProduct(product);
}
if (vo.getQuantity() != null) {
uomRelation.setUnit(vo.getQuantity());
}
if (vo.getLabel() != null) {
uomRelation.setLabel(vo.getLabel());
}
if (vo.getDimension() != null) {
uomRelation.setDimension(dimensionMapper.convertVO(vo.getDimension()));
}
if (vo.getDetails() != null) {
uomRelation.setDetails(vo.getDetails());
}
if (vo.getCode() != null) {
uomRelation.setCode(vo.getCode());
}
return uomRelation;
}).collect(Collectors.toList()); // *** Keep this and return a mutable list ***
}
}