Merge branch 'main' of git.avatic.de:avatic/lcc_tool

# Conflicts:
#	src/main/resources/master_data/01-properties.sql
This commit is contained in:
Anja Guenther 2025-09-22 21:16:11 +02:00
commit 3f5e3cb115
30 changed files with 653 additions and 133 deletions

View file

@ -2,8 +2,9 @@
<div class="property-container">
<div class="caption-column">
<div class="caption-column-id">{{ property.name }}:</div>
<div class="caption-column-name">Ext. Mapping: {{ property.external_mapping_id }}</div>
<div class="caption-column-id">{{ property.name }}: </div>
<div class="caption-column-name">{{ property.description }}</div>
<div class="caption-column-name"><basic-badge variant="grey">{{ property.external_mapping_id}}</basic-badge></div>
</div>
<div class="input-column">
@ -43,10 +44,11 @@ import Dropdown from "@/components/UI/Dropdown.vue";
import IconButton from "@/components/UI/IconButton.vue";
import Tooltip from "@/components/UI/Tooltip.vue";
import {parseNumberFromString} from "@/common.js";
import BasicBadge from "@/components/UI/BasicBadge.vue";
export default {
name: "Property",
components: {Tooltip, IconButton, Dropdown, ToggleSwitch, PhGear, InputField},
components: {BasicBadge, Tooltip, IconButton, Dropdown, ToggleSwitch, PhGear, InputField},
props: {
property: {
type: Object,
@ -199,6 +201,7 @@ export default {
align-items: center;
gap: 2.4rem;
height: 8rem;
margin: 3.6rem 0 ;
}
.caption-column {
@ -206,6 +209,7 @@ export default {
flex-direction: column;
font-weight: 300;
font-size: 1.4rem;
max-width: 60rem;
}
.caption-column-id {

View file

@ -186,7 +186,7 @@ export default {
created() {
this.bulkQuery = this.$route.params.ids;
this.ids = new UrlSafeBase64().decodeIds(this.$route.params.ids);
this.premiseEditStore.loadPremissesIfNeeded(this.ids, true);
this.premiseEditStore.loadPremissesForced(this.ids);
},
data() {
return {

View file

@ -225,6 +225,9 @@ public class ContainerCalculationResult {
* @return The volume utilization ratio of one HU to container volume.
*/
public double getHuUtilizationByVolume() {
if (containerType.getVolume() <= 0.0) {
return 0.0;
}
return hu.getVolume(DimensionUnit.M) / containerType.getVolume();
}
@ -245,7 +248,10 @@ public class ContainerCalculationResult {
* @return Weight utilization ratio of one HU to the container's maximum weight.
*/
public double getHuUtilizationByWeight() {
return WeightUnit.KG.convertFromG(hu.getWeight()).doubleValue() / maxContainerWeight;
if (maxContainerWeight == null || maxContainerWeight <= 0) {
return 0;
}
return WeightUnit.KG.convertFromG(hu.getWeight()) / maxContainerWeight;
}
}

View file

@ -61,11 +61,11 @@ public class NodeController {
return ResponseEntity.ok(nodeService.deleteNode(id));
}
// @PutMapping("/{id}")
// public ResponseEntity<Integer> updateNode(@PathVariable Integer id, @RequestBody NodeUpdateDTO node) {
// Check.equals(id, node.getId());
// return ResponseEntity.ok(nodeService.updateNode(node));
// }
@PutMapping("/{id}")
public ResponseEntity<Integer> updateNode(@PathVariable Integer id, @RequestBody NodeUpdateDTO node) {
Check.equals(id, node.getId());
return ResponseEntity.ok(nodeService.updateNode(node));
}
@GetMapping("/locate")
public ResponseEntity<LocateNodeDTO> locateNode(@RequestParam String address) {

View file

@ -24,6 +24,15 @@ public class PropertyDTO {
@JsonProperty("validation_rule")
private String validationRule;
@JsonProperty("description")
private String description;
@JsonProperty("property_group")
private String propertyGroup;
@JsonProperty("sequence_number")
private Integer sequenceNumber;
public String getName() {
return name;
}
@ -79,4 +88,28 @@ public class PropertyDTO {
public String getValidationRule() {
return validationRule;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPropertyGroup() {
return propertyGroup;
}
public void setPropertyGroup(String propertyGroup) {
this.propertyGroup = propertyGroup;
}
public Integer getSequenceNumber() {
return sequenceNumber;
}
public void setSequenceNumber(Integer sequenceNumber) {
this.sequenceNumber = sequenceNumber;
}
}

View file

@ -3,6 +3,8 @@ package de.avatic.lcc.excelmodel;
import de.avatic.lcc.model.utils.DimensionUnit;
import de.avatic.lcc.model.utils.WeightUnit;
import java.util.Map;
public class ExcelPackaging {
private Integer id;
@ -19,6 +21,8 @@ public class ExcelPackaging {
private DimensionUnit shuDimensionUnit;
private WeightUnit shuWeightUnit;
private Integer shuUnitCount;
private Double huLength;
private Double huWidth;
private Double huHeight;
@ -27,6 +31,9 @@ public class ExcelPackaging {
private DimensionUnit huDimensionUnit;
private WeightUnit huWeightUnit;
private Integer huUnitCount;
private Map<String, String> properties;
public Integer getId() {
return id;
}
@ -146,4 +153,29 @@ public class ExcelPackaging {
public void setHuWeightUnit(WeightUnit huWeightUnit) {
this.huWeightUnit = huWeightUnit;
}
public Integer getShuUnitCount() {
return shuUnitCount;
}
public void setShuUnitCount(Integer shuUnitCount) {
this.shuUnitCount = shuUnitCount;
}
public Integer getHuUnitCount() {
return huUnitCount;
}
public void setHuUnitCount(Integer huUnitCount) {
this.huUnitCount = huUnitCount;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public Map<String, String> getProperties() {
return properties;
}
}

View file

@ -42,7 +42,8 @@ public enum SystemPropertyMappingId {
KLT_HANDLING("GR handling KLT [EUR/HU]", "0,71 €"),
GLT_HANDLING("GR handling GLT [EUR/HU]", "3,50 €"),
BOOKING("GLT/KLT booking & document handling [EUR/GR]", "3,50 €"),
BOOKING("GLT booking & document handling [EUR/GR]", "3,50 €"),
BOOKING_KLT("KLT booking & document handling [EUR/GR]", "0,35 €"),
GLT_RELEASE("GLT release from storage [EUR/GLT release]", "2,23 €"),
KLT_RELEASE("KLT release from storage [EUR/KLT release]", "1,12 €"),
GLT_DISPATCH("GLT dispatch [EUR/GLT dispatch]", "1,61 €"),

View file

@ -79,6 +79,23 @@ public class MaterialRepository {
return jdbcTemplate.query(query, new MaterialMapper(), params.toArray());
}
public Optional<Material> getByPartNumber(String partNumber) {
if (partNumber == null) {
return Optional.empty();
}
String query = "SELECT * FROM material WHERE part_number = ? OR normalized_part_number = ?";
var material = jdbcTemplate.query(query, new MaterialMapper(), partNumber, partNumber);
if(material.isEmpty())
return Optional.empty();
return Optional.ofNullable(material.getFirst());
}
@Transactional
public Optional<Integer> setDeprecatedById(Integer id) {
String query = "UPDATE material SET is_deprecated = TRUE WHERE id = ?";
@ -190,6 +207,8 @@ public class MaterialRepository {
.collect(Collectors.toList());
}
private static class MaterialMapper implements RowMapper<Material> {
@Override

View file

@ -65,8 +65,12 @@ public class CountryPropertyRepository {
type.external_mapping_id as externalMappingId,
type.validation_rule as validationRule,
type.is_required as is_required,
type.description as description,
type.property_group as propertyGroup,
type.sequence_number as sequenceNumber,
draft.property_value as draftValue,
valid.property_value as validValue
FROM country_property_type AS type
LEFT JOIN (
SELECT cp.property_value, cp.country_property_type_id
@ -104,6 +108,10 @@ public class CountryPropertyRepository {
type.external_mapping_id as externalMappingId,
type.validation_rule as validationRule,
type.is_required as is_required,
type.is_required as is_required,
type.description as description,
type.property_group as propertyGroup,
type.sequence_number as sequenceNumber,
MAX(CASE WHEN ps.state = 'DRAFT' THEN cp.property_value END) as draftValue,
MAX(CASE WHEN ps.state = 'VALID' THEN cp.property_value END) as validValue
FROM country_property_type AS type
@ -121,6 +129,9 @@ public class CountryPropertyRepository {
String query = """
SELECT type.name as name, type.data_type as dataType, type.external_mapping_id as externalMappingId, type.validation_rule as validationRule, type.is_required as is_required,
type.description as description,
type.property_group as propertyGroup,
type.sequence_number as sequenceNumber,
property.property_value as draftValue, property.property_value as validValue
FROM country_property_type AS type
LEFT JOIN country_property AS property ON property.country_property_type_id = type.id
@ -161,6 +172,10 @@ public class CountryPropertyRepository {
dto.setRequired(rs.getBoolean("is_required"));
dto.setDataType(rs.getString("dataType"));
dto.setDescription(rs.getString("description"));
dto.setPropertyGroup(rs.getString("propertyGroup"));
dto.setSequenceNumber(rs.getInt("sequenceNumber"));
return dto;
}
}

View file

@ -101,4 +101,19 @@ public class PackagingPropertiesRepository {
jdbcTemplate.update(query, value, packagingId, typeId, value);
}
public Integer getTypeIdByMappingId(String mappingId) {
String query = "SELECT id FROM packaging_property_type WHERE external_mapping_id = ?";
return jdbcTemplate.queryForObject(query, Integer.class, mappingId);
}
public void update(Integer packagingId, String typeId, String value) {
String query = """
INSERT INTO packaging_property (property_value, packaging_id, packaging_property_type_id) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE property_value = ?""";
jdbcTemplate.update(query, value, packagingId, typeId, value);
}
}

View file

@ -92,13 +92,14 @@ public class PropertyRepository {
String query = """
SELECT type.name as name, type.data_type as dataType, type.external_mapping_id as externalMappingId, type.validation_rule as validationRule,
type.description as description, type.property_group as propertyGroup, type.sequence_number as sequenceNumber,
MAX(CASE WHEN ps.state = ? THEN sp.property_value END) as draftValue,
MAX(CASE WHEN ps.state = ? THEN sp.property_value END) as validValue
FROM system_property_type AS type
LEFT JOIN system_property AS sp ON sp.system_property_type_id = type.id
LEFT JOIN property_set AS ps ON ps.id = sp.property_set_id AND ps.state IN (?, ?)
GROUP BY type.id, type.name, type.data_type, type.external_mapping_id, type.validation_rule
HAVING draftValue IS NOT NULL OR validValue IS NOT NULL ORDER BY type.name;
GROUP BY type.id, type.name, type.data_type, type.external_mapping_id, type.validation_rule, type.description, type.property_group, type.sequence_number
HAVING draftValue IS NOT NULL OR validValue IS NOT NULL ORDER BY type.property_group , type.sequence_number;
""";
return jdbcTemplate.query(query, new PropertyMapper(), ValidityPeriodState.DRAFT.name(), ValidityPeriodState.VALID.name(), ValidityPeriodState.DRAFT.name(), ValidityPeriodState.VALID.name());
@ -115,11 +116,12 @@ public class PropertyRepository {
String query = """
SELECT type.name as name, type.data_type as dataType, type.external_mapping_id as externalMappingId, type.validation_rule as validationRule,
type.description as description, type.property_group as propertyGroup, type.sequence_number as sequenceNumber,
NULL as draftValue, property.property_value as validValue
FROM system_property_type AS type
LEFT JOIN system_property AS property ON property.system_property_type_id = type.id
LEFT JOIN property_set AS propertySet ON propertySet.id = property.property_set_id
WHERE propertySet.id = ? AND (propertySet.state = ? OR propertySet.state = ?) ORDER BY type.name;
WHERE propertySet.id = ? AND (propertySet.state = ? OR propertySet.state = ?) ORDER BY type.property_group , type.sequence_number;
""";
return jdbcTemplate.query(query, new PropertyMapper(), propertySetId, ValidityPeriodState.EXPIRED.name(), ValidityPeriodState.INVALID.name());
@ -129,6 +131,7 @@ public class PropertyRepository {
public Optional<PropertyDTO> getPropertyByMappingId(SystemPropertyMappingId mappingId) {
String query = """
SELECT type.name as name, type.data_type as dataType, type.external_mapping_id as externalMappingId, type.validation_rule as validationRule,
type.description as description, type.property_group as propertyGroup, type.sequence_number as sequenceNumber,
property.property_value as draftValue, property.property_value as validValue
FROM system_property_type AS type
LEFT JOIN system_property AS property ON property.system_property_type_id = type.id
@ -190,6 +193,10 @@ public class PropertyRepository {
dto.setRequired(true);
dto.setDataType(rs.getString("dataType"));
dto.setDescription(rs.getString("description"));
dto.setPropertyGroup(rs.getString("propertyGroup"));
dto.setSequenceNumber(rs.getInt("sequenceNumber"));
return dto;
}
}

View file

@ -107,8 +107,7 @@ public class NodeService {
* @param includeUserNode if true, includes user-specific nodes in the search results.
* @return a list of {@link NodeDTO} objects representing the search results.
*/
public List<NodeDTO> searchNode(String filter, int limit, NodeType nodeType, boolean includeUserNode) {
List<NodeDTO> nodes = new ArrayList<>();
public List<NodeDTO> searchNode(String filter, int limit, NodeType nodeType, boolean includeUserNode) { List<NodeDTO> nodes = new ArrayList<>();
int userId = 1; //TODO get current user's id
if( includeUserNode && NodeType.SOURCE.equals(nodeType)) {

View file

@ -13,6 +13,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
/**
* Service for managing properties and property sets within the application.
@ -117,4 +118,40 @@ public class PropertyService {
}
@SuppressWarnings("unchecked")
public <T> Optional<T> getProperty(SystemPropertyMappingId mappingId) {
var prop = propertyRepository.getPropertyByMappingId(mappingId);
if (prop.isEmpty())
return Optional.empty();
var property = prop.get();
var propValue = property.getCurrentValue();
var dataType = property.getDataType();
if (propValue == null)
return Optional.empty();
try {
Object convertedValue = convertStringByDataType(propValue, dataType);
return Optional.of((T) convertedValue);
} catch (ClassCastException e) {
// The caller expected a different type than what the dataType indicates
return Optional.empty();
} catch (Exception e) {
// Parsing error
return Optional.empty();
}
}
private Object convertStringByDataType(String value, String dataType) {
return switch (dataType.toUpperCase()) {
case "TEXT", "ENUMERATION" -> value;
case "CURRENCY", "PERCENTAGE" -> Double.valueOf(value);
case "BOOLEAN" -> Boolean.valueOf(value);
case "INT" -> Integer.valueOf(value);
default -> throw new IllegalArgumentException("Unsupported data type: " + dataType);
};
}
}

View file

@ -4,9 +4,11 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.avatic.lcc.model.properties.CountryPropertyMappingId;
import de.avatic.lcc.model.properties.PackagingPropertyMappingId;
import de.avatic.lcc.model.properties.PropertyDataType;
import de.avatic.lcc.model.properties.SystemPropertyMappingId;
import de.avatic.lcc.repositories.country.CountryPropertyRepository;
import de.avatic.lcc.repositories.packaging.PackagingPropertiesRepository;
import de.avatic.lcc.repositories.properties.PropertyRepository;
import de.avatic.lcc.util.exception.badrequest.PropertyValidationException;
import de.avatic.lcc.util.exception.base.InternalErrorException;
@ -23,11 +25,13 @@ public class PropertyValidationService {
private final CountryPropertyRepository countryPropertyRepository;
private final PropertyRepository propertyRepository;
private final PackagingPropertiesRepository packagingPropertiesRepository;
public PropertyValidationService(ObjectMapper objectMapper, CountryPropertyRepository countryPropertyRepository, PropertyRepository propertyRepository) {
public PropertyValidationService(ObjectMapper objectMapper, CountryPropertyRepository countryPropertyRepository, PropertyRepository propertyRepository, PackagingPropertiesRepository packagingPropertiesRepository) {
this.objectMapper = objectMapper;
this.countryPropertyRepository = countryPropertyRepository;
this.propertyRepository = propertyRepository;
this.packagingPropertiesRepository = packagingPropertiesRepository;
}
public void validateProperty(SystemPropertyMappingId mappingId, String value) {
@ -36,6 +40,13 @@ public class PropertyValidationService {
validate(mappingId.name(), PropertyDataType.valueOf(property.orElseThrow().getDataType()), property.orElseThrow().getValidationRule(), value);
}
public void validatePackagingProperty(Integer packagingId, PackagingPropertyMappingId mappingId, String value) {
var property = packagingPropertiesRepository.getByPackagingIdAndType(packagingId, mappingId.name());
validate(mappingId.name(), property.orElseThrow().getType().getDataType(), property.orElseThrow().getType().getValidationRule(), value);
}
public void validateCountryProperty(Integer countryId, CountryPropertyMappingId mappingId, String value) {
var property = countryPropertyRepository.getByMappingIdAndCountryId(mappingId, countryId);

View file

@ -5,7 +5,10 @@ import de.avatic.lcc.model.bulk.BulkFileTypes;
import de.avatic.lcc.model.bulk.BulkInstruction;
import de.avatic.lcc.model.bulk.BulkInstructionType;
import de.avatic.lcc.model.bulk.BulkOperation;
import de.avatic.lcc.model.nodes.Node;
import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.service.bulk.bulkImport.NodeBulkImportService;
import de.avatic.lcc.service.bulk.bulkImport.PackagingBulkImportService;
import de.avatic.lcc.service.excelMapper.*;
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
@ -17,6 +20,7 @@ import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
@Service
public class BulkImportService {
@ -28,8 +32,10 @@ public class BulkImportService {
private final NodeExcelMapper nodeExcelMapper;
private final NodeRepository nodeRepository;
private final NodeTransformer nodeTransformer;
private final NodeBulkImportService nodeBulkImportService;
private final PackagingBulkImportService packagingBulkImportService;
public BulkImportService(MatrixRateExcelMapper matrixRateExcelMapper, ContainerRateExcelMapper containerRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, NodeRepository nodeRepository, NodeTransformer nodeTransformer) {
public BulkImportService(MatrixRateExcelMapper matrixRateExcelMapper, ContainerRateExcelMapper containerRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, NodeRepository nodeRepository, NodeTransformer nodeTransformer, NodeBulkImportService nodeBulkImportService, PackagingBulkImportService packagingBulkImportService) {
this.matrixRateExcelMapper = matrixRateExcelMapper;
this.containerRateExcelMapper = containerRateExcelMapper;
this.materialExcelMapper = materialExcelMapper;
@ -37,6 +43,8 @@ public class BulkImportService {
this.nodeExcelMapper = nodeExcelMapper;
this.nodeRepository = nodeRepository;
this.nodeTransformer = nodeTransformer;
this.nodeBulkImportService = nodeBulkImportService;
this.packagingBulkImportService = packagingBulkImportService;
}
public void processOperation(BulkOperation op) throws IOException {
@ -63,10 +71,11 @@ public class BulkImportService {
break;
case PACKAGING:
var packaging = packagingExcelMapper.extractSheet(sheet);
packaging.forEach(packagingBulkImportService::processPackagingInstructions);
break;
case NODE:
var nodeInstructions = nodeExcelMapper.extractSheet(sheet);
nodeInstructions.forEach(this::processNodeInstructions);
nodeInstructions.forEach(nodeBulkImportService::processNodeInstructions);
break;
default:
@ -75,31 +84,5 @@ public class BulkImportService {
}
private void processNodeInstructions(BulkInstruction<ExcelNode> instr) {
BulkInstructionType instrType = instr.getType();
ExcelNode excelNode = instr.getEntity();
if (instrType == BulkInstructionType.UPDATE) {
updateNode(excelNode);
} else if (instrType == BulkInstructionType.DELETE) {
deleteNode(excelNode);
}
}
private void deleteNode(ExcelNode excelNode) {
nodeRepository.setDeprecatedById(excelNode.getId());
}
private void updateNode(ExcelNode excelNode) {
var node = nodeRepository.getByExternalMappingId(excelNode.getExternalMappingId());
if(node.isEmpty()) {
nodeRepository.insert(nodeTransformer.toNodeEntity(excelNode));
} else {
nodeRepository.update(nodeTransformer.toNodeEntity(excelNode));
}
}
}

View file

@ -0,0 +1,120 @@
package de.avatic.lcc.service.bulk.bulkImport;
import de.avatic.lcc.excelmodel.ExcelNode;
import de.avatic.lcc.model.bulk.BulkInstruction;
import de.avatic.lcc.model.bulk.BulkInstructionType;
import de.avatic.lcc.model.nodes.Node;
import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class NodeBulkImportService {
private final NodeRepository nodeRepository;
private final NodeTransformer nodeTransformer;
public NodeBulkImportService(NodeRepository nodeRepository, NodeTransformer nodeTransformer) {
this.nodeRepository = nodeRepository;
this.nodeTransformer = nodeTransformer;
}
public void processNodeInstructions(BulkInstruction<ExcelNode> instr) {
BulkInstructionType instrType = instr.getType();
ExcelNode excelNode = instr.getEntity();
if (instrType == BulkInstructionType.UPDATE) {
updateNode(excelNode);
} else if (instrType == BulkInstructionType.DELETE) {
deleteNode(excelNode);
}
}
private void deleteNode(ExcelNode excelNode) {
var node = nodeRepository.getByExternalMappingId(excelNode.getExternalMappingId());
if (node.isEmpty()) {
throw new ExcelValidationError("Node with external mapping id " + excelNode.getExternalMappingId() + " not found");
} else {
nodeRepository.setDeprecatedById(node.get().getId());
}
}
private void updateNode(ExcelNode excelNode) {
var node = nodeRepository.getByExternalMappingId(excelNode.getExternalMappingId());
if (node.isEmpty()) {
nodeRepository.insert(nodeTransformer.toNodeEntity(excelNode));
} else {
var convertedNode = nodeTransformer.toNodeEntity(excelNode);
convertedNode.setId(node.get().getId());
if (!compare(convertedNode, node.get())) {
nodeRepository.update(convertedNode);
}
}
}
private boolean compare(Node updateNode, Node currentNode) {
return updateNode.getName().equals(currentNode.getName()) &&
updateNode.getGeoLat().compareTo(currentNode.getGeoLat()) == 0 &&
updateNode.getGeoLng().compareTo(currentNode.getGeoLng()) == 0 &&
updateNode.getExternalMappingId().equals(currentNode.getExternalMappingId()) &&
updateNode.getCountryId().equals(currentNode.getCountryId()) &&
updateNode.getIntermediate().equals(currentNode.getIntermediate()) &&
updateNode.getDestination().equals(currentNode.getDestination()) &&
updateNode.getSource().equals(currentNode.getSource()) &&
updateNode.getAddress().equals(currentNode.getAddress()) &&
updateNode.getDeprecated().equals(currentNode.getDeprecated()) &&
updateNode.getId().equals(currentNode.getId()) &&
updateNode.getPredecessorRequired().equals(currentNode.getPredecessorRequired()) &&
compare(updateNode.getNodePredecessors(), currentNode.getNodePredecessors()) &&
compare(updateNode.getOutboundCountries(), currentNode.getOutboundCountries());
}
private boolean compare(Collection<Integer> outbound1, Collection<Integer> outbound2) {
if (outbound1 == null && outbound2 == null) {
return true;
}
if (outbound1 == null || outbound2 == null) {
return false;
}
if (outbound1.size() != outbound2.size()) {
return false;
}
var set1 = new HashSet<>(outbound1);
var set2 = new HashSet<>(outbound2);
return set1.equals(set2);
}
private boolean compare(List<Map<Integer, Integer>> chain1, List<Map<Integer, Integer>> chain2) {
if (chain1 == null && chain2 == null) {
return true;
}
if (chain1 == null || chain2 == null) {
return false;
}
if (chain1.size() != chain2.size()) {
return false;
}
Set<Map<Integer, Integer>> set1 = new HashSet<>(chain1);
Set<Map<Integer, Integer>> set2 = new HashSet<>(chain2);
return set1.equals(set2);
}
}

View file

@ -0,0 +1,124 @@
package de.avatic.lcc.service.bulk.bulkImport;
import de.avatic.lcc.excelmodel.ExcelPackaging;
import de.avatic.lcc.model.bulk.BulkInstruction;
import de.avatic.lcc.model.bulk.BulkInstructionType;
import de.avatic.lcc.model.packaging.Packaging;
import de.avatic.lcc.model.packaging.PackagingType;
import de.avatic.lcc.model.properties.PackagingPropertyMappingId;
import de.avatic.lcc.repositories.MaterialRepository;
import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository;
import de.avatic.lcc.repositories.packaging.PackagingPropertiesRepository;
import de.avatic.lcc.repositories.packaging.PackagingRepository;
import de.avatic.lcc.service.access.PropertyValidationService;
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.springframework.stereotype.Service;
@Service
public class PackagingBulkImportService {
private final PackagingRepository packagingRepository;
private final MaterialRepository materialRepository;
private final NodeRepository nodeRepository;
private final PackagingDimensionRepository packagingDimensionRepository;
private final DimensionTransformer dimensionTransformer;
private final PackagingPropertiesRepository packagingPropertiesRepository;
private final PropertyValidationService propertyValidationService;
public PackagingBulkImportService(PackagingRepository packagingRepository, MaterialRepository materialRepository, NodeRepository nodeRepository, PackagingDimensionRepository packagingDimensionRepository, DimensionTransformer dimensionTransformer, PackagingPropertiesRepository packagingPropertiesRepository, PropertyValidationService propertyValidationService) {
this.packagingRepository = packagingRepository;
this.materialRepository = materialRepository;
this.nodeRepository = nodeRepository;
this.packagingDimensionRepository = packagingDimensionRepository;
this.dimensionTransformer = dimensionTransformer;
this.packagingPropertiesRepository = packagingPropertiesRepository;
this.propertyValidationService = propertyValidationService;
}
public void processPackagingInstructions(BulkInstruction<ExcelPackaging> instr) {
BulkInstructionType instrType = instr.getType();
ExcelPackaging excelPackaging = instr.getEntity();
if (instrType == BulkInstructionType.UPDATE) {
updatePackaging(excelPackaging);
} else if (instrType == BulkInstructionType.DELETE) {
deletePackaging(excelPackaging);
}
}
private void deletePackaging(ExcelPackaging excelPackaging) {
var material = materialRepository.getByPartNumber(excelPackaging.getPartNumber());
var supplier = nodeRepository.getByExternalMappingId(excelPackaging.getSupplierMappingId());
if (material.isEmpty() || supplier.isEmpty()) {
throw new ExcelValidationError("Packaging references non existing supplier \"" + excelPackaging.getSupplierMappingId() + "\" and/or material \"" + excelPackaging.getPartNumber() + "\"");
} else {
packagingRepository.getByMaterialIdAndSupplierId(material.get().getId(), supplier.get().getId()).ifPresent(packaging -> packagingRepository.setDeprecatedById(packaging.getId()));
}
}
private void updatePackaging(ExcelPackaging excelPackaging) {
var material = materialRepository.getByPartNumber(excelPackaging.getPartNumber());
var supplier = nodeRepository.getByExternalMappingId(excelPackaging.getSupplierMappingId());
if (material.isEmpty() || supplier.isEmpty()) {
throw new ExcelValidationError("Packaging references non existing supplier \"" + excelPackaging.getSupplierMappingId() + "\" and/or material \"" + excelPackaging.getPartNumber() + "\"");
} else {
var excelHu = dimensionTransformer.toDimensionEntity(excelPackaging, PackagingType.HU);
var excelShu = dimensionTransformer.toDimensionEntity(excelPackaging, PackagingType.SHU);
var packaging = packagingRepository.getByMaterialIdAndSupplierId(material.get().getId(), supplier.get().getId());
if (packaging.isEmpty()) {
var huId = packagingDimensionRepository.insert(excelHu).orElseThrow();
var shuId = packagingDimensionRepository.insert(excelShu).orElseThrow();
var convertedPackaging = new Packaging();
convertedPackaging.setMaterialId(material.get().getId());
convertedPackaging.setSupplierId(supplier.get().getId());
convertedPackaging.setDeprecated(false);
convertedPackaging.setHuId(huId);
convertedPackaging.setShuId(shuId);
packagingRepository.insert(convertedPackaging);
} else {
var hu = packaging.flatMap(o -> packagingDimensionRepository.getById(o.getHuId()));
var shu = packaging.flatMap(o -> packagingDimensionRepository.getById(o.getShuId()));
excelHu.setId(hu.isEmpty() ? packagingDimensionRepository.insert(excelHu).orElseThrow() : hu.get().getId());
excelShu.setId(shu.isEmpty() ? packagingDimensionRepository.insert(excelShu).orElseThrow() : shu.get().getId());
var convertedPackaging = new Packaging();
convertedPackaging.setMaterialId(material.get().getId());
convertedPackaging.setSupplierId(supplier.get().getId());
convertedPackaging.setDeprecated(false);
convertedPackaging.setHuId(excelHu.getId());
convertedPackaging.setShuId(excelShu.getId());
convertedPackaging.setId(packaging.get().getId());
if (hu.isPresent())
packagingDimensionRepository.update(excelHu);
if (shu.isPresent())
packagingDimensionRepository.update(excelShu);
for (var mappingId : excelPackaging.getProperties().keySet()) {
var id = packagingPropertiesRepository.getTypeIdByMappingId(mappingId);
propertyValidationService.validatePackagingProperty(id, PackagingPropertyMappingId.valueOf(mappingId), excelPackaging.getProperties().get(mappingId));
packagingPropertiesRepository.update(convertedPackaging.getId(), id, excelPackaging.getProperties().get(mappingId));
}
packagingRepository.update(convertedPackaging);
}
}
}
}

View file

@ -193,6 +193,22 @@ public class ConstraintGenerator {
}
public void validateIntegerCell(Row row, int columnIdx) {
CellType cellType = row.getCell(columnIdx).getCellType();
if (cellType == CellType.NUMERIC) {
double value = row.getCell(columnIdx).getNumericCellValue();
if(value % 1 == 0) {
return;
}
}
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected integer value");
}
public void validateStringCell(Row row, int columnIdx) {
CellType cellType = row.getCell(columnIdx).getCellType();
@ -202,7 +218,7 @@ public class ConstraintGenerator {
return;
}
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected numeric value");
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected string value");
}

View file

@ -99,9 +99,14 @@ public class PremiseSearchStringAnalyzerService {
while (matcher.find()) {
// Get the match from group 1 (inside the lookahead)
String partNumber = matcher.group(1);
partNumbers.add(partNumber);
partNumbers.add(normalizePartNumber(partNumber));
}
return partNumbers;
}
private static String normalizePartNumber(String partNumber) {
if (partNumber.length() > 12) throw new IllegalArgumentException("Part number must be less than 12 characters");
return "000000000000".concat(partNumber).substring(partNumber.length());
}
}

View file

@ -48,19 +48,6 @@ public class CustomCostCalculationService {
}
}
public CustomResult doD2dCalculation(Premise premise, Destination destination, List<SectionInfo> sections) {
var destUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, destination.getCountryId()).orElseThrow();
var sourceUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, premise.getCountryId()).orElseThrow();
if (!CustomUnionType.EU.name().equals(destUnion.getCurrentValue()) || !CustomUnionType.NONE.name().equals(sourceUnion.getCurrentValue()))
return CustomResult.EMPTY;
double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(sections.getFirst().containerResult().getHuUnitCount()),2, RoundingMode.HALF_UP).doubleValue();
return getCustomCalculationResult(premise, destination, getContainerShare(premise, sections.getFirst().containerResult()), huAnnualAmount, sections.getFirst().result().getAnnualCost(), sections.getFirst().result().getAnnualChanceCost(), sections.getFirst().result().getAnnualRiskCost());
}
public CustomResult doCalculation(Premise premise, Destination destination, List<SectionInfo> sections) {
var destUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, destination.getCountryId()).orElseThrow();

View file

@ -57,7 +57,7 @@ public class HandlingCostCalculationService {
BigDecimal disposal = destinationDisposal != null ? destinationDisposal : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.DISPOSAL).orElseThrow().getCurrentValue()));
BigDecimal wageFactor = BigDecimal.valueOf(Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.WAGE, destination.getCountryId()).orElseThrow().getCurrentValue()));
BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING).orElseThrow().getCurrentValue()));
BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING_KLT).orElseThrow().getCurrentValue()));
return new HandlingResult(LoadCarrierType.SLC,
getRepackingCost(hu, loadCarrierType, addRepackingCosts, destinationRepacking).multiply(huAnnualAmount),

View file

@ -20,11 +20,9 @@ import de.avatic.lcc.service.bulk.helper.HeaderGenerator;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class PackagingExcelMapper {
@ -132,19 +130,32 @@ public class PackagingExcelMapper {
}
public List<ExcelPackaging> extractSheet(Sheet sheet) {
public List<BulkInstruction<ExcelPackaging>> extractSheet(Sheet sheet) {
headerGenerator.validateHeader(sheet, PackagingHeader.class);
Map<Integer, String> propertyMappingIds = getPropertyHeaders(sheet.getRow(0));
var packaging = new ArrayList<ExcelPackaging>();
var packaging = new ArrayList<BulkInstruction<ExcelPackaging>>();
sheet.forEach(row -> {
if(row.getRowNum() == 0) return;
packaging.add(mapToEntity(row));
packaging.add(mapToEntity(row, propertyMappingIds));
});
return packaging;
}
private Map<Integer, String> getPropertyHeaders(Row row) {
var propertyMappingIds = packagingPropertiesRepository.listTypes().stream().map(PropertyType::getExternalMappingId).toList();
private ExcelPackaging mapToEntity(Row row) {
var headers = new HashMap<Integer, String>();
for (int i = 0; i < row.getLastCellNum(); i++) {
if (propertyMappingIds.contains(row.getCell(i).getStringCellValue())) {
headers.put(i, row.getCell(i).getStringCellValue());
}
}
return headers;
}
private BulkInstruction<ExcelPackaging> mapToEntity(Row row, Map<Integer, String> propertyMappingIds) {
ExcelPackaging entity = new ExcelPackaging();
validateConstraints(row);
@ -168,7 +179,12 @@ public class PackagingExcelMapper {
entity.setShuDimensionUnit(DimensionUnit.valueOf(row.getCell(PackagingHeader.SHU_DIMENSION_UNIT.ordinal()).getStringCellValue()));
entity.setShuWeightUnit(WeightUnit.valueOf(row.getCell(PackagingHeader.SHU_WEIGHT_UNIT.ordinal()).getStringCellValue()));
return entity;
entity.setHuUnitCount(Double.valueOf(row.getCell(PackagingHeader.HU_UNIT_COUNT.ordinal()).getNumericCellValue()).intValue());
entity.setShuUnitCount(Double.valueOf(row.getCell(PackagingHeader.SHU_UNIT_COUNT.ordinal()).getNumericCellValue()).intValue());
entity.setProperties(propertyMappingIds.keySet().stream().collect(Collectors.toMap(propertyMappingIds::get, idx -> row.getCell(idx).getStringCellValue())));
return new BulkInstruction<>(entity, BulkInstructionType.valueOf(row.getCell(PackagingHeader.OPERATION.ordinal()).getStringCellValue()));
}
@ -186,6 +202,9 @@ public class PackagingExcelMapper {
constraintGenerator.validateNumericCell(row, PackagingHeader.SHU_LENGTH.ordinal());
constraintGenerator.validateNumericCell(row, PackagingHeader.SHU_WEIGHT.ordinal());
constraintGenerator.validateIntegerCell(row, PackagingHeader.HU_UNIT_COUNT.ordinal());
constraintGenerator.validateIntegerCell(row, PackagingHeader.SHU_UNIT_COUNT.ordinal());
constraintGenerator.validateLengthConstraint(row, PackagingHeader.PART_NUMBER.ordinal(), 0, 12);
constraintGenerator.validateEnumConstraint(row, PackagingHeader.SHU_DIMENSION_UNIT.ordinal(), DimensionUnit.class);
constraintGenerator.validateEnumConstraint(row, PackagingHeader.SHU_WEIGHT_UNIT.ordinal(), WeightUnit.class);

View file

@ -1,34 +1,49 @@
package de.avatic.lcc.service.precalculation;
import de.avatic.lcc.dto.generic.ContainerType;
import de.avatic.lcc.model.nodes.Node;
import de.avatic.lcc.model.premises.Premise;
import de.avatic.lcc.model.premises.route.Destination;
import de.avatic.lcc.model.premises.route.Route;
import de.avatic.lcc.model.properties.SystemPropertyMappingId;
import de.avatic.lcc.model.utils.WeightUnit;
import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.premise.DestinationRepository;
import de.avatic.lcc.repositories.premise.PremiseRepository;
import de.avatic.lcc.repositories.premise.RouteRepository;
import de.avatic.lcc.repositories.properties.PropertyRepository;
import de.avatic.lcc.service.CustomApiService;
import de.avatic.lcc.service.access.PropertyService;
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
import de.avatic.lcc.util.exception.internalerror.PremiseValidationError;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Optional;
@Service
public class PreCalculationCheckService {
private static final double DIMENSION_TOLERANCE = 0.02;
private final PremiseRepository premiseRepository;
private final CustomApiService customApiService;
private final DestinationRepository destinationRepository;
private final RouteRepository routeRepository;
private final NodeRepository nodeRepository;
private final DimensionTransformer dimensionTransformer;
private final PropertyRepository propertyRepository;
private final PropertyService propertyService;
public PreCalculationCheckService(PremiseRepository premiseRepository, CustomApiService customApiService, DestinationRepository destinationRepository, RouteRepository routeRepository, NodeRepository nodeRepository) {
public PreCalculationCheckService(PremiseRepository premiseRepository, CustomApiService customApiService, DestinationRepository destinationRepository, RouteRepository routeRepository, NodeRepository nodeRepository, DimensionTransformer dimensionTransformer, PropertyRepository propertyRepository, PropertyService propertyService) {
this.premiseRepository = premiseRepository;
this.customApiService = customApiService;
this.destinationRepository = destinationRepository;
this.routeRepository = routeRepository;
this.nodeRepository = nodeRepository;
this.dimensionTransformer = dimensionTransformer;
this.propertyRepository = propertyRepository;
this.propertyService = propertyService;
}
public void doPrecheck(Integer premiseId) {
@ -45,12 +60,12 @@ public class PreCalculationCheckService {
var destinations = destinationRepository.getByPremiseId(premiseId);
if(destinations == null || destinations.isEmpty()) {
if (destinations == null || destinations.isEmpty()) {
throw new PremiseValidationError("No destination for calculation. At least one destination is required.");
}
for (Destination destination : destinations ) {
for (Destination destination : destinations) {
var node = nodeRepository.getByDestinationId(destination.getId()).orElseThrow();
@ -59,18 +74,17 @@ public class PreCalculationCheckService {
var routes = routeRepository.getByDestinationId(destination.getId());
if(routes.isEmpty() && destination.getD2d() == false)
if (routes.isEmpty() && destination.getD2d() == false)
throw new PremiseValidationError("No route found for destination " + node.getName() + ". Cannot use standard routing.");
if(routes.stream().noneMatch(Route::getSelected) && destination.getD2d() == false)
if (routes.stream().noneMatch(Route::getSelected) && destination.getD2d() == false)
throw new PremiseValidationError("No route selected for destination " + node.getName());
if(destination.getD2d() && (destination.getRateD2d() == null || destination.getRateD2d().compareTo(BigDecimal.ZERO) == 0)) {
if (destination.getD2d() && (destination.getRateD2d() == null || destination.getRateD2d().compareTo(BigDecimal.ZERO) == 0)) {
throw new PremiseValidationError("Door-2-door rate not set or set to zero.");
}
if(destination.getD2d() && (destination.getLeadTimeD2d() == null || destination.getLeadTimeD2d() == 0)) {
if (destination.getD2d() && (destination.getLeadTimeD2d() == null || destination.getLeadTimeD2d() == 0)) {
throw new PremiseValidationError("Door-2-door rate not set or set to zero.");
}
@ -84,7 +98,7 @@ public class PreCalculationCheckService {
throw new PremiseValidationError("In destination " + node.getName() + ": annual quantity must be greater than zero.");
if (destination.getD2d() == null)
throw new PremiseValidationError("In destination " + node.getName() +": D2D not set.");
throw new PremiseValidationError("In destination " + node.getName() + ": D2D not set.");
if (destination.getD2d() == true) {
if (destination.getRateD2d() == null || destination.getRateD2d().compareTo(BigDecimal.ZERO) == 0) {
@ -97,7 +111,7 @@ public class PreCalculationCheckService {
}
if (destination.getCountryId() == null || destination.getCountryId() == 0) {
throw new PremiseValidationError("In destination " + node.getName() +": destination country ID not set. Please contact administrator");
throw new PremiseValidationError("In destination " + node.getName() + ": destination country ID not set. Please contact administrator");
}
if (destination.getGeoLat() == null || destination.getGeoLng() == null) {
@ -183,6 +197,24 @@ public class PreCalculationCheckService {
throw new PremiseValidationError("Packaging dimension unit is not set");
}
var hu = dimensionTransformer.toDimensionEntity(premise).withTolerance(DIMENSION_TOLERANCE);
Optional<Integer> teuLoad = propertyService.getProperty(SystemPropertyMappingId.TEU_LOAD);
Optional<Integer> feuLoad = propertyService.getProperty(SystemPropertyMappingId.TEU_LOAD);
if (teuLoad.isEmpty() || feuLoad.isEmpty())
throw new PremiseValidationError("There is a system property misconfiguration. Please contact administrator");
if (WeightUnit.KG.convertFromG(hu.getWeight()) > teuLoad.get() && hu.getWeight() > feuLoad.get())
throw new PremiseValidationError("The handling unit is too heavy. Configured maximum is " + Math.max(teuLoad.get(), feuLoad.get()) + " kg. ");
var teuFitsXY = (hu.getLength() < ContainerType.TEU.getLength() && hu.getWidth() < ContainerType.TEU.getWidth());
var teuFitsYX = (hu.getWidth() < ContainerType.TEU.getLength() && hu.getLength() < ContainerType.TEU.getWidth());
if (!teuFitsYX && !teuFitsXY) {
throw new PremiseValidationError("The handling unit is too big. Has to fit into twenty food equivalent (minus " + DIMENSION_TOLERANCE + " tolerance) container.");
}
}
private void materialCheck(Premise premise) {

View file

@ -1,6 +1,7 @@
package de.avatic.lcc.service.transformer.generic;
import de.avatic.lcc.dto.generic.DimensionDTO;
import de.avatic.lcc.excelmodel.ExcelPackaging;
import de.avatic.lcc.model.packaging.PackagingDimension;
import de.avatic.lcc.model.packaging.PackagingType;
import de.avatic.lcc.model.premises.Premise;
@ -108,4 +109,46 @@ public class DimensionTransformer {
return dto;
}
public PackagingDimension toDimensionEntity(ExcelPackaging packaging, PackagingType type) {
PackagingDimension dimension = new PackagingDimension();
if (type == PackagingType.HU) {
WeightUnit weightUnit = packaging.getHuWeightUnit();
DimensionUnit unit = packaging.getHuDimensionUnit();
dimension.setLength(unit.convertToMM(packaging.getHuLength()));
dimension.setHeight(unit.convertToMM(packaging.getHuHeight()));
dimension.setWidth(unit.convertToMM(packaging.getHuWidth()));
dimension.setDimensionUnit(unit);
dimension.setWeight(weightUnit.convertToG(packaging.getHuWeight()));
dimension.setWeightUnit(weightUnit);
dimension.setContentUnitCount(packaging.getHuUnitCount());
dimension.setType(PackagingType.HU);
dimension.setDeprecated(false);
} else if (type == PackagingType.SHU) {
WeightUnit weightUnit = packaging.getShuWeightUnit();
DimensionUnit unit = packaging.getShuDimensionUnit();
dimension.setLength(unit.convertToMM(packaging.getShuLength()));
dimension.setHeight(unit.convertToMM(packaging.getShuHeight()));
dimension.setWidth(unit.convertToMM(packaging.getShuWidth()));
dimension.setDimensionUnit(unit);
dimension.setWeight(weightUnit.convertToG(packaging.getShuWeight()));
dimension.setWeightUnit(weightUnit);
dimension.setContentUnitCount(packaging.getShuUnitCount());
dimension.setType(PackagingType.SHU);
dimension.setDeprecated(false);
}
return dimension;
}
}

View file

@ -90,6 +90,8 @@ public class NodeTransformer {
}
entity.setId(excelNode.getId());
entity.setExternalMappingId(excelNode.getExternalMappingId());
entity.setName(excelNode.getName());
entity.setAddress(excelNode.getAddress());
entity.setCountryId(countryId.get().getId());

View file

@ -30,6 +30,9 @@ public class MaterialDetailPackagingPropertyTransformer {
dto.setExternalMappingId(property.getType().getExternalMappingId());
dto.setValidationRule(property.getType().getValidationRule());
return dto;
}

View file

@ -5,51 +5,51 @@
-- Description -> name
-- ===================================================
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Reference route: Port of origin', 'START_REF', 'TEXT', '{}','Reference route used to demonstrate sea freight fluctuation, port in country of origin','Reference route','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Reference route: Port of destination', 'END_REF', 'TEXT', '{}','Reference route used to demonstrate sea freight fluctuation, port in country of destination','Reference route','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'All-time-high container rate (40 ft.) [EUR]', 'RISK_REF', 'CURRENCY', '{"GT":0}','Highest container rate to be used to demnastrate sea freight fluctuation, cost for 40 Ft. (FEU) general purpose container','Reference route','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'All-time-low container rate (40 ft.) [EUR]', 'CHANCE_REF', 'CURRENCY', '{"GT":0}','Lowest container rate to be used to demnastrate sea freight fluctuation, cost for 40 Ft. (FEU) general purpose container','Reference route','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Payment terms [days]', 'PAYMENT_TERMS', 'INT', '{}','Payment target [days] agreed with suppliers','General','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Annual working days', 'WORKDAYS', 'INT', '{"GT": 0, "LT": 366}','Annual working days (production)','General','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Interest rate inventory [%]', 'INTEREST_RATE', 'PERCENTAGE', '{"GTE": 0}','Calculatory interest rate for inventories and payment targets','General','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'FCA fee [%]', 'FCA_FEE', 'PERCENTAGE', '{"GTE": 0}','FCA fee to be added on EXW prices (MEK_A)','General','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Default customs rate [%]', 'TARIFF_RATE', 'PERCENTAGE', '{"GTE":0}','Customs rate to be applied, if no exact value is available','General','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Customs clearance fee per import & HS code [EUR]', 'CUSTOM_FEE', 'CURRENCY', '{"GTE":0}','Average customs clearance fee charged for the import of one HS code per import (mixed container)','General','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Standard reporting format', 'REPORTING', 'ENUMERATION', '{"ENUM":["MEK_B","MEK_C"]}','Defines standard format for reports (MEK_B = excl. Risks, MEK_C = incl. risks)','General','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( '40 ft.', 'FEU', 'BOOLEAN', '{}','To be activated, if calculation shall be possible with this container size. Container rates to be maintained.','Sea and road transport','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( '20 ft.', 'TEU', 'BOOLEAN', '{}','To be activated, if calculation shall be possible with this container size. Container rates to be maintained.','Sea and road transport','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( '40 ft. HC', 'FEU_HQ', 'BOOLEAN', '{}','To be activated, if calculation shall be possible with this container size. Container rates to be maintained.','Sea and road transport','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Container utilization in mixed containers [%]', 'CONTAINER_UTIL', 'PERCENTAGE', '{"GTE":0,"LTE":1}','Defines, to which degree the volume of a mixed container shall be utilized (loss due to inefficient stacking and different packaging sizes).','Sea and road transport','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Truck utilization road transport EMEA [%]', 'TRUCK_UTIL', 'PERCENTAGE', '{"GTE":0,"LTE":1}','Defines, to which degree the volume of a truck shall be utilized (loss due to inefficient stacking and different packaging sizes).','Sea and road transport','8');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Max validity period of container freight rates [days]', 'VALID_DAYS', 'INT', '{"GT": 0}','Defines the maximum period of time, after which container freight rates cannot be used for calculations anymore.','General','8');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Metropolition region size (diameter) [km]', 'RADIUS_REGION', 'INT', '{"GT": 0}','Defines the average distance a supplier may have from a defined source (e.g. center of metropolitan area), for which a container rate is maintained.','General','9');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Min delivery frequency / year for containter transports', 'FREQ_MIN', 'INT', '{"GT": 0, "LT": 366}','Relevant for low runners; defines into how many deliveries a HU shall be split, if HU content >= yearly demand (e.g. 4 = 1/4 of yearly demand is allocated to a shipment)','General','10');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Max delivery frequency / year for containter transport', 'FREQ_MAX', 'INT', '{"GT": 0, "LT": 366}','Relevant for high runners; defines the maximum shipping frequency for sea shipments (e.g. 52 = weekly, 104 = 2x/week, 12 = monthly etc.)','General','11');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Max load 20 ft. container [kg]', 'TEU_LOAD', 'INT', '{"GT": 0}','Defines the weight limit of a TEU container.','Sea and road transport','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Max load 40 ft. container [kg]', 'FEU_LOAD', 'INT', '{"GT": 0}','Defines the weight limit of a FEU container. Can be also limited by local law (e.g. road transport weight in CN limited to 21 tons).','Sea and road transport','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Max load truck [kg]', 'TRUCK_LOAD', 'INT', '{"GT": 0}','Defines the weight limit of a truck (use standard type, usually 40-ton truck)','Sea and road transport','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Pre-carriage [EUR/kg]', 'AIR_PRECARRIAGE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for pre-carriage to airport in country of origin','Air transport','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Pre-carriage handling [EUR]', 'AIR_HANDLING', 'CURRENCY', '{"GTE": 0}','For air transports only: one time costs for handling of air shipments (documents)','Air transport','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Main carriage [EUR/kg]', 'AIR_MAINCARRIAGE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for flight. (use as reference route the flight route with the highest traffic, e.g. CN-DE)','Air transport','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Hand over fee [EUR]', 'AIR_HANDOVER_FEE', 'CURRENCY', '{"GTE": 0}','For air transports only: one time cost for handover of air shipment ','Air transport','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Customs clearance fee [EUR]', 'AIR_CUSTOM_FEE', 'CURRENCY', '{"GTE": 0}','For air transports only: one time cost for customs clearance of air shipment ','Air transport','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'On-carriage [EUR/kg]', 'AIR_ONCARRIAGE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for on-carriage from airport to destination','Air transport','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Terminal handling fee [EUR/kg]', 'AIR_TERMINAL_FEE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for handling of shipment in airport terminal','Air transport','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'GR handling KLT [EUR/HU] (DE)', 'KLT_HANDLING', 'CURRENCY', '{"GTE": 0}','Cost per KLT for the handling in the Goods Receipt area of a warehouse or plant; reference country: Germany','Warehouse','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'GR handling GLT [EUR/HU] (DE)', 'GLT_HANDLING', 'CURRENCY', '{"GTE": 0}','Cost per GLT for the handling in the Goods Receipt area of a warehouse or plant; reference country: Germany','Warehouse','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'GLT booking & document handling [EUR/GR] (DE)', 'BOOKING', 'CURRENCY', '{"GTE": 0}','One time document handling fee for 1 GLT; reference country: Germany','Warehouse','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'GLT release from storage [EUR/GLT release] (DE)', 'GLT_RELEASE', 'CURRENCY', '{"GTE": 0}','Cost to release one GLT from the storage; reference country: Germany','Warehouse','12');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'KLT release from storage [EUR/KLT release] (DE)', 'KLT_RELEASE', 'CURRENCY', '{"GTE": 0}','Cost to release one KLT from the storage; reference country: Germany','Warehouse','11');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'GLT dispatch [EUR/GLT dispatch] (DE)', 'GLT_DISPATCH', 'CURRENCY', '{"GTE": 0}','Cost to disptach one GLT; reference country: Germany','Warehouse','14');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'KLT dispacth [EUR/KLT dispatch] (DE)', 'KLT_DISPATCH', 'CURRENCY', '{"GTE": 0}','Cost to disptach one KLT; reference country: Germany','Warehouse','13');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Repacking KLT, HU <15kg [EUR/HU] (DE)', 'KLT_REPACK_S', 'CURRENCY', '{"GTE": 0}','Cost to repack one KLT (<15 kg) from one-way to returnable empty; reference country: Germany','Warehouse','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Repacking KLT, HU >=15kg [EUR/HU] (DE)', 'KLT_REPACK_M', 'CURRENCY', '{"GTE": 0}','Cost to repack one KLT (>=15 kg) from one-way to returnable empty with crane handling; reference country: Germany','Warehouse','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Repacking GLT, HU <15kg [EUR/HU] (DE)', 'GLT_REPACK_S', 'CURRENCY', '{"GTE": 0}','Cost to repack one GLT (<15 kg) from oneway to returnable empty; reference country: Germany','Warehouse','8');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Repacking GLT, HU 15 - 2000kg [EUR/HU] (DE)', 'GLT_REPACK_M', 'CURRENCY', '{"GTE": 0}','Cost to repack one GLT (>=15 - 2000 kg) from one-way to returnable empty with crane handling; reference country: Germany','Warehouse','9');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Repacking GLT, HU >2000kg [EUR/HU] (DE)', 'GLT_REPACK_L', 'INT', '{"GTE": 0}','Cost to repack one GLT (> 2000 kg, e.g. counterweight) from one-way to returnable empty with crane handling; reference country: Germany','Warehouse','10');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'GLT disposal [EUR/GLT] (DE)', 'DISPOSAL', 'INT', '{"GTE": 0}','Cost to dispose one wooden pallet (value valid for all countries)','Warehouse','15');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'Space costs per cbm per night [EUR/cbm] (DE)', 'SPACE_COST', 'CURRENCY', '{"GTE": 0}','Cost per month for a standard storage bin (1,20 x 0,80 x 1,00 m)','Warehouse','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sort_id) VALUES ( 'KLT booking & document handling [EUR/GR] (DE)', 'BOOKING_KLT', 'CURRENCY', '{"GTE": 0}','One time document handling fee for 1 KLT; reference country: Germany','Warehouse','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Reference route: Port of origin', 'START_REF', 'TEXT', '{}','Reference route used to demonstrate sea freight fluctuation, port in country of origin','Reference route','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Reference route: Port of destination', 'END_REF', 'TEXT', '{}','Reference route used to demonstrate sea freight fluctuation, port in country of destination','Reference route','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'All-time-high container rate (40 ft.) [EUR]', 'RISK_REF', 'CURRENCY', '{"GT":0}','Highest container rate to be used to demnastrate sea freight fluctuation, cost for 40 Ft. (FEU) general purpose container','Reference route','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'All-time-low container rate (40 ft.) [EUR]', 'CHANCE_REF', 'CURRENCY', '{"GT":0}','Lowest container rate to be used to demnastrate sea freight fluctuation, cost for 40 Ft. (FEU) general purpose container','Reference route','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Payment terms [days]', 'PAYMENT_TERMS', 'INT', '{}','Payment target [days] agreed with suppliers','General','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Annual working days', 'WORKDAYS', 'INT', '{"GT": 0, "LT": 366}','Annual working days (production)','General','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Interest rate inventory [%]', 'INTEREST_RATE', 'PERCENTAGE', '{"GTE": 0}','Calculatory interest rate for inventories and payment targets','General','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'FCA fee [%]', 'FCA_FEE', 'PERCENTAGE', '{"GTE": 0}','FCA fee to be added on EXW prices (MEK_A)','General','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Default customs rate [%]', 'TARIFF_RATE', 'PERCENTAGE', '{"GTE":0}','Customs rate to be applied, if no exact value is available','General','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Customs clearance fee per import & HS code [EUR]', 'CUSTOM_FEE', 'CURRENCY', '{"GTE":0}','Average customs clearance fee charged for the import of one HS code per import (mixed container)','General','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Standard reporting format', 'REPORTING', 'ENUMERATION', '{"ENUM":["MEK_B","MEK_C"]}','Defines standard format for reports (MEK_B = excl. Risks, MEK_C = incl. risks)','General','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( '40 ft.', 'FEU', 'BOOLEAN', '{}','To be activated, if calculation shall be possible with this container size. Container rates to be maintained.','Sea and road transport','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( '20 ft.', 'TEU', 'BOOLEAN', '{}','To be activated, if calculation shall be possible with this container size. Container rates to be maintained.','Sea and road transport','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( '40 ft. HC', 'FEU_HQ', 'BOOLEAN', '{}','To be activated, if calculation shall be possible with this container size. Container rates to be maintained.','Sea and road transport','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Container utilization in mixed containers [%]', 'CONTAINER_UTIL', 'PERCENTAGE', '{"GTE":0,"LTE":1}','Defines, to which degree the volume of a mixed container shall be utilized (loss due to inefficient stacking and different packaging sizes).','Sea and road transport','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Truck utilization road transport EMEA [%]', 'TRUCK_UTIL', 'PERCENTAGE', '{"GTE":0,"LTE":1}','Defines, to which degree the volume of a truck shall be utilized (loss due to inefficient stacking and different packaging sizes).','Sea and road transport','8');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Max validity period of container freight rates [days]', 'VALID_DAYS', 'INT', '{"GT": 0}','Defines the maximum period of time, after which container freight rates cannot be used for calculations anymore.','General','8');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Metropolition region size (diameter) [km]', 'RADIUS_REGION', 'INT', '{"GT": 0}','Defines the average distance a supplier may have from a defined source (e.g. center of metropolitan area), for which a container rate is maintained.','General','9');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Min delivery frequency / year for containter transports', 'FREQ_MIN', 'INT', '{"GT": 0, "LT": 366}','Relevant for low runners; defines into how many deliveries a HU shall be split, if HU content >= yearly demand (e.g. 4 = 1/4 of yearly demand is allocated to a shipment)','General','10');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Max delivery frequency / year for containter transport', 'FREQ_MAX', 'INT', '{"GT": 0, "LT": 366}','Relevant for high runners; defines the maximum shipping frequency for sea shipments (e.g. 52 = weekly, 104 = 2x/week, 12 = monthly etc.)','General','11');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Max load 20 ft. container [kg]', 'TEU_LOAD', 'INT', '{"GT": 0}','Defines the weight limit of a TEU container.','Sea and road transport','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Max load 40 ft. container [kg]', 'FEU_LOAD', 'INT', '{"GT": 0}','Defines the weight limit of a FEU container. Can be also limited by local law (e.g. road transport weight in CN limited to 21 tons).','Sea and road transport','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Max load truck [kg]', 'TRUCK_LOAD', 'INT', '{"GT": 0}','Defines the weight limit of a truck (use standard type, usually 40-ton truck)','Sea and road transport','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Pre-carriage [EUR/kg]', 'AIR_PRECARRIAGE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for pre-carriage to airport in country of origin','Air transport','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Pre-carriage handling [EUR]', 'AIR_HANDLING', 'CURRENCY', '{"GTE": 0}','For air transports only: one time costs for handling of air shipments (documents)','Air transport','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Main carriage [EUR/kg]', 'AIR_MAINCARRIAGE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for flight. (use as reference route the flight route with the highest traffic, e.g. CN-DE)','Air transport','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Hand over fee [EUR]', 'AIR_HANDOVER_FEE', 'CURRENCY', '{"GTE": 0}','For air transports only: one time cost for handover of air shipment ','Air transport','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Customs clearance fee [EUR]', 'AIR_CUSTOM_FEE', 'CURRENCY', '{"GTE": 0}','For air transports only: one time cost for customs clearance of air shipment ','Air transport','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'On-carriage [EUR/kg]', 'AIR_ONCARRIAGE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for on-carriage from airport to destination','Air transport','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Terminal handling fee [EUR/kg]', 'AIR_TERMINAL_FEE', 'CURRENCY', '{"GTE": 0}','For air transports only: cost per kg for handling of shipment in airport terminal','Air transport','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'GR handling KLT [EUR/HU] (DE)', 'KLT_HANDLING', 'CURRENCY', '{"GTE": 0}','Cost per KLT for the handling in the Goods Receipt area of a warehouse or plant; reference country: Germany','Warehouse','4');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'GR handling GLT [EUR/HU] (DE)', 'GLT_HANDLING', 'CURRENCY', '{"GTE": 0}','Cost per GLT for the handling in the Goods Receipt area of a warehouse or plant; reference country: Germany','Warehouse','5');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'GLT booking & document handling [EUR/GR] (DE)', 'BOOKING', 'CURRENCY', '{"GTE": 0}','One time document handling fee for 1 GLT; reference country: Germany','Warehouse','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'GLT release from storage [EUR/GLT release] (DE)', 'GLT_RELEASE', 'CURRENCY', '{"GTE": 0}','Cost to release one GLT from the storage; reference country: Germany','Warehouse','12');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'KLT release from storage [EUR/KLT release] (DE)', 'KLT_RELEASE', 'CURRENCY', '{"GTE": 0}','Cost to release one KLT from the storage; reference country: Germany','Warehouse','11');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'GLT dispatch [EUR/GLT dispatch] (DE)', 'GLT_DISPATCH', 'CURRENCY', '{"GTE": 0}','Cost to disptach one GLT; reference country: Germany','Warehouse','14');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'KLT dispacth [EUR/KLT dispatch] (DE)', 'KLT_DISPATCH', 'CURRENCY', '{"GTE": 0}','Cost to disptach one KLT; reference country: Germany','Warehouse','13');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Repacking KLT, HU <15kg [EUR/HU] (DE)', 'KLT_REPACK_S', 'CURRENCY', '{"GTE": 0}','Cost to repack one KLT (<15 kg) from one-way to returnable empty; reference country: Germany','Warehouse','6');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Repacking KLT, HU >=15kg [EUR/HU] (DE)', 'KLT_REPACK_M', 'CURRENCY', '{"GTE": 0}','Cost to repack one KLT (>=15 kg) from one-way to returnable empty with crane handling; reference country: Germany','Warehouse','7');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Repacking GLT, HU <15kg [EUR/HU] (DE)', 'GLT_REPACK_S', 'CURRENCY', '{"GTE": 0}','Cost to repack one GLT (<15 kg) from oneway to returnable empty; reference country: Germany','Warehouse','8');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Repacking GLT, HU 15 - 2000kg [EUR/HU] (DE)', 'GLT_REPACK_M', 'CURRENCY', '{"GTE": 0}','Cost to repack one GLT (>=15 - 2000 kg) from one-way to returnable empty with crane handling; reference country: Germany','Warehouse','9');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Repacking GLT, HU >2000kg [EUR/HU] (DE)', 'GLT_REPACK_L', 'INT', '{"GTE": 0}','Cost to repack one GLT (> 2000 kg, e.g. counterweight) from one-way to returnable empty with crane handling; reference country: Germany','Warehouse','10');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'GLT disposal [EUR/GLT] (DE)', 'DISPOSAL', 'INT', '{"GTE": 0}','Cost to dispose one wooden pallet (value valid for all countries)','Warehouse','15');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Space costs per cbm per night [EUR/cbm] (DE)', 'SPACE_COST', 'CURRENCY', '{"GTE": 0}','Cost per month for a standard storage bin (1,20 x 0,80 x 1,00 m)','Warehouse','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'KLT booking & document handling [EUR/GR] (DE)', 'BOOKING_KLT', 'CURRENCY', '{"GTE": 0}','One time document handling fee for 1 KLT; reference country: Germany','Warehouse','3');

View file

@ -22,12 +22,12 @@ WHERE NOT EXISTS (
-- =============================================================================
INSERT INTO `country_property_type`
(`name`, `external_mapping_id`, `data_type`, `validation_rule`, `is_required`)
(`name`, `external_mapping_id`, `data_type`, `validation_rule`, `is_required`, `description`, `property_group`, `sequence_number`)
VALUES
('Customs Union', 'UNION', 'ENUMERATION', '{ "ENUM" : ["EU", "NONE"]}', FALSE),
('Safety Stock [working days]', 'SAFETY_STOCK', 'INT', '{"GTE": 0}', FALSE),
('Air Freight Share [%]', 'AIR_SHARE', 'PERCENTAGE', '{"GTE": 0}', FALSE),
('Wage Factor [%]', 'WAGE', 'PERCENTAGE', '{"GT": 0}', FALSE);
('Customs Union', 'UNION', 'ENUMERATION', '{ "ENUM" : ["EU", "NONE"]}', FALSE, 'Custom union description', 'General', 1),
('Safety Stock [working days]', 'SAFETY_STOCK', 'INT', '{"GTE": 0}', FALSE, 'Safety stock description', 'General', 2),
('Air Freight Share [%]', 'AIR_SHARE', 'PERCENTAGE', '{"GTE": 0}', FALSE, 'Air freight description', 'General', 3),
('Wage Factor [%]', 'WAGE', 'PERCENTAGE', '{"GT": 0}', FALSE, 'Wage factor description', 'General', 4);
-- =============================================================================
-- 2. INSERT COUNTRIES

View file

@ -7,7 +7,8 @@
INSERT INTO packaging_property_type (name, external_mapping_id, data_type, validation_rule, is_required)
VALUES
('Stackable', 'STACKABLE', 'BOOLEAN', NULL, FALSE),
('Rust Prevention', 'RUST_PREVENTION', 'BOOLEAN', NULL, FALSE)
('Rust Prevention', 'RUST_PREVENTION', 'BOOLEAN', NULL, FALSE),
('Mixable', 'MIXABLE', 'BOOLEAN', NULL, FALSE)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
data_type = VALUES(data_type);

View file

@ -21,8 +21,8 @@ CREATE TABLE IF NOT EXISTS `system_property_type`
`name` VARCHAR(255) NOT NULL,
`external_mapping_id` VARCHAR(16),
`description` VARCHAR(255) NOT NULL,
`property_group` VARCHAR(32) NOT NULL,
`sort_id` INT,
`property_group` VARCHAR(32) NOT NULL,
`sequence_number` INT NOT NULL,
`data_type` VARCHAR(16) NOT NULL,
`validation_rule` VARCHAR(64),
UNIQUE KEY `idx_external_mapping` (`external_mapping_id`),
@ -52,6 +52,9 @@ CREATE TABLE IF NOT EXISTS `country`
`iso_code` CHAR(2) NOT NULL COMMENT 'ISO 3166-1 alpha-2 country code',
`region_code` CHAR(5) NOT NULL COMMENT 'Geographic region code (EMEA/LATAM/APAC/NAM)',
`name` VARCHAR(255) NOT NULL,
`description` VARCHAR(255) NOT NULL,
`property_group` VARCHAR(32) NOT NULL,
`sequence_number` INT NOT NULL,
`is_deprecated` BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_country_iso_code` (`iso_code`),
@ -308,6 +311,9 @@ CREATE TABLE IF NOT EXISTS packaging_property_type
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL,
external_mapping_id VARCHAR(16) NOT NULL,
`description` VARCHAR(255) NOT NULL,
`property_group` VARCHAR(32) NOT NULL,
`sequence_number` INT NOT NULL,
`data_type` VARCHAR(16),
`validation_rule` VARCHAR(64),
`is_required` BOOLEAN NOT NULL DEFAULT FALSE,