diff --git a/src/main/java/de/avatic/lcc/controller/CountryController.java b/src/main/java/de/avatic/lcc/controller/CountryController.java index e886866..da2b0e7 100644 --- a/src/main/java/de/avatic/lcc/controller/CountryController.java +++ b/src/main/java/de/avatic/lcc/controller/CountryController.java @@ -2,6 +2,7 @@ package de.avatic.lcc.controller; import de.avatic.lcc.dto.countries.get.CountryGetDTO; import de.avatic.lcc.dto.countries.get.CountryListGetDTO; +import de.avatic.lcc.dto.countries.post.CountryPostDTO; import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.service.CountryService; import org.springframework.http.ResponseEntity; @@ -38,4 +39,9 @@ public class CountryController { public ResponseEntity getCountryDetails(@PathVariable Integer id) { return ResponseEntity.ok(countryService.getCountry(id)); } + + public ResponseEntity updateCountry(@PathVariable Integer id, @RequestBody CountryPostDTO country) { + countryService.updateCountry(id, country); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/de/avatic/lcc/controller/PropertiesController.java b/src/main/java/de/avatic/lcc/controller/PropertiesController.java new file mode 100644 index 0000000..2b4392b --- /dev/null +++ b/src/main/java/de/avatic/lcc/controller/PropertiesController.java @@ -0,0 +1,30 @@ +package de.avatic.lcc.controller; + +import de.avatic.lcc.dto.properties.post.PropertiesPostDTO; +import de.avatic.lcc.service.PropertiesService; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.List; + +@RestController +@RequestMapping("/properties") +public class PropertiesController { + + private final PropertiesService propertiesService; + + public PropertiesController(PropertiesService propertiesService) { + this.propertiesService = propertiesService; + } + + @PostMapping("/{type}/{id}") + public void setProperties(@PathVariable String type, @PathVariable Integer id, @RequestBody List properties) { + propertiesService.setProperties(type, properties); + } + + @PostMapping("/{type}/{id}/{external_mapping}") + public void setProperties(@PathVariable(name = "type") String type, @PathVariable(name= "external_mapping") String externalMappingId, @RequestBody PropertiesPostDTO property) { + propertiesService.setProperties(type, List.of(property)); + } + +} diff --git a/src/main/java/de/avatic/lcc/dto/countries/get/CountryPropertyGetDTO.java b/src/main/java/de/avatic/lcc/dto/countries/get/CountryPropertyGetDTO.java index 297df44..0cdd866 100644 --- a/src/main/java/de/avatic/lcc/dto/countries/get/CountryPropertyGetDTO.java +++ b/src/main/java/de/avatic/lcc/dto/countries/get/CountryPropertyGetDTO.java @@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class CountryPropertyGetDTO { - private Integer id; - private String name; @JsonProperty("external_mapping_id") @@ -23,13 +21,8 @@ public class CountryPropertyGetDTO { @JsonProperty("draft_value") private String draftValue; - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } + @JsonProperty("validation_rule") + private String validationRule; public String getName() { return name; @@ -78,4 +71,12 @@ public class CountryPropertyGetDTO { public void setDraftValue(String draftValue) { this.draftValue = draftValue; } + + public void setValidationRule(String validationRule) { + this.validationRule = validationRule; + } + + public String getValidationRule() { + return validationRule; + } } diff --git a/src/main/java/de/avatic/lcc/dto/countries/post/CountryPostDTO.java b/src/main/java/de/avatic/lcc/dto/countries/post/CountryPostDTO.java new file mode 100644 index 0000000..788b72e --- /dev/null +++ b/src/main/java/de/avatic/lcc/dto/countries/post/CountryPostDTO.java @@ -0,0 +1,26 @@ +package de.avatic.lcc.dto.countries.post; + +import java.util.Map; + +public class CountryPostDTO { + + String id; + + Map properties; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } +} diff --git a/src/main/java/de/avatic/lcc/dto/packaging/get/PackagingGetDTO.java b/src/main/java/de/avatic/lcc/dto/packaging/get/PackagingGetDTO.java index 4b6662b..f30d34c 100644 --- a/src/main/java/de/avatic/lcc/dto/packaging/get/PackagingGetDTO.java +++ b/src/main/java/de/avatic/lcc/dto/packaging/get/PackagingGetDTO.java @@ -2,6 +2,8 @@ package de.avatic.lcc.dto.packaging.get; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + public class PackagingGetDTO { @@ -20,6 +22,8 @@ public class PackagingGetDTO { @JsonProperty("small_handling_unit") private PackagingDimensionGetDTO shu; + private List properties; + public Integer getId() { return id; } @@ -67,4 +71,12 @@ public class PackagingGetDTO { public void setShu(PackagingDimensionGetDTO shu) { this.shu = shu; } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } } diff --git a/src/main/java/de/avatic/lcc/dto/packaging/get/PackagingPropertyGetDTO.java b/src/main/java/de/avatic/lcc/dto/packaging/get/PackagingPropertyGetDTO.java new file mode 100644 index 0000000..36d0757 --- /dev/null +++ b/src/main/java/de/avatic/lcc/dto/packaging/get/PackagingPropertyGetDTO.java @@ -0,0 +1,71 @@ +package de.avatic.lcc.dto.packaging.get; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class PackagingPropertyGetDTO { + + private String name; + + @JsonProperty("external_mapping_id") + private String externalMappingId; + + @JsonProperty("is_required") + private Boolean isRequired; + + @JsonProperty("data_type") + private String dataType; + + @JsonProperty("current_value") + private String currentValue; + + @JsonProperty("validation_rule") + private String validationRule; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getExternalMappingId() { + return externalMappingId; + } + + public void setExternalMappingId(String externalMappingId) { + this.externalMappingId = externalMappingId; + } + + public Boolean getRequired() { + return isRequired; + } + + public void setRequired(Boolean required) { + isRequired = required; + } + + public String getDataType() { + return dataType; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + + public String getCurrentValue() { + return currentValue; + } + + public void setCurrentValue(String currentValue) { + this.currentValue = currentValue; + } + + public String getValidationRule() { + return validationRule; + } + + public void setValidationRule(String validationRule) { + this.validationRule = validationRule; + } +} diff --git a/src/main/java/de/avatic/lcc/dto/packaging/post/PackagingDimensionPostDTO.java b/src/main/java/de/avatic/lcc/dto/packaging/post/PackagingDimensionPostDTO.java new file mode 100644 index 0000000..64e7db3 --- /dev/null +++ b/src/main/java/de/avatic/lcc/dto/packaging/post/PackagingDimensionPostDTO.java @@ -0,0 +1,113 @@ +package de.avatic.lcc.dto.packaging.post; + +import com.fasterxml.jackson.annotation.JsonProperty; +import de.avatic.lcc.model.packaging.PackagingType; +import de.avatic.lcc.model.utils.DimensionUnit; +import de.avatic.lcc.model.utils.WeightUnit; + +public class PackagingDimensionPostDTO { + + private Integer id; + + private PackagingType type; + + private Double length; + + private Double width; + + private Double height; + + @JsonProperty("dimension_unit") + private DimensionUnit dimensionUnit; + + private Double weight; + + @JsonProperty("weight_unit") + private WeightUnit weightUnit; + + @JsonProperty("content_unit_count") + private Integer contentUnitCount; + + @JsonProperty("is_deprecated") + private Boolean isDeprecated; + + public PackagingType getType() { + return type; + } + + public void setType(PackagingType type) { + this.type = type; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Double getLength() { + return length; + } + + public void setLength(Double length) { + this.length = length; + } + + public Double getWidth() { + return width; + } + + public void setWidth(Double width) { + this.width = width; + } + + public Double getHeight() { + return height; + } + + public void setHeight(Double height) { + this.height = height; + } + + public DimensionUnit getDimensionUnit() { + return dimensionUnit; + } + + public void setDimensionUnit(DimensionUnit dimensionUnit) { + this.dimensionUnit = dimensionUnit; + } + + public Double getWeight() { + return weight; + } + + public void setWeight(Double weight) { + this.weight = weight; + } + + public WeightUnit getWeightUnit() { + return weightUnit; + } + + public void setWeightUnit(WeightUnit weightUnit) { + this.weightUnit = weightUnit; + } + + public Integer getContentUnitCount() { + return contentUnitCount; + } + + public void setContentUnitCount(Integer contentUnitCount) { + this.contentUnitCount = contentUnitCount; + } + + public Boolean getDeprecated() { + return isDeprecated; + } + + public void setDeprecated(Boolean deprecated) { + isDeprecated = deprecated; + } +} diff --git a/src/main/java/de/avatic/lcc/dto/packaging/post/PackagingPostDTO.java b/src/main/java/de/avatic/lcc/dto/packaging/post/PackagingPostDTO.java index 44cfb4c..5e1af3e 100644 --- a/src/main/java/de/avatic/lcc/dto/packaging/post/PackagingPostDTO.java +++ b/src/main/java/de/avatic/lcc/dto/packaging/post/PackagingPostDTO.java @@ -1,9 +1,9 @@ package de.avatic.lcc.dto.packaging.post; import com.fasterxml.jackson.annotation.JsonProperty; -import de.avatic.lcc.dto.packaging.get.PackagingDimensionGetDTO; -import de.avatic.lcc.dto.packaging.get.PackagingMaterialGetDTO; -import de.avatic.lcc.dto.packaging.get.PackagingSupplierGetDTO; + +import java.util.List; +import java.util.Map; public class PackagingPostDTO { @@ -18,10 +18,13 @@ public class PackagingPostDTO { private Integer materialId; @JsonProperty("handling_unit") - private PackagingDimensionGetDTO hu; + private PackagingDimensionPostDTO hu; @JsonProperty("small_handling_unit") - private PackagingDimensionGetDTO shu; + private PackagingDimensionPostDTO shu; + + @JsonProperty("properties") + private Map properties; public Integer getId() { return id; @@ -55,19 +58,27 @@ public class PackagingPostDTO { this.materialId = materialId; } - public PackagingDimensionGetDTO getHu() { + public PackagingDimensionPostDTO getHu() { return hu; } - public void setHu(PackagingDimensionGetDTO hu) { + public void setHu(PackagingDimensionPostDTO hu) { this.hu = hu; } - public PackagingDimensionGetDTO getShu() { + public PackagingDimensionPostDTO getShu() { return shu; } - public void setShu(PackagingDimensionGetDTO shu) { + public void setShu(PackagingDimensionPostDTO shu) { this.shu = shu; } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } } diff --git a/src/main/java/de/avatic/lcc/dto/properties/post/PropertiesPostDTO.java b/src/main/java/de/avatic/lcc/dto/properties/post/PropertiesPostDTO.java new file mode 100644 index 0000000..8cb67c7 --- /dev/null +++ b/src/main/java/de/avatic/lcc/dto/properties/post/PropertiesPostDTO.java @@ -0,0 +1,7 @@ +package de.avatic.lcc.dto.properties.post; + +public class PropertiesPostDTO { + + String externalMappingId; + String value; +} diff --git a/src/main/java/de/avatic/lcc/model/packaging/PackagingProperty.java b/src/main/java/de/avatic/lcc/model/packaging/PackagingProperty.java index 1902bfb..3b15df6 100644 --- a/src/main/java/de/avatic/lcc/model/packaging/PackagingProperty.java +++ b/src/main/java/de/avatic/lcc/model/packaging/PackagingProperty.java @@ -13,6 +13,39 @@ public class PackagingProperty { private String propertyValue; - private AggregateReference packagingPropertyType; + private Integer packagingId; + private PackagingPropertyType packagingPropertyType; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getPropertyValue() { + return propertyValue; + } + + public void setPropertyValue(String propertyValue) { + this.propertyValue = propertyValue; + } + + public Integer getPackagingId() { + return packagingId; + } + + public void setPackagingId(Integer packagingId) { + this.packagingId = packagingId; + } + + public PackagingPropertyType getPackagingPropertyType() { + return packagingPropertyType; + } + + public void setPackagingPropertyType(PackagingPropertyType packagingPropertyType) { + this.packagingPropertyType = packagingPropertyType; + } } diff --git a/src/main/java/de/avatic/lcc/model/packaging/PackagingPropertyType.java b/src/main/java/de/avatic/lcc/model/packaging/PackagingPropertyType.java index 8e00ae6..1d176af 100644 --- a/src/main/java/de/avatic/lcc/model/packaging/PackagingPropertyType.java +++ b/src/main/java/de/avatic/lcc/model/packaging/PackagingPropertyType.java @@ -12,10 +12,9 @@ import org.springframework.data.relational.core.mapping.Table; * Represents the type of a property used in packaging. * This includes details such as its name, data type, validation rules, and whether the property is required. */ -@Table("packaging_property_type") public class PackagingPropertyType { - @Id + /** * Unique identifier for the packaging property type. */ @@ -50,4 +49,55 @@ public class PackagingPropertyType { */ private Boolean isRequired; + @Size(max = 16) + private String externalMappingId; + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public PropertyDataType getDataType() { + return dataType; + } + + public void setDataType(PropertyDataType dataType) { + this.dataType = dataType; + } + + public String getValidationRule() { + return validationRule; + } + + public void setValidationRule(String validationRule) { + this.validationRule = validationRule; + } + + public Boolean getRequired() { + return isRequired; + } + + public void setRequired(Boolean required) { + isRequired = required; + } + + public String getExternalMappingId() { + return externalMappingId; + } + + public void setExternalMappingId(String externalMappingId) { + this.externalMappingId = externalMappingId; + } } diff --git a/src/main/java/de/avatic/lcc/model/properties/CountryProperty.java b/src/main/java/de/avatic/lcc/model/properties/CountryProperty.java index 9350d08..c93e120 100644 --- a/src/main/java/de/avatic/lcc/model/properties/CountryProperty.java +++ b/src/main/java/de/avatic/lcc/model/properties/CountryProperty.java @@ -10,28 +10,22 @@ import org.springframework.data.relational.core.mapping.Table; public class CountryProperty { + private Integer id; - private String activeValue; - - private String draftValue; + private String value; private CountryPropertyType type; + private Integer countryId; - public String getActiveValue() { - return activeValue; + private PropertySet propertySet; + + public String getValue() { + return value; } - public void setActiveValue(String activeValue) { - this.activeValue = activeValue; - } - - public String getDraftValue() { - return draftValue; - } - - public void setDraftValue(String draftValue) { - this.draftValue = draftValue; + public void setValue(String value) { + this.value = value; } public CountryPropertyType getType() { @@ -41,4 +35,20 @@ public class CountryProperty { public void setType(CountryPropertyType type) { this.type = type; } + + public Integer getCountryId() { + return countryId; + } + + public void setCountryId(Integer countryId) { + this.countryId = countryId; + } + + public PropertySet getPropertySet() { + return propertySet; + } + + public void setPropertySet(PropertySet propertySet) { + this.propertySet = propertySet; + } } diff --git a/src/main/java/de/avatic/lcc/model/properties/CountryPropertyType.java b/src/main/java/de/avatic/lcc/model/properties/CountryPropertyType.java index affd2ac..82341f5 100644 --- a/src/main/java/de/avatic/lcc/model/properties/CountryPropertyType.java +++ b/src/main/java/de/avatic/lcc/model/properties/CountryPropertyType.java @@ -9,7 +9,6 @@ import org.springframework.data.relational.core.mapping.Table; public class CountryPropertyType { - private Integer id; @NotNull diff --git a/src/main/java/de/avatic/lcc/model/properties/PropertySet.java b/src/main/java/de/avatic/lcc/model/properties/PropertySet.java index 59ff99d..07fc103 100644 --- a/src/main/java/de/avatic/lcc/model/properties/PropertySet.java +++ b/src/main/java/de/avatic/lcc/model/properties/PropertySet.java @@ -4,6 +4,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.relational.core.mapping.MappedCollection; import org.springframework.data.relational.core.mapping.Table; +import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.util.Set; @@ -14,17 +15,42 @@ public class PropertySet { @Id private Integer id; - private OffsetDateTime startDate; + private LocalDateTime startDate; - private OffsetDateTime endDate; + private LocalDateTime endDate; private PropertySetState state; - @MappedCollection(idColumn = "property_set_id") - private Set systemProperties; - @MappedCollection(idColumn = "property_set_id") - private Set countryProperties; + public Integer getId() { + return id; + } + public void setId(Integer id) { + this.id = id; + } + public LocalDateTime getStartDate() { + return startDate; + } + + public void setStartDate(LocalDateTime startDate) { + this.startDate = startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + public void setEndDate(LocalDateTime endDate) { + this.endDate = endDate; + } + + public PropertySetState getState() { + return state; + } + + public void setState(PropertySetState state) { + this.state = state; + } } diff --git a/src/main/java/de/avatic/lcc/model/properties/PropertyType.java b/src/main/java/de/avatic/lcc/model/properties/PropertyType.java new file mode 100644 index 0000000..421b9f8 --- /dev/null +++ b/src/main/java/de/avatic/lcc/model/properties/PropertyType.java @@ -0,0 +1,5 @@ +package de.avatic.lcc.model.properties; + +public enum PropertyType { + COUNTRY, SYSTEM, PACKAGING +} diff --git a/src/main/java/de/avatic/lcc/repositories/country/CountryPropertyRepository.java b/src/main/java/de/avatic/lcc/repositories/country/CountryPropertyRepository.java deleted file mode 100644 index c6c95bb..0000000 --- a/src/main/java/de/avatic/lcc/repositories/country/CountryPropertyRepository.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.avatic.lcc.repositories.country; - -import de.avatic.lcc.model.properties.CountryProperty; -import de.avatic.lcc.model.properties.CountryPropertyType; -import de.avatic.lcc.model.properties.PropertyDataType; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class CountryPropertyRepository { - - private final JdbcTemplate jdbcTemplate; - - public CountryPropertyRepository(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - public List listByCountryId(Integer id) { - - String query = """ - SELECT draft.id AS draft_id, active.id AS active_id, active.property_value AS avtice_value, draft.property_value AS draft_value, - type.id AS type_id, type.name AS name, type.data_type AS data_type, type.is_required AS is_required, - type.external_mapping_id AS external_mapping_id, type.validation_rule AS validation_rule - FROM country_property active - LEFT JOIN country_property_type type on active.country_property_type_id = type.id - LEFT JOIN country_property draft on active.id = draft.id - LEFT JOIN property_set active_set on active.property_set_id = active_set.id - LEFT JOIN property_set draft_set on draft.property_set_id = draft_set.id - WHERE active.country_id = ? AND active_set.state = 'VALID' AND draft_set.state = 'DRAFT'"""; - - return jdbcTemplate.query(query, (rs, rowNum) -> { - CountryProperty entity = new CountryProperty(); - CountryPropertyType type = new CountryPropertyType(); - - int idActive = rs.getInt("active_id"); - int idDraft = rs.getInt("draft_id"); - - type.setId(rs.getInt("type_id")); - type.setName(rs.getString("name")); - type.setDataType(PropertyDataType.valueOf(rs.getString("data_type"))); - type.setRequired(rs.getBoolean("is_required")); - type.setExternalMappingId(rs.getString("external_mapping_id")); - type.setValidationRule(rs.getString("validation_rule")); - - entity.setActiveValue(rs.getString("active_value")); - entity.setDraftValue(rs.getString("draft_value")); - entity.setType(type); - - return entity; - }, id); - - - } -} diff --git a/src/main/java/de/avatic/lcc/repositories/packaging/PackagingPropertyRepository.java b/src/main/java/de/avatic/lcc/repositories/packaging/PackagingPropertyRepository.java deleted file mode 100644 index be4e146..0000000 --- a/src/main/java/de/avatic/lcc/repositories/packaging/PackagingPropertyRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.avatic.lcc.repositories.packaging; - -import org.springframework.stereotype.Repository; - -@Repository -public class PackagingPropertyRepository { -} diff --git a/src/main/java/de/avatic/lcc/repositories/properties/CountryPropertiesRepository.java b/src/main/java/de/avatic/lcc/repositories/properties/CountryPropertiesRepository.java new file mode 100644 index 0000000..a25ae3d --- /dev/null +++ b/src/main/java/de/avatic/lcc/repositories/properties/CountryPropertiesRepository.java @@ -0,0 +1,94 @@ +package de.avatic.lcc.repositories.properties; + +import de.avatic.lcc.model.properties.*; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +public class CountryPropertiesRepository { + + private final JdbcTemplate jdbcTemplate; + + public CountryPropertiesRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + + + @Transactional + public List listByCountryId(Integer id) { + + String query = """ + SELECT p.id as id, p.country_id as country_id, p.property_value as value, + ps.id as property_set_id, ps.start_date as property_set_start_date, ps.end_date as property_set_end_date, ps.state as property_set_state, + type.id as type_id, type.name as type_name, type.data_type as type_data_type, type.is_required as type_is_required, type.external_mapping_id as type_external_mapping_id, type.validation_rule as type_validation_rule + FROM country_property p + LEFT JOIN country_property_type type on p.country_property_type_id = type.id + LEFT JOIN property_set ps on p.property_set_id = ps.id + WHERE p.country_id = ? AND ps.state = 'VALID' OR ps.state = 'DRAFT'"""; + + return jdbcTemplate.query(query, (rs, rowNum) -> { + CountryProperty entity = new CountryProperty(); + CountryPropertyType type = new CountryPropertyType(); + PropertySet propertySet = new PropertySet(); + + propertySet.setId(rs.getInt("property_set_id")); + propertySet.setStartDate(rs.getTimestamp("property_set_start_date").toLocalDateTime()); + propertySet.setEndDate(rs.getTimestamp("property_set_end_date").toLocalDateTime()); + propertySet.setState(PropertySetState.valueOf(rs.getString("property_set_state"))); + + type.setId(rs.getInt("type_id")); + type.setName(rs.getString("type_name")); + type.setDataType(PropertyDataType.valueOf(rs.getString("type_data_type"))); + type.setRequired(rs.getBoolean("type_is_required")); + type.setExternalMappingId(rs.getString("type_external_mapping_id")); + type.setValidationRule(rs.getString("type_validation_rule")); + + entity.setCountryId(id); + entity.setType(type); + entity.setPropertySet(propertySet); + entity.setValue(rs.getString("value")); + + return entity; + }, id); + } + + public void update(CountryProperty entity) { + + } + + @Transactional + public List listTypes() { + String query = """ + SELECT * FROM country_property_type + """; + + return jdbcTemplate.query(query, (rs, rowNum) -> { + CountryPropertyType type = new CountryPropertyType(); + + type.setId(rs.getInt("id")); + type.setName(rs.getString("name")); + type.setDataType(PropertyDataType.valueOf(rs.getString("data_type"))); + type.setRequired(rs.getBoolean("is_required")); + type.setExternalMappingId(rs.getString("external_mapping_id")); + type.setValidationRule(rs.getString("validation_rule")); + + return type; + }); + + } + + + public void update(Integer countryId, Integer typeId, Integer propertySetId, String value) { + + String query = """ + INSERT INTO country_property (property_value, property_set_id, country_property_type_id, country_id) VALUES (?, ?, ?, ?) + ON DUPLICATE KEY UPDATE property_value = ?"""; + + jdbcTemplate.update(query, value, propertySetId, typeId, countryId, value); + + } +} diff --git a/src/main/java/de/avatic/lcc/repositories/properties/PackagingPropertiesRepository.java b/src/main/java/de/avatic/lcc/repositories/properties/PackagingPropertiesRepository.java new file mode 100644 index 0000000..88729af --- /dev/null +++ b/src/main/java/de/avatic/lcc/repositories/properties/PackagingPropertiesRepository.java @@ -0,0 +1,80 @@ +package de.avatic.lcc.repositories.properties; + +import de.avatic.lcc.model.packaging.PackagingProperty; +import de.avatic.lcc.model.packaging.PackagingPropertyType; +import de.avatic.lcc.model.properties.CountryPropertyType; +import de.avatic.lcc.model.properties.PropertyDataType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class PackagingPropertiesRepository { + + private final JdbcTemplate jdbcTemplate; + + public PackagingPropertiesRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List getByPackagingId(Integer id) { + + String query = """ + SELECT property.id as id, property.property_value AS value, property.packaging_id as packaging_id, + type.name AS type_name, type.data_type AS type_data_type, type.is_required AS type_is_required, + type.external_mapping_id AS type_external_mapping_id, type.validation_rule AS type_validation_rule + FROM packaging_property property LEFT JOIN packaging_property_type type ON property.packaging_property_type_id = type.id WHERE packaging_id = ?"""; + + return jdbcTemplate.query(query, (rs, rowNum) -> { + + PackagingProperty property = new PackagingProperty(); + PackagingPropertyType type = new PackagingPropertyType(); + + type.setId(rs.getInt("type_id")); + type.setName(rs.getString("type_name")); + type.setDataType(PropertyDataType.valueOf(rs.getString("type_data_type"))); + type.setRequired(rs.getBoolean("type_is_required")); + type.setExternalMappingId(rs.getString("type_external_mapping_id")); + type.setValidationRule(rs.getString("type_validation_rule")); + + property.setPackagingPropertyType(type); + property.setId(rs.getInt("id")); + property.setPackagingId(rs.getInt("packaging_id")); + property.setPropertyValue(rs.getString("value")); + + return property; + }, id); + + } + + + + public List listTypes() { + String query = """ + SELECT * FROM packaging_property_type + """; + + return jdbcTemplate.query(query, (rs, rowNum) -> { + PackagingPropertyType type = new PackagingPropertyType(); + + type.setId(rs.getInt("id")); + type.setName(rs.getString("name")); + type.setDataType(PropertyDataType.valueOf(rs.getString("data_type"))); + type.setRequired(rs.getBoolean("is_required")); + type.setExternalMappingId(rs.getString("external_mapping_id")); + type.setValidationRule(rs.getString("validation_rule")); + + return type; + }); + } + + + public void update(Integer packagingId, Integer 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); + } +} diff --git a/src/main/java/de/avatic/lcc/repositories/properties/SystemPropertiesRepository.java b/src/main/java/de/avatic/lcc/repositories/properties/SystemPropertiesRepository.java new file mode 100644 index 0000000..1db7a68 --- /dev/null +++ b/src/main/java/de/avatic/lcc/repositories/properties/SystemPropertiesRepository.java @@ -0,0 +1,71 @@ +package de.avatic.lcc.repositories.properties; + +import de.avatic.lcc.model.properties.*; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.util.List; +import java.util.Objects; + + +@Repository +public class SystemPropertiesRepository { + + private final JdbcTemplate jdbcTemplate; + + public SystemPropertiesRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @Transactional + public PropertySet getDraftSet() { + createSet(); + + String query = "SELECT id, start_date, end_date, state FROM property_set WHERE state = ?"; + + return jdbcTemplate.queryForObject(query, (rs, rowNum) -> { + PropertySet propertySet = new PropertySet(); + + propertySet.setId(rs.getInt("id")); + propertySet.setStartDate(rs.getTimestamp("start_date").toLocalDateTime()); + propertySet.setEndDate(rs.getTimestamp("end_date").toLocalDateTime()); + + return propertySet; + + }, PropertySetState.DRAFT.name()); + } + + @Transactional + public boolean hasDraftSet() { + Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM property_set WHERE state = ?", Integer.class, PropertySetState.DRAFT.name()); + return !(count == null || count == 0); + } + + + private void createSet() { + String query = "INSERT INTO property_set (state) SELECT ? WHERE NOT EXISTS (SELECT 1 FROM property_set WHERE state = ?)"; + jdbcTemplate.update(query, PropertySetState.DRAFT.name(), PropertySetState.DRAFT.name()); + } + + private List getSystemPropertyTypes() { + return jdbcTemplate.query("SELECT * FROM system_property_type", (rs, rowNum) -> { + SystemPropertyType systemPropertyType = new SystemPropertyType(); + + systemPropertyType.setId(rs.getInt("id")); + systemPropertyType.setName(rs.getString("name")); + systemPropertyType.setDataType(PropertyDataType.valueOf(rs.getString("data_type"))); + systemPropertyType.setExternalMappingId(rs.getString("external_mapping_id")); + systemPropertyType.setValidationRule(rs.getString("validation_rule")); + + return systemPropertyType; + }); + } + + + +} diff --git a/src/main/java/de/avatic/lcc/service/CountryService.java b/src/main/java/de/avatic/lcc/service/CountryService.java index 6c2a8db..c8cade0 100644 --- a/src/main/java/de/avatic/lcc/service/CountryService.java +++ b/src/main/java/de/avatic/lcc/service/CountryService.java @@ -2,30 +2,35 @@ package de.avatic.lcc.service; import de.avatic.lcc.dto.countries.get.CountryGetDTO; import de.avatic.lcc.dto.countries.get.CountryListGetDTO; +import de.avatic.lcc.dto.countries.post.CountryPostDTO; import de.avatic.lcc.model.country.Country; import de.avatic.lcc.model.properties.CountryProperty; -import de.avatic.lcc.repositories.country.CountryPropertyRepository; +import de.avatic.lcc.model.properties.CountryPropertyType; +import de.avatic.lcc.model.properties.PropertySet; +import de.avatic.lcc.repositories.properties.CountryPropertiesRepository; import de.avatic.lcc.repositories.country.CountryRepository; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import de.avatic.lcc.repositories.properties.SystemPropertiesRepository; import de.avatic.lcc.service.transformer.CountryTransformerService; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service public class CountryService { - - private final CountryRepository countryRepository; private final CountryTransformerService countryTransformerService; - private final CountryPropertyRepository countryPropertyRepository; + private final CountryPropertiesRepository countryPropertiesRepository; + private final SystemPropertiesRepository systemPropertiesRepository; - public CountryService(CountryRepository countryRepository, CountryTransformerService countryTransformerService, CountryPropertyRepository countryPropertyRepository) { + public CountryService(CountryRepository countryRepository, CountryTransformerService countryTransformerService, CountryPropertiesRepository countryPropertiesRepository, SystemPropertiesRepository systemPropertiesRepository) { this.countryRepository = countryRepository; this.countryTransformerService = countryTransformerService; - this.countryPropertyRepository = countryPropertyRepository; + this.countryPropertiesRepository = countryPropertiesRepository; + this.systemPropertiesRepository = systemPropertiesRepository; } public SearchQueryResult listMaterial(String filter, int page, int limit) { @@ -46,7 +51,20 @@ public class CountryService { } public CountryGetDTO getCountry(Integer id) { - List properties = countryPropertyRepository.listByCountryId(id); + List properties = countryPropertiesRepository.listByCountryId(id); return countryTransformerService.convertToCountryGetDTO(countryRepository.getById(id), properties).orElseThrow(); } + + @Transactional + public void updateCountry(Integer id, CountryPostDTO dto) { + List types = countryPropertiesRepository.listTypes(); + PropertySet set = systemPropertiesRepository.getDraftSet(); + + for(CountryPropertyType type : types) { + var value = dto.getProperties().get(type.getExternalMappingId()); + if(value != null) { + countryPropertiesRepository.update(id, type.getId(), set.getId(), value); + } + } + } } diff --git a/src/main/java/de/avatic/lcc/service/PackagingService.java b/src/main/java/de/avatic/lcc/service/PackagingService.java index a089754..82866b2 100644 --- a/src/main/java/de/avatic/lcc/service/PackagingService.java +++ b/src/main/java/de/avatic/lcc/service/PackagingService.java @@ -7,13 +7,18 @@ import de.avatic.lcc.model.materials.Material; import de.avatic.lcc.model.nodes.Node; import de.avatic.lcc.model.packaging.Packaging; import de.avatic.lcc.model.packaging.PackagingDimension; -import de.avatic.lcc.repositories.country.CountryRepository; +import de.avatic.lcc.model.packaging.PackagingProperty; +import de.avatic.lcc.model.packaging.PackagingPropertyType; +import de.avatic.lcc.model.properties.CountryPropertyType; +import de.avatic.lcc.model.properties.PropertySet; import de.avatic.lcc.repositories.MaterialRepository; import de.avatic.lcc.repositories.NodeRepository; +import de.avatic.lcc.repositories.country.CountryRepository; import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository; import de.avatic.lcc.repositories.packaging.PackagingRepository; import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; +import de.avatic.lcc.repositories.properties.PackagingPropertiesRepository; import de.avatic.lcc.service.transformer.DimensionTransformerService; import de.avatic.lcc.service.transformer.NodeTransformerService; import de.avatic.lcc.service.transformer.PackagingTransformerService; @@ -32,14 +37,16 @@ public class PackagingService { private final MaterialRepository materialRepository; private final CountryRepository countryRepository; private final PackagingTransformerService packagingTransformerService; + private final PackagingPropertiesRepository packagingPropertiesRepository; - public PackagingService(PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, NodeRepository nodeRepository, MaterialRepository materialRepository, DimensionTransformerService dimensionTransformerService, NodeTransformerService nodeTransformerService, CountryRepository countryRepository, PackagingTransformerService packagingTransformerService) { + public PackagingService(PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, NodeRepository nodeRepository, MaterialRepository materialRepository, DimensionTransformerService dimensionTransformerService, NodeTransformerService nodeTransformerService, CountryRepository countryRepository, PackagingTransformerService packagingTransformerService, PackagingPropertiesRepository packagingPropertiesRepository) { this.packagingRepository = packagingRepository; this.packagingDimensionRepository = packagingDimensionRepository; this.nodeRepository = nodeRepository; this.materialRepository = materialRepository; this.countryRepository = countryRepository; this.packagingTransformerService = packagingTransformerService; + this.packagingPropertiesRepository = packagingPropertiesRepository; } @Transactional @@ -62,7 +69,7 @@ public class PackagingService { }).toList(); - return new SearchQueryResult<>(dto, queryResult.getPage(), queryResult.getTotalElements(), queryResult.getElementsPerPage() ); + return new SearchQueryResult<>(dto, queryResult.getPage(), queryResult.getTotalElements(), queryResult.getElementsPerPage()); } @Transactional @@ -74,25 +81,36 @@ public class PackagingService { Optional country = countryRepository.getById(supplier.orElseThrow().getCountryId()); Optional hu = packagingDimensionRepository.getById(packaging.orElseThrow().getHuId()); Optional shu = packagingDimensionRepository.getById(packaging.orElseThrow().getShuId()); + List properties = packagingPropertiesRepository.getByPackagingId(id); - //TODO packaging properties. - return packagingTransformerService.convertToPackagingGetDTO(packaging, material, supplier, country, hu, shu).orElseThrow(); + return packagingTransformerService.convertToPackagingGetDTO(packaging, material, supplier, country, hu, shu, properties).orElseThrow(); } @Transactional public void updatePackaging(Integer id, PackagingPostDTO dto) { Optional entity = packagingRepository.getById(id); - if(entity.isEmpty()) throw new RuntimeException("Packaging does not exists " + id); + if (entity.isEmpty()) throw new RuntimeException("Packaging does not exists " + id); // check integrity Check.equals(dto.getHu().getId(), entity.get().getHuId()); Check.equals(dto.getHu().getId(), entity.get().getHuId()); Check.equals(dto.getId(), id); - packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getHu())); - packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getShu())); + packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getHu())); + packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getShu())); + + List types = packagingPropertiesRepository.listTypes(); + + + for(PackagingPropertyType type : types) { + var value = dto.getProperties().get(type.getExternalMappingId()); + if(value != null) { + packagingPropertiesRepository.update(id, type.getId(), value); + } + } + packagingRepository.update(packagingTransformerService.convertFromPackagingPostDTO(dto)); } @@ -103,8 +121,9 @@ public class PackagingService { @Transactional public Integer createPackaging(PackagingPostDTO dto) { - Optional huId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getHu())); - Optional shuId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getShu())); + Optional huId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getHu())); + Optional shuId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getShu())); + Packaging entity = packagingTransformerService.convertFromPackagingPostDTO(dto); entity.setHuId(huId.orElseThrow()); diff --git a/src/main/java/de/avatic/lcc/service/PropertiesService.java b/src/main/java/de/avatic/lcc/service/PropertiesService.java new file mode 100644 index 0000000..ee9ee26 --- /dev/null +++ b/src/main/java/de/avatic/lcc/service/PropertiesService.java @@ -0,0 +1,26 @@ +package de.avatic.lcc.service; + +import de.avatic.lcc.dto.properties.post.PropertiesPostDTO; +import de.avatic.lcc.model.properties.PropertyType; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PropertiesService { + + public void setProperties(String type, List property) { + PropertyType propertyType = PropertyType.valueOf(type); + + switch (propertyType) { + case SYSTEM: + + break; + case COUNTRY: + break; + case PACKAGING: + break; + } + + } +} diff --git a/src/main/java/de/avatic/lcc/service/transformer/CountryTransformerService.java b/src/main/java/de/avatic/lcc/service/transformer/CountryTransformerService.java index 35eb0c4..3e0c9e1 100644 --- a/src/main/java/de/avatic/lcc/service/transformer/CountryTransformerService.java +++ b/src/main/java/de/avatic/lcc/service/transformer/CountryTransformerService.java @@ -5,6 +5,7 @@ import de.avatic.lcc.dto.countries.get.CountryGetDTO; import de.avatic.lcc.dto.countries.get.CountryPropertyGetDTO; import de.avatic.lcc.model.country.Country; import de.avatic.lcc.model.properties.CountryProperty; +import de.avatic.lcc.model.properties.PropertySetState; import org.springframework.stereotype.Service; import java.util.List; @@ -26,16 +27,18 @@ public class CountryTransformerService { dto.setName(entity.getIsoCode().getFullName()); dto.setId(entity.getId()); - dto.setProperties(properties.stream().map(p -> { + dto.setProperties(properties.stream().filter(p -> p.getPropertySet().getState().equals(PropertySetState.VALID)).map(p -> { CountryPropertyGetDTO dtoEntry = new CountryPropertyGetDTO(); - dtoEntry.setCurrentValue(p.getActiveValue()); - dtoEntry.setDraftValue(p.getDraftValue()); + Optional draft = properties.stream().filter(d -> d.getPropertySet().getState().equals(PropertySetState.DRAFT) && d.getType().getExternalMappingId().equals(p.getType().getExternalMappingId())).findFirst(); + + dtoEntry.setCurrentValue(p.getValue()); + draft.ifPresent(countryProperty -> dtoEntry.setDraftValue(countryProperty.getValue())); dtoEntry.setRequired(p.getType().getRequired()); - dtoEntry.setId(p.getType().getId()); dtoEntry.setName(p.getType().getName()); dtoEntry.setExternalMappingId(p.getType().getExternalMappingId()); dtoEntry.setDataType(p.getType().getDataType().name()); + dtoEntry.setValidationRule(p.getType().getValidationRule()); return dtoEntry; }).toList()); @@ -43,4 +46,5 @@ public class CountryTransformerService { return Optional.of(dto); } + } diff --git a/src/main/java/de/avatic/lcc/service/transformer/PackagingTransformerService.java b/src/main/java/de/avatic/lcc/service/transformer/PackagingTransformerService.java index 2a4caef..214f2c0 100644 --- a/src/main/java/de/avatic/lcc/service/transformer/PackagingTransformerService.java +++ b/src/main/java/de/avatic/lcc/service/transformer/PackagingTransformerService.java @@ -2,15 +2,18 @@ package de.avatic.lcc.service.transformer; import de.avatic.lcc.dto.generic.NodeTypeDTO; import de.avatic.lcc.dto.packaging.get.*; +import de.avatic.lcc.dto.packaging.post.PackagingDimensionPostDTO; import de.avatic.lcc.dto.packaging.post.PackagingPostDTO; import de.avatic.lcc.model.country.Country; import de.avatic.lcc.model.materials.Material; import de.avatic.lcc.model.nodes.Node; import de.avatic.lcc.model.packaging.Packaging; import de.avatic.lcc.model.packaging.PackagingDimension; +import de.avatic.lcc.model.packaging.PackagingProperty; import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.List; import java.util.Optional; @Service @@ -92,7 +95,7 @@ public class PackagingTransformerService { return Optional.of(dto); } - public Optional convertToPackagingGetDTO(Optional packaging, Optional material, Optional supplier, Optional country, Optional hu, Optional shu) { + public Optional convertToPackagingGetDTO(Optional packaging, Optional material, Optional supplier, Optional country, Optional hu, Optional shu, List properties) { if(packaging.isEmpty()) return Optional.empty(); Packaging data = packaging.get(); @@ -104,10 +107,24 @@ public class PackagingTransformerService { dto.setHu(convertToPackagingDimensionDTO(hu).orElseThrow()); dto.setShu(convertToPackagingDimensionDTO(shu).orElseThrow()); dto.setDeprecated(data.getDeprecated()); + dto.setProperties(properties.stream().map(this::convertToPackagingPropertyGetDTO).toList()); return Optional.of(dto); } + private PackagingPropertyGetDTO convertToPackagingPropertyGetDTO(PackagingProperty property) { + PackagingPropertyGetDTO dto = new PackagingPropertyGetDTO(); + + dto.setCurrentValue(property.getPropertyValue()); + dto.setDataType(property.getPackagingPropertyType().getDataType().name()); + dto.setRequired(property.getPackagingPropertyType().getRequired()); + dto.setName(property.getPackagingPropertyType().getName()); + dto.setExternalMappingId(property.getPackagingPropertyType().getExternalMappingId()); + dto.setValidationRule(property.getPackagingPropertyType().getValidationRule()); + + return dto; + } + public Packaging convertFromPackagingPostDTO(PackagingPostDTO dto) { var entity = new Packaging(); @@ -121,7 +138,24 @@ public class PackagingTransformerService { return entity; } - public PackagingDimension convertFromPackagingDimensionDTO(PackagingDimensionGetDTO dto) { + public PackagingDimension convertFromPackagingDimensionGetDTO(PackagingDimensionGetDTO dto) { + + var entity = new PackagingDimension(); + entity.setId(dto.getId()); + entity.setType(dto.getType()); + entity.setLength(dto.getDimensionUnit().convertToMM(dto.getLength()).intValue()); + entity.setWidth(dto.getDimensionUnit().convertToMM(dto.getWidth()).intValue()); + entity.setHeight(dto.getDimensionUnit().convertToMM(dto.getHeight()).intValue()); + entity.setDimensionUnit(dto.getDimensionUnit()); + entity.setWeight(dto.getWeightUnit().convertToG(dto.getWeight()).intValue()); + entity.setWeightUnit(dto.getWeightUnit()); + entity.setContentUnitCount(dto.getContentUnitCount()); + entity.setDeprecated(dto.getDeprecated()); + + return entity; + } + + public PackagingDimension convertFromPackagingDimensionPostDTO(PackagingDimensionPostDTO dto) { var entity = new PackagingDimension(); entity.setId(dto.getId()); @@ -139,4 +173,14 @@ public class PackagingTransformerService { } + public List convertFromPackagingPropertyPostDTO(PackagingPropertiesPostDTO properties) { + + return properties.stream().map(p -> { + PackagingProperty entity = new PackagingProperty(); + + entity.set(); + + }).toList() + + } } diff --git a/src/main/java/de/avatic/lcc/service/transformer/PropertiesTransformerService.java b/src/main/java/de/avatic/lcc/service/transformer/PropertiesTransformerService.java new file mode 100644 index 0000000..d007b23 --- /dev/null +++ b/src/main/java/de/avatic/lcc/service/transformer/PropertiesTransformerService.java @@ -0,0 +1,9 @@ +package de.avatic.lcc.service.transformer; + +import org.springframework.stereotype.Service; + +@Service +public class PropertiesTransformerService { + + +} diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 3e5564b..9172b0f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -44,10 +44,9 @@ CREATE TABLE IF NOT EXISTS `country` `id` INT NOT NULL AUTO_INCREMENT, `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(128) NOT NULL, `is_deprecated` BOOLEAN NOT NULL DEFAULT FALSE, PRIMARY KEY (`id`), - UNIQUE INDEX `idx_country_iso_code` (`iso_code`), + UNIQUE KEY `uk_country_iso_code` (`iso_code`), CONSTRAINT `chk_country_region_code` CHECK (`region_code` IN ('EMEA', 'LATAM', 'APAC', 'NAM')) ) COMMENT 'Master data table for country information and regional classification'; @@ -76,7 +75,8 @@ CREATE TABLE IF NOT EXISTS `country_property` `property_value` VARCHAR(500), FOREIGN KEY (`country_id`) REFERENCES `country` (`id`), FOREIGN KEY (`country_property_type_id`) REFERENCES `country_property_type` (`id`), - FOREIGN KEY (`property_set_id`) REFERENCES `property_set` (`id`) + FOREIGN KEY (`property_set_id`) REFERENCES `property_set` (`id`), + UNIQUE KEY `idx_country_property` (`country_id`, `country_property_type_id`, `property_set_id`) ) COMMENT 'Stores country-specific property values with versioning support'; -- Main table for user information @@ -88,8 +88,8 @@ CREATE TABLE IF NOT EXISTS `sys_user` `firstname` VARCHAR(100) NOT NULL, `lastname` VARCHAR(100) NOT NULL, `is_active` BOOLEAN NOT NULL DEFAULT TRUE, - UNIQUE INDEX `idx_user_email` (`email`), - UNIQUE INDEX `idx_user_workday` (`workday_id`) + UNIQUE KEY `idx_user_email` (`email`), + UNIQUE KEY `idx_user_workday` (`workday_id`) ) COMMENT 'Stores basic information about system users'; -- Group definitions @@ -98,7 +98,7 @@ CREATE TABLE IF NOT EXISTS `sys_group` `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `group_name` VARCHAR(64) NOT NULL, `group_description` VARCHAR(128) NOT NULL, - UNIQUE INDEX `idx_group_name` (`group_name`) + UNIQUE KEY `idx_group_name` (`group_name`) ) COMMENT 'Defines user groups for access management'; -- Junction table for user-group assignments @@ -168,7 +168,7 @@ CREATE TABLE IF NOT EXISTS outbound_country_mapping country_id INT NOT NULL, FOREIGN KEY (node_id) REFERENCES node (id), FOREIGN KEY (country_id) REFERENCES country (id), - UNIQUE (node_id, country_id), + UNIQUE KEY uk_node_id_country_id (node_id, country_id), INDEX idx_node_id (node_id), INDEX idx_country_id (country_id) ); @@ -245,7 +245,7 @@ CREATE TABLE IF NOT EXISTS material hs_code CHAR(8), name VARCHAR(500) NOT NULL, is_deprecated BOOLEAN NOT NULL DEFAULT FALSE, - CONSTRAINT `chk_normalized_part_number` UNIQUE (`normalized_part_number`) + CONSTRAINT `uq_normalized_part_number` UNIQUE (`normalized_part_number`) ); CREATE TABLE IF NOT EXISTS packaging_dimension @@ -291,9 +291,11 @@ 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, `data_type` VARCHAR(16), `validation_rule` VARCHAR(64), `is_required` BOOLEAN NOT NULL DEFAULT FALSE, + UNIQUE KEY idx_packaging_property_type (`external_mapping_id`), CONSTRAINT `chk_packaging_data_type_values` CHECK (`data_type` IN ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', 'TEXT')) @@ -308,7 +310,8 @@ CREATE TABLE IF NOT EXISTS packaging_property FOREIGN KEY (packaging_property_type_id) REFERENCES packaging_property_type (id), FOREIGN KEY (packaging_id) REFERENCES packaging (id), INDEX idx_packaging_property_type_id (packaging_property_type_id), - INDEX idx_packaging_id (packaging_id) + INDEX idx_packaging_id (packaging_id), + UNIQUE KEY idx_packaging_property_unique (packaging_property_type_id, packaging_id) ); CREATE TABLE IF NOT EXISTS premiss