Updated SQL seed data descriptions for clarity and consistency. Added unique constraint validation and error highlighting in Excel mappers. Enhanced validation methods and refactored utilities for better maintainability.

This commit is contained in:
Jan 2025-09-29 21:19:27 +02:00
parent ee989d1bfc
commit 1fa1680535
5 changed files with 88 additions and 23 deletions

View file

@ -3,7 +3,9 @@ package de.avatic.lcc.service.bulk.helper;
import de.avatic.lcc.model.bulk.HiddenTableType;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.springframework.stereotype.Service;
import java.util.EnumSet;
@ -80,6 +82,48 @@ public class ConstraintGenerator {
sheet.addValidationData(validation);
}
public void createUniqueConstraint(Sheet sheet, int columnIdx) {
// SheetConditionalFormatting Objekt holen
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
String columnLetter = toExcelLetter(columnIdx);
CellRangeAddress[] regions = {
CellRangeAddress.valueOf(columnLetter+"2:"+columnLetter+(MAX_ROWS))
};
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(
"COUNTIF($" + columnLetter + "$2:$" + columnLetter + "$" + (MAX_ROWS) + ","+columnLetter+"2)>1"
);
createHighlightCellStyle(rule);
sheetCF.addConditionalFormatting(regions, rule);
}
private void createHighlightCellStyle(ConditionalFormattingRule rule) {
XSSFColor customTextColor = new XSSFColor(new byte[]{(byte)255, (byte)255, (byte)255}, null);
XSSFColor customColor = new XSSFColor(new byte[]{(byte)188, (byte)43, (byte)114}, null);
PatternFormatting patternFmt = rule.createPatternFormatting();
patternFmt.setFillBackgroundColor(customColor);
patternFmt.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
FontFormatting fontFmt = rule.createFontFormatting();
fontFmt.setFontColor(customTextColor);
fontFmt.setFontStyle(false, true);
}
public Name createReference(Workbook workbook, Integer columnIdx, HiddenTableType hiddenTableType) {
// Check if the referenced sheet exists
Sheet hiddenSheet = workbook.getSheet(hiddenTableType.getSheetName());
@ -210,6 +254,13 @@ public class ConstraintGenerator {
}
public void validateStringCell(Row row, int columnIdx, Boolean allowEmpty) {
if(allowEmpty) {
if(row.getCell(columnIdx) == null) {
return;
}
}
CellType cellType = row.getCell(columnIdx).getCellType();
if(cellType == CellType.BLANK && allowEmpty) {
@ -244,4 +295,6 @@ public class ConstraintGenerator {
throw new ExcelValidationError("Unable to validate row " + (row.getRowNum() + 1) + " column " + toExcelLetter(columnIdx) + ": Expected numeric integer value within range: [" + min + " , " + max + "]");
}
}

View file

@ -11,8 +11,6 @@ public class HeaderCellStyleProvider {
public CellStyle createHeaderCellStyle(Workbook workbook) {
XSSFFont headerFont = (XSSFFont) workbook.createFont();
XSSFColor customTextColor = new XSSFColor(new byte[]{(byte)0, (byte)47, (byte)84}, null); // Blue
@ -41,4 +39,6 @@ public class HeaderCellStyleProvider {
return headerStyle;
}
}

View file

@ -3,6 +3,7 @@ package de.avatic.lcc.service.excelMapper;
import de.avatic.lcc.model.bulk.BulkInstruction;
import de.avatic.lcc.model.bulk.BulkInstructionType;
import de.avatic.lcc.model.bulk.header.MaterialHeader;
import de.avatic.lcc.model.bulk.header.NodeHeader;
import de.avatic.lcc.model.materials.Material;
import de.avatic.lcc.repositories.MaterialRepository;
import de.avatic.lcc.service.bulk.helper.ConstraintGenerator;
@ -47,6 +48,9 @@ public class MaterialExcelMapper {
constraintGenerator.createLengthConstraint(sheet, MaterialHeader.HS_CODE.ordinal(), 0, 11);
constraintGenerator.createLengthConstraint(sheet, MaterialHeader.DESCRIPTION.ordinal(), 1, 500);
constraintGenerator.createEnumConstraint(sheet, MaterialHeader.OPERATION.ordinal(), BulkInstructionType.class);
constraintGenerator.createUniqueConstraint(sheet, MaterialHeader.PART_NUMBER.ordinal());
}
public List<BulkInstruction<Material>> extractSheet(Sheet sheet) {

View file

@ -13,7 +13,9 @@ import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.country.CountryRepository;
import de.avatic.lcc.service.bulk.helper.ConstraintGenerator;
import de.avatic.lcc.service.bulk.helper.HeaderGenerator;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellUtil;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@ -87,6 +89,8 @@ public class NodeExcelMapper {
constraintGenerator.createEnumConstraint(sheet, NodeHeader.OPERATION.ordinal(), BulkInstructionType.class);
constraintGenerator.createUniqueConstraint(sheet, NodeHeader.MAPPING_ID.ordinal());
}
public List<BulkInstruction<ExcelNode>> extractSheet(Sheet sheet) {
@ -94,22 +98,27 @@ public class NodeExcelMapper {
var nodes = new ArrayList<BulkInstruction<ExcelNode>>();
System.out.println(sheet.getLastRowNum());
sheet.forEach(row -> {
if (row.getRowNum() == 0) return;
if (!isEmpty(row))
nodes.add(mapToEntity(row));
});
if(nodes.stream().map(BulkInstruction::getEntity).map(ExcelNode::getExternalMappingId).distinct().count() != nodes.size()) {
throw new ExcelValidationError("Duplicate external mapping ids found in sheet");
}
return nodes;
}
private boolean isEmpty(Row row) {
for(Cell cell : row) {
if (cell.getCellType() != CellType.BLANK) {
return false;
if(cell != null) {
if (cell.getCellType() != CellType.BLANK) {
return false;
}
}
}
@ -131,9 +140,8 @@ public class NodeExcelMapper {
entity.setIntermediate(Boolean.valueOf(row.getCell(NodeHeader.IS_INTERMEDIATE.ordinal()).getStringCellValue()));
entity.setDestination(Boolean.valueOf(row.getCell(NodeHeader.IS_DESTINATION.ordinal()).getStringCellValue()));
entity.setPredecessorRequired(Boolean.valueOf(row.getCell(NodeHeader.IS_PREDECESSOR_MANDATORY.ordinal()).getStringCellValue()));
entity.setNodePredecessors(mapChainsFromCell(row.getCell(NodeHeader.PREDECESSOR_NODES.ordinal()).getStringCellValue()));
entity.setOutboundCountries(mapOutboundCountriesFromCell(row.getCell(NodeHeader.OUTBOUND_COUNTRIES.ordinal()).getStringCellValue()));
entity.setNodePredecessors(mapChainsFromCell(CellUtil.getCell(row, NodeHeader.PREDECESSOR_NODES.ordinal()).getStringCellValue()));
entity.setOutboundCountries(mapOutboundCountriesFromCell(CellUtil.getCell(row, NodeHeader.OUTBOUND_COUNTRIES.ordinal()).getStringCellValue()));
return new BulkInstruction<>(entity, BulkInstructionType.valueOf(row.getCell(NodeHeader.OPERATION.ordinal()).getStringCellValue()));
}

View file

@ -5,15 +5,15 @@
-- Description -> name
-- ===================================================
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( '2_Reference route: Port of origin', 'START_REF', 'TEXT', '{}','2_Reference route used to demonstrate sea freight fluctuation, port in country of origin','2_Reference route','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( '2_Reference route: Port of destination', 'END_REF', 'TEXT', '{}','2_Reference route used to demonstrate sea freight fluctuation, port in country of destination','2_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 demonstrate sea freight fluctuation, cost for 40 Ft. (FEU) general purpose container','2_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 demonstrate sea freight fluctuation, cost for 40 Ft. (FEU) general purpose container','2_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 terms [days] agreed with suppliers.','1_General','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Reference route: Start node', 'START_REF', 'TEXT', '{}','Specifies the starting node of the reference route. A historical maximum and a historical minimum value are stored for the reference route. This reference route is used to calculate fluctuations in transport costs.','2_Reference route','1');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Reference route: End node', 'END_REF', 'TEXT', '{}','Specifies the end node of the reference route. A historical maximum and a historical minimum value are stored for the reference route. This reference route is used to calculate fluctuations in transport costs.','2_Reference route','2');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Reference route: All-time-high container rate (40 ft. GP) [EUR]', 'RISK_REF', 'CURRENCY', '{"GT":0}','Specifies the historically maximum container rate of the reference route for a 40 ft. GP container. A historical maximum and a historical minimum value are stored for the reference route. This reference route is used to calculate fluctuations in transport costs.','2_Reference route','3');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Reference route: All-time-low container rate (40 ft. GP) [EUR]', 'CHANCE_REF', 'CURRENCY', '{"GT":0}','Specifies the historically lowest container rate of the reference route for a 40 ft. GP container. A historical maximum and a historical minimum value are stored for the reference route. This reference route is used to calculate fluctuations in transport costs.','2_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 terms agreed with suppliers in days. This value is used to calculate the financing costs for goods in transit and in safety stock.','1_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 production working days.','1_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}','Interest rate for inventories and payment terms.','1_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 added on EXW prices (MEK_A); applied only if selected in calculation.','1_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 applied if no exact database value available.','1_General','6');
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}','Interest rate used for calculating capital costs.','1_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 to EXW prices. The logistics cost expert must explicitly select this during the calculation for the fee to be applied.','1_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}','Standard customs duty rate to be applied when the HS Code cannot be resolved automatically.','1_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}','Avg. customs clearance fee per HS code and import.','1_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"]}','Standard report format (MEK_B = excl. risks, MEK_C = incl. risks).','1_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', '{}','Enable if calculation should include this container size; container rates to be maintained.','3_Sea and road transport','1');
@ -22,13 +22,13 @@ INSERT INTO system_property_type ( name, external_mapping_id, data_type, validat
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}','Utilization degree of mixed containers (loss from stacking/packaging).','3_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}','Utilization degree of trucks (loss from stacking/packaging).','3_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}','Max. validity period for container freight rates. Afterwards update required.','1_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}','Avg. supplier distance allowed from origin point of container rates (e.g. rate from metropolitan center to local port).','1_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}','Low runners: defines delivery splits if HU content >= yearly demand (e.g. 4 = quarterly shipment).','1_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}','High runners: defines max. sea shipment frequency (e.g. 52 = weekly, 104 = 2x/week, 12 = monthly); affects avg. inventory.','1_General','11');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Metropolitan region size (diameter) [km]', 'RADIUS_REGION', 'INT', '{"GT": 0}','If there are no kilometer rates within a country, it is possible to use container rates from neighboring logistics nodes. However, the node must be within the metropolitan region radius.','1_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 container transports', 'FREQ_MIN', 'INT', '{"GT": 0, "LT": 366}','Low runners: Indicates the number of annual deliveries when the annual demand is lower than the content of a handling unit (The HU is then split up)','1_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 container transport', 'FREQ_MAX', 'INT', '{"GT": 0, "LT": 366}','High runners: Indicates the maximum number of annual deliveries. (If the annual demand exceeds this number, one delivery contains more than one HU). Please note that this value affects the storage space cost.','1_General','11');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'Max weight load 20 ft. container [kg]', 'TEU_LOAD', 'INT', '{"GT": 0}','Weight limit of TEU container.','3_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 weight load 40 ft. container [kg]', 'FEU_LOAD', 'INT', '{"GT": 0}','Weight limit of FEU container (may be restricted by law, e.g. CN truck load = 21 tons).','3_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 weight load truck [kg]', 'TRUCK_LOAD', 'INT', '{"GT": 0}','Weight limit of standard truck.','3_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}','FAir only: pre-carriage cost per kg to airport of origin.','4_Air transport','1');
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}','Air only: pre-carriage cost per kg to airport of origin.','4_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}','Air only: one-time handling cost (documents).','4_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}','Air only: flight cost per kg (use most frequently used route, e.g. CN-DE).','4_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}','Air only: one-time handover cost. ','4_Air transport','4');
@ -41,14 +41,14 @@ INSERT INTO system_property_type ( name, external_mapping_id, data_type, validat
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 storage (reference country, e.g. DE).','5_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 storage (reference country, e.g. DE).','5_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 dispatch one GLT (reference country, e.g. DE).','5_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 dispatch one KLT (reference country, e.g. DE).','5_Warehouse','13');
INSERT INTO system_property_type ( name, external_mapping_id, data_type, validation_rule, description, property_group, sequence_number) VALUES ( 'KLT dispatch [EUR/KLT dispatch] (DE)', 'KLT_DISPATCH', 'CURRENCY', '{"GTE": 0}','Cost to dispatch one KLT (reference country, e.g. DE).','5_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 (reference country, e.g. DE).','5_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 with crane (reference country, e.g. DE).','5_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 one-way to returnable (reference country, e.g. DE).','5_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 (152000 kg) from one-way to returnable with crane (reference country, e.g. DE).','5_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 with crane (reference country, e.g. DE).','5_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 (all countries).','5_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}','Monthly cost for standard storage bin (~1.20 × 0.80 × 1.00 m).','5_Warehouse','1');
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}','Daily cost for standard storage bin (~1.20 × 0.80 × 1.00 m).','5_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 per KLT (reference country, e.g. DE).','5_Warehouse','3');