Bugfixes for #72, #73, #75, #68

This commit is contained in:
Jan 2025-12-14 10:39:15 +01:00
parent b75fe9bb99
commit bce745e458
5 changed files with 55 additions and 20 deletions

View file

@ -24,7 +24,6 @@ public class BulkExportService {
private final HeaderCellStyleProvider headerCellStyleProvider; private final HeaderCellStyleProvider headerCellStyleProvider;
private final ContainerRateExcelMapper containerRateExcelMapper; private final ContainerRateExcelMapper containerRateExcelMapper;
private final MatrixRateExcelMapper matrixRateExcelMapper; private final MatrixRateExcelMapper matrixRateExcelMapper;
private final MaterialExcelMapper materialExcelMapper;
private final PackagingExcelMapper packagingExcelMapper; private final PackagingExcelMapper packagingExcelMapper;
private final NodeExcelMapper nodeExcelMapper; private final NodeExcelMapper nodeExcelMapper;
private final HiddenNodeExcelMapper hiddenNodeExcelMapper; private final HiddenNodeExcelMapper hiddenNodeExcelMapper;
@ -32,11 +31,10 @@ public class BulkExportService {
private final String sheetPassword; private final String sheetPassword;
private final MaterialFastExcelMapper materialFastExcelMapper; private final MaterialFastExcelMapper materialFastExcelMapper;
public BulkExportService(@Value("${lcc.bulk.sheet_password}") String sheetPassword, HeaderCellStyleProvider headerCellStyleProvider, ContainerRateExcelMapper containerRateExcelMapper, MatrixRateExcelMapper matrixRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, HiddenNodeExcelMapper hiddenNodeExcelMapper, HiddenCountryExcelMapper hiddenCountryExcelMapper, MaterialFastExcelMapper materialFastExcelMapper) { public BulkExportService(@Value("${lcc.bulk.sheet_password}") String sheetPassword, HeaderCellStyleProvider headerCellStyleProvider, ContainerRateExcelMapper containerRateExcelMapper, MatrixRateExcelMapper matrixRateExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, HiddenNodeExcelMapper hiddenNodeExcelMapper, HiddenCountryExcelMapper hiddenCountryExcelMapper, MaterialFastExcelMapper materialFastExcelMapper) {
this.headerCellStyleProvider = headerCellStyleProvider; this.headerCellStyleProvider = headerCellStyleProvider;
this.containerRateExcelMapper = containerRateExcelMapper; this.containerRateExcelMapper = containerRateExcelMapper;
this.matrixRateExcelMapper = matrixRateExcelMapper; this.matrixRateExcelMapper = matrixRateExcelMapper;
this.materialExcelMapper = materialExcelMapper;
this.packagingExcelMapper = packagingExcelMapper; this.packagingExcelMapper = packagingExcelMapper;
this.nodeExcelMapper = nodeExcelMapper; this.nodeExcelMapper = nodeExcelMapper;
this.hiddenNodeExcelMapper = hiddenNodeExcelMapper; this.hiddenNodeExcelMapper = hiddenNodeExcelMapper;
@ -93,10 +91,6 @@ public class BulkExportService {
matrixRateExcelMapper.fillSheet(worksheet, style, periodId); matrixRateExcelMapper.fillSheet(worksheet, style, periodId);
matrixRateExcelMapper.createConstraints(workbook, worksheet); matrixRateExcelMapper.createConstraints(workbook, worksheet);
break; break;
// case MATERIAL:
// materialExcelMapper.fillSheet(worksheet, style);
// materialExcelMapper.createConstraints(worksheet);
// break;
case PACKAGING: case PACKAGING:
packagingExcelMapper.fillSheet(worksheet, style); packagingExcelMapper.fillSheet(worksheet, style);
packagingExcelMapper.createConstraints(workbook, worksheet); packagingExcelMapper.createConstraints(workbook, worksheet);

View file

@ -96,10 +96,6 @@ public class BulkImportService {
var matrixRates = matrixRateExcelMapper.extractSheet(sheet); var matrixRates = matrixRateExcelMapper.extractSheet(sheet);
matrixRateImportService.processMatrixRates(matrixRates); matrixRateImportService.processMatrixRates(matrixRates);
break; break;
// case MATERIAL:
// var materials = materialExcelMapper.extractSheet(sheet);
// materials.forEach(materialBulkImportService::processMaterialInstructions);
// break;
case PACKAGING: case PACKAGING:
var packaging = packagingExcelMapper.extractSheet(sheet); var packaging = packagingExcelMapper.extractSheet(sheet);
packaging.forEach(packagingBulkImportService::processPackagingInstructions); packaging.forEach(packagingBulkImportService::processPackagingInstructions);

View file

@ -4,9 +4,12 @@ import de.avatic.lcc.dto.generic.TransportType;
import de.avatic.lcc.model.bulk.HiddenTableType; import de.avatic.lcc.model.bulk.HiddenTableType;
import de.avatic.lcc.model.bulk.header.ContainerRateHeader; import de.avatic.lcc.model.bulk.header.ContainerRateHeader;
import de.avatic.lcc.model.bulk.header.HiddenNodeHeader; import de.avatic.lcc.model.bulk.header.HiddenNodeHeader;
import de.avatic.lcc.model.db.nodes.Node;
import de.avatic.lcc.model.db.properties.SystemPropertyMappingId;
import de.avatic.lcc.model.db.rates.ContainerRate; import de.avatic.lcc.model.db.rates.ContainerRate;
import de.avatic.lcc.repositories.NodeRepository; import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.rates.ContainerRateRepository; import de.avatic.lcc.repositories.rates.ContainerRateRepository;
import de.avatic.lcc.service.access.PropertyService;
import de.avatic.lcc.service.bulk.helper.ConstraintGenerator; import de.avatic.lcc.service.bulk.helper.ConstraintGenerator;
import de.avatic.lcc.service.bulk.helper.HeaderGenerator; import de.avatic.lcc.service.bulk.helper.HeaderGenerator;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError; import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
@ -16,6 +19,7 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
@Service @Service
public class ContainerRateExcelMapper { public class ContainerRateExcelMapper {
@ -24,12 +28,14 @@ public class ContainerRateExcelMapper {
private final ContainerRateRepository containerRateRepository; private final ContainerRateRepository containerRateRepository;
private final NodeRepository nodeRepository; private final NodeRepository nodeRepository;
private final ConstraintGenerator constraintGenerator; private final ConstraintGenerator constraintGenerator;
private final PropertyService propertyService;
public ContainerRateExcelMapper(HeaderGenerator headerGenerator, ContainerRateRepository containerRateRepository, NodeRepository nodeRepository, ConstraintGenerator constraintGenerator) { public ContainerRateExcelMapper(HeaderGenerator headerGenerator, ContainerRateRepository containerRateRepository, NodeRepository nodeRepository, ConstraintGenerator constraintGenerator, PropertyService propertyService) {
this.headerGenerator = headerGenerator; this.headerGenerator = headerGenerator;
this.containerRateRepository = containerRateRepository; this.containerRateRepository = containerRateRepository;
this.nodeRepository = nodeRepository; this.nodeRepository = nodeRepository;
this.constraintGenerator = constraintGenerator; this.constraintGenerator = constraintGenerator;
this.propertyService = propertyService;
} }
public void fillSheet(Sheet sheet, CellStyle headerStyle, Integer periodId) { public void fillSheet(Sheet sheet, CellStyle headerStyle, Integer periodId) {
@ -73,10 +79,20 @@ public class ContainerRateExcelMapper {
return true; return true;
} }
private String getRefStart() {
Optional<String> ref = propertyService.getProperty(SystemPropertyMappingId.START_REF);
return ref.orElseThrow(() -> new InternalError("Unable to get start reference from properties"));
}
private String getRefEnd() {
Optional<String> ref = propertyService.getProperty(SystemPropertyMappingId.END_REF);
return ref.orElseThrow(() -> new InternalError("Unable to get end reference from properties"));
}
public List<ContainerRate> extractSheet(Sheet sheet) { public List<ContainerRate> extractSheet(Sheet sheet) {
headerGenerator.validateHeader(sheet, ContainerRateHeader.class); headerGenerator.validateHeader(sheet, ContainerRateHeader.class);
var rates = new ArrayList<ContainerRate>(); var rates = new ArrayList<ExcelContainerRate>();
sheet.forEach(row -> { sheet.forEach(row -> {
if (row.getRowNum() == 0) return; if (row.getRowNum() == 0) return;
@ -84,7 +100,18 @@ public class ContainerRateExcelMapper {
rates.add(mapToEntity(row)); rates.add(mapToEntity(row));
}); });
return rates; validateReferenceRoute(rates);
return rates.stream().map(ExcelContainerRate::rate).toList();
}
private void validateReferenceRoute(List<ExcelContainerRate> rates) {
var startRef = getRefStart();
var endRef = getRefEnd();
if(rates.stream().noneMatch(rate -> rate.fromNode().getExternalMappingId().equals(startRef) || rate.toNode().getExternalMappingId().equals(endRef)))
throw new ExcelValidationError(String.format("Container rates must reference route (%s - %s) not found in container rates", startRef, endRef));
} }
private boolean isEmpty(Row row) { private boolean isEmpty(Row row) {
@ -109,7 +136,7 @@ public class ContainerRateExcelMapper {
return result.toString(); return result.toString();
} }
private ContainerRate mapToEntity(Row row) { private ExcelContainerRate mapToEntity(Row row) {
ContainerRate entity = new ContainerRate(); ContainerRate entity = new ContainerRate();
validateConstraints(row); validateConstraints(row);
@ -134,7 +161,7 @@ public class ContainerRateExcelMapper {
entity.setRateTeu(BigDecimal.valueOf(row.getCell(ContainerRateHeader.RATE_TEU.ordinal()).getNumericCellValue())); entity.setRateTeu(BigDecimal.valueOf(row.getCell(ContainerRateHeader.RATE_TEU.ordinal()).getNumericCellValue()));
entity.setRateHc(BigDecimal.valueOf(row.getCell(ContainerRateHeader.RATE_HC.ordinal()).getNumericCellValue())); entity.setRateHc(BigDecimal.valueOf(row.getCell(ContainerRateHeader.RATE_HC.ordinal()).getNumericCellValue()));
return entity; return new ExcelContainerRate(entity, fromNode.orElseThrow(), toNode.orElseThrow());
} }
private void validateConstraints(Row row) { private void validateConstraints(Row row) {
@ -142,10 +169,12 @@ public class ContainerRateExcelMapper {
constraintGenerator.validateStringCell(row, ContainerRateHeader.FROM_NODE.ordinal()); constraintGenerator.validateStringCell(row, ContainerRateHeader.FROM_NODE.ordinal());
constraintGenerator.validateStringCell(row, ContainerRateHeader.TO_NODE.ordinal()); constraintGenerator.validateStringCell(row, ContainerRateHeader.TO_NODE.ordinal());
constraintGenerator.validateEnumConstraint(row, ContainerRateHeader.CONTAINER_RATE_TYPE.ordinal(), TransportType.class); constraintGenerator.validateEnumConstraint(row, ContainerRateHeader.CONTAINER_RATE_TYPE.ordinal(), TransportType.class);
constraintGenerator.validateDecimalConstraint(row, ContainerRateHeader.RATE_FEU.ordinal(), 0.0, 1000000.0); constraintGenerator.validateDecimalConstraint(row, ContainerRateHeader.RATE_FEU.ordinal(), 1.0, 1000000.0);
constraintGenerator.validateDecimalConstraint(row, ContainerRateHeader.RATE_TEU.ordinal(), 0.0, 1000000.0); constraintGenerator.validateDecimalConstraint(row, ContainerRateHeader.RATE_TEU.ordinal(), 1.0, 1000000.0);
constraintGenerator.validateDecimalConstraint(row, ContainerRateHeader.RATE_HC.ordinal(), 0.0, 1000000.0); constraintGenerator.validateDecimalConstraint(row, ContainerRateHeader.RATE_HC.ordinal(), 1.0, 1000000.0);
constraintGenerator.validateIntegerConstraint(row, ContainerRateHeader.LEAD_TIME.ordinal(), 0, 365); constraintGenerator.validateIntegerConstraint(row, ContainerRateHeader.LEAD_TIME.ordinal(), 0, 365);
} }
private record ExcelContainerRate(ContainerRate rate, Node fromNode, Node toNode) {}
} }

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.service.excelMapper; package de.avatic.lcc.service.excelMapper;
import de.avatic.lcc.model.bulk.header.ContainerRateHeader;
import de.avatic.lcc.model.excel.ExcelNode; import de.avatic.lcc.model.excel.ExcelNode;
import de.avatic.lcc.model.bulk.BulkInstruction; import de.avatic.lcc.model.bulk.BulkInstruction;
import de.avatic.lcc.model.bulk.BulkInstructionType; import de.avatic.lcc.model.bulk.BulkInstructionType;
@ -150,6 +151,11 @@ public class NodeExcelMapper {
entity.setSource(Boolean.valueOf(row.getCell(NodeHeader.IS_SOURCE.ordinal()).getStringCellValue())); entity.setSource(Boolean.valueOf(row.getCell(NodeHeader.IS_SOURCE.ordinal()).getStringCellValue()));
entity.setIntermediate(Boolean.valueOf(row.getCell(NodeHeader.IS_INTERMEDIATE.ordinal()).getStringCellValue())); entity.setIntermediate(Boolean.valueOf(row.getCell(NodeHeader.IS_INTERMEDIATE.ordinal()).getStringCellValue()));
entity.setDestination(Boolean.valueOf(row.getCell(NodeHeader.IS_DESTINATION.ordinal()).getStringCellValue())); entity.setDestination(Boolean.valueOf(row.getCell(NodeHeader.IS_DESTINATION.ordinal()).getStringCellValue()));
if(!entity.getSource() && !entity.getDestination() && !entity.getIntermediate())
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(ContainerRateHeader.FROM_NODE.ordinal()) + ": Node with mapping id " + row.getCell(NodeHeader.MAPPING_ID.ordinal()).getStringCellValue() + " must be either source, destination or intermediate");
entity.setPredecessorRequired(Boolean.valueOf(row.getCell(NodeHeader.IS_PREDECESSOR_MANDATORY.ordinal()).getStringCellValue())); entity.setPredecessorRequired(Boolean.valueOf(row.getCell(NodeHeader.IS_PREDECESSOR_MANDATORY.ordinal()).getStringCellValue()));
entity.setNodePredecessors(mapChainsFromCell(CellUtil.getCell(row, NodeHeader.PREDECESSOR_NODES.ordinal()).getStringCellValue())); entity.setNodePredecessors(mapChainsFromCell(CellUtil.getCell(row, NodeHeader.PREDECESSOR_NODES.ordinal()).getStringCellValue()));
entity.setOutboundCountries(mapOutboundCountriesFromCell(CellUtil.getCell(row, NodeHeader.OUTBOUND_COUNTRIES.ordinal()).getStringCellValue())); entity.setOutboundCountries(mapOutboundCountriesFromCell(CellUtil.getCell(row, NodeHeader.OUTBOUND_COUNTRIES.ordinal()).getStringCellValue()));
@ -199,4 +205,14 @@ public class NodeExcelMapper {
return Arrays.stream(chain.split(",")).map(String::trim).toList(); return Arrays.stream(chain.split(",")).map(String::trim).toList();
} }
private String toExcelLetter(int columnIdx) {
StringBuilder result = new StringBuilder();
columnIdx++; // Convert from 0-based to 1-based for the algorithm
while (columnIdx > 0) {
columnIdx--; // Adjust for 1-based indexing
result.insert(0, (char) ('A' + columnIdx % 26));
columnIdx /= 26;
}
return result.toString();
}
} }

View file

@ -60,7 +60,7 @@ public class PackagingExcelMapper {
private void mapToRow(Packaging packaging, ArrayList<String> headers, Row row) { private void mapToRow(Packaging packaging, ArrayList<String> headers, Row row) {
Optional<PackagingDimension> shu = packagingDimensionRepository.getById(packaging.getShuId()); Optional<PackagingDimension> shu = packagingDimensionRepository.getById(packaging.getShuId());
Optional<PackagingDimension> hu = packagingDimensionRepository.getById(packaging.getShuId()); Optional<PackagingDimension> hu = packagingDimensionRepository.getById(packaging.getHuId());
row.createCell(PackagingHeader.OPERATION.ordinal()).setCellValue(BulkInstructionType.UPDATE.name()); row.createCell(PackagingHeader.OPERATION.ordinal()).setCellValue(BulkInstructionType.UPDATE.name());