Add DTOs, repositories, and logic for properties management.

Introduced new DTOs for handling properties at the packaging and country levels, alongside corresponding repositories and property validation. Enhanced CountryService and PackagingService with update and retrieval logic for property values. Updated database schema to support unique constraints and property mapping.
This commit is contained in:
Jan 2025-03-29 21:14:03 +01:00
parent c5096b129b
commit b55aca0ddf
27 changed files with 843 additions and 138 deletions

View file

@ -2,6 +2,7 @@ package de.avatic.lcc.controller;
import de.avatic.lcc.dto.countries.get.CountryGetDTO; import de.avatic.lcc.dto.countries.get.CountryGetDTO;
import de.avatic.lcc.dto.countries.get.CountryListGetDTO; 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.repositories.pagination.SearchQueryResult;
import de.avatic.lcc.service.CountryService; import de.avatic.lcc.service.CountryService;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -38,4 +39,9 @@ public class CountryController {
public ResponseEntity<CountryGetDTO> getCountryDetails(@PathVariable Integer id) { public ResponseEntity<CountryGetDTO> getCountryDetails(@PathVariable Integer id) {
return ResponseEntity.ok(countryService.getCountry(id)); return ResponseEntity.ok(countryService.getCountry(id));
} }
public ResponseEntity<Void> updateCountry(@PathVariable Integer id, @RequestBody CountryPostDTO country) {
countryService.updateCountry(id, country);
return ResponseEntity.noContent().build();
}
} }

View file

@ -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<PropertiesPostDTO> 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));
}
}

View file

@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class CountryPropertyGetDTO { public class CountryPropertyGetDTO {
private Integer id;
private String name; private String name;
@JsonProperty("external_mapping_id") @JsonProperty("external_mapping_id")
@ -23,13 +21,8 @@ public class CountryPropertyGetDTO {
@JsonProperty("draft_value") @JsonProperty("draft_value")
private String draftValue; private String draftValue;
public Integer getId() { @JsonProperty("validation_rule")
return id; private String validationRule;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() { public String getName() {
return name; return name;
@ -78,4 +71,12 @@ public class CountryPropertyGetDTO {
public void setDraftValue(String draftValue) { public void setDraftValue(String draftValue) {
this.draftValue = draftValue; this.draftValue = draftValue;
} }
public void setValidationRule(String validationRule) {
this.validationRule = validationRule;
}
public String getValidationRule() {
return validationRule;
}
} }

View file

@ -0,0 +1,26 @@
package de.avatic.lcc.dto.countries.post;
import java.util.Map;
public class CountryPostDTO {
String id;
Map<String, String> properties;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
}

View file

@ -2,6 +2,8 @@ package de.avatic.lcc.dto.packaging.get;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class PackagingGetDTO { public class PackagingGetDTO {
@ -20,6 +22,8 @@ public class PackagingGetDTO {
@JsonProperty("small_handling_unit") @JsonProperty("small_handling_unit")
private PackagingDimensionGetDTO shu; private PackagingDimensionGetDTO shu;
private List<PackagingPropertyGetDTO> properties;
public Integer getId() { public Integer getId() {
return id; return id;
} }
@ -67,4 +71,12 @@ public class PackagingGetDTO {
public void setShu(PackagingDimensionGetDTO shu) { public void setShu(PackagingDimensionGetDTO shu) {
this.shu = shu; this.shu = shu;
} }
public List<PackagingPropertyGetDTO> getProperties() {
return properties;
}
public void setProperties(List<PackagingPropertyGetDTO> properties) {
this.properties = properties;
}
} }

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -1,9 +1,9 @@
package de.avatic.lcc.dto.packaging.post; package de.avatic.lcc.dto.packaging.post;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import de.avatic.lcc.dto.packaging.get.PackagingDimensionGetDTO;
import de.avatic.lcc.dto.packaging.get.PackagingMaterialGetDTO; import java.util.List;
import de.avatic.lcc.dto.packaging.get.PackagingSupplierGetDTO; import java.util.Map;
public class PackagingPostDTO { public class PackagingPostDTO {
@ -18,10 +18,13 @@ public class PackagingPostDTO {
private Integer materialId; private Integer materialId;
@JsonProperty("handling_unit") @JsonProperty("handling_unit")
private PackagingDimensionGetDTO hu; private PackagingDimensionPostDTO hu;
@JsonProperty("small_handling_unit") @JsonProperty("small_handling_unit")
private PackagingDimensionGetDTO shu; private PackagingDimensionPostDTO shu;
@JsonProperty("properties")
private Map<String, String> properties;
public Integer getId() { public Integer getId() {
return id; return id;
@ -55,19 +58,27 @@ public class PackagingPostDTO {
this.materialId = materialId; this.materialId = materialId;
} }
public PackagingDimensionGetDTO getHu() { public PackagingDimensionPostDTO getHu() {
return hu; return hu;
} }
public void setHu(PackagingDimensionGetDTO hu) { public void setHu(PackagingDimensionPostDTO hu) {
this.hu = hu; this.hu = hu;
} }
public PackagingDimensionGetDTO getShu() { public PackagingDimensionPostDTO getShu() {
return shu; return shu;
} }
public void setShu(PackagingDimensionGetDTO shu) { public void setShu(PackagingDimensionPostDTO shu) {
this.shu = shu; this.shu = shu;
} }
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
} }

View file

@ -0,0 +1,7 @@
package de.avatic.lcc.dto.properties.post;
public class PropertiesPostDTO {
String externalMappingId;
String value;
}

View file

@ -13,6 +13,39 @@ public class PackagingProperty {
private String propertyValue; private String propertyValue;
private AggregateReference<PackagingPropertyType,Integer> 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;
}
} }

View file

@ -12,10 +12,9 @@ import org.springframework.data.relational.core.mapping.Table;
* Represents the type of a property used in packaging. * 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. * This includes details such as its name, data type, validation rules, and whether the property is required.
*/ */
@Table("packaging_property_type")
public class PackagingPropertyType { public class PackagingPropertyType {
@Id
/** /**
* Unique identifier for the packaging property type. * Unique identifier for the packaging property type.
*/ */
@ -50,4 +49,55 @@ public class PackagingPropertyType {
*/ */
private Boolean isRequired; 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;
}
} }

View file

@ -10,28 +10,22 @@ import org.springframework.data.relational.core.mapping.Table;
public class CountryProperty { public class CountryProperty {
private Integer id;
private String activeValue; private String value;
private String draftValue;
private CountryPropertyType type; private CountryPropertyType type;
private Integer countryId;
public String getActiveValue() { private PropertySet propertySet;
return activeValue;
public String getValue() {
return value;
} }
public void setActiveValue(String activeValue) { public void setValue(String value) {
this.activeValue = activeValue; this.value = value;
}
public String getDraftValue() {
return draftValue;
}
public void setDraftValue(String draftValue) {
this.draftValue = draftValue;
} }
public CountryPropertyType getType() { public CountryPropertyType getType() {
@ -41,4 +35,20 @@ public class CountryProperty {
public void setType(CountryPropertyType type) { public void setType(CountryPropertyType type) {
this.type = 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;
}
} }

View file

@ -9,7 +9,6 @@ import org.springframework.data.relational.core.mapping.Table;
public class CountryPropertyType { public class CountryPropertyType {
private Integer id; private Integer id;
@NotNull @NotNull

View file

@ -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.MappedCollection;
import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.relational.core.mapping.Table;
import java.time.LocalDateTime;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.Set; import java.util.Set;
@ -14,17 +15,42 @@ public class PropertySet {
@Id @Id
private Integer id; private Integer id;
private OffsetDateTime startDate; private LocalDateTime startDate;
private OffsetDateTime endDate; private LocalDateTime endDate;
private PropertySetState state; private PropertySetState state;
@MappedCollection(idColumn = "property_set_id")
private Set<SystemProperty> systemProperties;
@MappedCollection(idColumn = "property_set_id") public Integer getId() {
private Set<CountryProperty> countryProperties; 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;
}
} }

View file

@ -0,0 +1,5 @@
package de.avatic.lcc.model.properties;
public enum PropertyType {
COUNTRY, SYSTEM, PACKAGING
}

View file

@ -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<CountryProperty> 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);
}
}

View file

@ -1,7 +0,0 @@
package de.avatic.lcc.repositories.packaging;
import org.springframework.stereotype.Repository;
@Repository
public class PackagingPropertyRepository {
}

View file

@ -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<CountryProperty> 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<CountryPropertyType> 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);
}
}

View file

@ -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<PackagingProperty> 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<PackagingPropertyType> 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);
}
}

View file

@ -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<SystemPropertyType> 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;
});
}
}

View file

@ -2,30 +2,35 @@ package de.avatic.lcc.service;
import de.avatic.lcc.dto.countries.get.CountryGetDTO; import de.avatic.lcc.dto.countries.get.CountryGetDTO;
import de.avatic.lcc.dto.countries.get.CountryListGetDTO; 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.country.Country;
import de.avatic.lcc.model.properties.CountryProperty; 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.country.CountryRepository;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.repositories.pagination.SearchQueryResult;
import de.avatic.lcc.repositories.properties.SystemPropertiesRepository;
import de.avatic.lcc.service.transformer.CountryTransformerService; import de.avatic.lcc.service.transformer.CountryTransformerService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
@Service @Service
public class CountryService { public class CountryService {
private final CountryRepository countryRepository; private final CountryRepository countryRepository;
private final CountryTransformerService countryTransformerService; 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.countryRepository = countryRepository;
this.countryTransformerService = countryTransformerService; this.countryTransformerService = countryTransformerService;
this.countryPropertyRepository = countryPropertyRepository; this.countryPropertiesRepository = countryPropertiesRepository;
this.systemPropertiesRepository = systemPropertiesRepository;
} }
public SearchQueryResult<CountryListGetDTO> listMaterial(String filter, int page, int limit) { public SearchQueryResult<CountryListGetDTO> listMaterial(String filter, int page, int limit) {
@ -46,7 +51,20 @@ public class CountryService {
} }
public CountryGetDTO getCountry(Integer id) { public CountryGetDTO getCountry(Integer id) {
List<CountryProperty> properties = countryPropertyRepository.listByCountryId(id); List<CountryProperty> properties = countryPropertiesRepository.listByCountryId(id);
return countryTransformerService.convertToCountryGetDTO(countryRepository.getById(id), properties).orElseThrow(); return countryTransformerService.convertToCountryGetDTO(countryRepository.getById(id), properties).orElseThrow();
} }
@Transactional
public void updateCountry(Integer id, CountryPostDTO dto) {
List<CountryPropertyType> 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);
}
}
}
} }

View file

@ -7,13 +7,18 @@ import de.avatic.lcc.model.materials.Material;
import de.avatic.lcc.model.nodes.Node; import de.avatic.lcc.model.nodes.Node;
import de.avatic.lcc.model.packaging.Packaging; import de.avatic.lcc.model.packaging.Packaging;
import de.avatic.lcc.model.packaging.PackagingDimension; 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.MaterialRepository;
import de.avatic.lcc.repositories.NodeRepository; 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.PackagingDimensionRepository;
import de.avatic.lcc.repositories.packaging.PackagingRepository; import de.avatic.lcc.repositories.packaging.PackagingRepository;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult; 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.DimensionTransformerService;
import de.avatic.lcc.service.transformer.NodeTransformerService; import de.avatic.lcc.service.transformer.NodeTransformerService;
import de.avatic.lcc.service.transformer.PackagingTransformerService; import de.avatic.lcc.service.transformer.PackagingTransformerService;
@ -32,14 +37,16 @@ public class PackagingService {
private final MaterialRepository materialRepository; private final MaterialRepository materialRepository;
private final CountryRepository countryRepository; private final CountryRepository countryRepository;
private final PackagingTransformerService packagingTransformerService; 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.packagingRepository = packagingRepository;
this.packagingDimensionRepository = packagingDimensionRepository; this.packagingDimensionRepository = packagingDimensionRepository;
this.nodeRepository = nodeRepository; this.nodeRepository = nodeRepository;
this.materialRepository = materialRepository; this.materialRepository = materialRepository;
this.countryRepository = countryRepository; this.countryRepository = countryRepository;
this.packagingTransformerService = packagingTransformerService; this.packagingTransformerService = packagingTransformerService;
this.packagingPropertiesRepository = packagingPropertiesRepository;
} }
@Transactional @Transactional
@ -62,7 +69,7 @@ public class PackagingService {
}).toList(); }).toList();
return new SearchQueryResult<>(dto, queryResult.getPage(), queryResult.getTotalElements(), queryResult.getElementsPerPage() ); return new SearchQueryResult<>(dto, queryResult.getPage(), queryResult.getTotalElements(), queryResult.getElementsPerPage());
} }
@Transactional @Transactional
@ -74,25 +81,36 @@ public class PackagingService {
Optional<Country> country = countryRepository.getById(supplier.orElseThrow().getCountryId()); Optional<Country> country = countryRepository.getById(supplier.orElseThrow().getCountryId());
Optional<PackagingDimension> hu = packagingDimensionRepository.getById(packaging.orElseThrow().getHuId()); Optional<PackagingDimension> hu = packagingDimensionRepository.getById(packaging.orElseThrow().getHuId());
Optional<PackagingDimension> shu = packagingDimensionRepository.getById(packaging.orElseThrow().getShuId()); Optional<PackagingDimension> shu = packagingDimensionRepository.getById(packaging.orElseThrow().getShuId());
List<PackagingProperty> 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 @Transactional
public void updatePackaging(Integer id, PackagingPostDTO dto) { public void updatePackaging(Integer id, PackagingPostDTO dto) {
Optional<Packaging> entity = packagingRepository.getById(id); Optional<Packaging> 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 integrity
Check.equals(dto.getHu().getId(), entity.get().getHuId()); Check.equals(dto.getHu().getId(), entity.get().getHuId());
Check.equals(dto.getHu().getId(), entity.get().getHuId()); Check.equals(dto.getHu().getId(), entity.get().getHuId());
Check.equals(dto.getId(), id); Check.equals(dto.getId(), id);
packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getHu())); packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getHu()));
packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getShu())); packagingDimensionRepository.update(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getShu()));
List<PackagingPropertyType> 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)); packagingRepository.update(packagingTransformerService.convertFromPackagingPostDTO(dto));
} }
@ -103,8 +121,9 @@ public class PackagingService {
@Transactional @Transactional
public Integer createPackaging(PackagingPostDTO dto) { public Integer createPackaging(PackagingPostDTO dto) {
Optional<Integer> huId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getHu())); Optional<Integer> huId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getHu()));
Optional<Integer> shuId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionDTO(dto.getShu())); Optional<Integer> shuId = packagingDimensionRepository.insert(packagingTransformerService.convertFromPackagingDimensionPostDTO(dto.getShu()));
Packaging entity = packagingTransformerService.convertFromPackagingPostDTO(dto); Packaging entity = packagingTransformerService.convertFromPackagingPostDTO(dto);
entity.setHuId(huId.orElseThrow()); entity.setHuId(huId.orElseThrow());

View file

@ -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<PropertiesPostDTO> property) {
PropertyType propertyType = PropertyType.valueOf(type);
switch (propertyType) {
case SYSTEM:
break;
case COUNTRY:
break;
case PACKAGING:
break;
}
}
}

View file

@ -5,6 +5,7 @@ import de.avatic.lcc.dto.countries.get.CountryGetDTO;
import de.avatic.lcc.dto.countries.get.CountryPropertyGetDTO; import de.avatic.lcc.dto.countries.get.CountryPropertyGetDTO;
import de.avatic.lcc.model.country.Country; import de.avatic.lcc.model.country.Country;
import de.avatic.lcc.model.properties.CountryProperty; import de.avatic.lcc.model.properties.CountryProperty;
import de.avatic.lcc.model.properties.PropertySetState;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
@ -26,16 +27,18 @@ public class CountryTransformerService {
dto.setName(entity.getIsoCode().getFullName()); dto.setName(entity.getIsoCode().getFullName());
dto.setId(entity.getId()); 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(); CountryPropertyGetDTO dtoEntry = new CountryPropertyGetDTO();
dtoEntry.setCurrentValue(p.getActiveValue()); Optional<CountryProperty> draft = properties.stream().filter(d -> d.getPropertySet().getState().equals(PropertySetState.DRAFT) && d.getType().getExternalMappingId().equals(p.getType().getExternalMappingId())).findFirst();
dtoEntry.setDraftValue(p.getDraftValue());
dtoEntry.setCurrentValue(p.getValue());
draft.ifPresent(countryProperty -> dtoEntry.setDraftValue(countryProperty.getValue()));
dtoEntry.setRequired(p.getType().getRequired()); dtoEntry.setRequired(p.getType().getRequired());
dtoEntry.setId(p.getType().getId());
dtoEntry.setName(p.getType().getName()); dtoEntry.setName(p.getType().getName());
dtoEntry.setExternalMappingId(p.getType().getExternalMappingId()); dtoEntry.setExternalMappingId(p.getType().getExternalMappingId());
dtoEntry.setDataType(p.getType().getDataType().name()); dtoEntry.setDataType(p.getType().getDataType().name());
dtoEntry.setValidationRule(p.getType().getValidationRule());
return dtoEntry; return dtoEntry;
}).toList()); }).toList());
@ -43,4 +46,5 @@ public class CountryTransformerService {
return Optional.of(dto); return Optional.of(dto);
} }
} }

View file

@ -2,15 +2,18 @@ package de.avatic.lcc.service.transformer;
import de.avatic.lcc.dto.generic.NodeTypeDTO; import de.avatic.lcc.dto.generic.NodeTypeDTO;
import de.avatic.lcc.dto.packaging.get.*; 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.dto.packaging.post.PackagingPostDTO;
import de.avatic.lcc.model.country.Country; import de.avatic.lcc.model.country.Country;
import de.avatic.lcc.model.materials.Material; import de.avatic.lcc.model.materials.Material;
import de.avatic.lcc.model.nodes.Node; import de.avatic.lcc.model.nodes.Node;
import de.avatic.lcc.model.packaging.Packaging; import de.avatic.lcc.model.packaging.Packaging;
import de.avatic.lcc.model.packaging.PackagingDimension; import de.avatic.lcc.model.packaging.PackagingDimension;
import de.avatic.lcc.model.packaging.PackagingProperty;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
@Service @Service
@ -92,7 +95,7 @@ public class PackagingTransformerService {
return Optional.of(dto); return Optional.of(dto);
} }
public Optional<PackagingGetDTO> convertToPackagingGetDTO(Optional<Packaging> packaging, Optional<Material> material, Optional<Node> supplier, Optional<Country> country, Optional<PackagingDimension> hu, Optional<PackagingDimension> shu) { public Optional<PackagingGetDTO> convertToPackagingGetDTO(Optional<Packaging> packaging, Optional<Material> material, Optional<Node> supplier, Optional<Country> country, Optional<PackagingDimension> hu, Optional<PackagingDimension> shu, List<PackagingProperty> properties) {
if(packaging.isEmpty()) return Optional.empty(); if(packaging.isEmpty()) return Optional.empty();
Packaging data = packaging.get(); Packaging data = packaging.get();
@ -104,10 +107,24 @@ public class PackagingTransformerService {
dto.setHu(convertToPackagingDimensionDTO(hu).orElseThrow()); dto.setHu(convertToPackagingDimensionDTO(hu).orElseThrow());
dto.setShu(convertToPackagingDimensionDTO(shu).orElseThrow()); dto.setShu(convertToPackagingDimensionDTO(shu).orElseThrow());
dto.setDeprecated(data.getDeprecated()); dto.setDeprecated(data.getDeprecated());
dto.setProperties(properties.stream().map(this::convertToPackagingPropertyGetDTO).toList());
return Optional.of(dto); 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) { public Packaging convertFromPackagingPostDTO(PackagingPostDTO dto) {
var entity = new Packaging(); var entity = new Packaging();
@ -121,7 +138,24 @@ public class PackagingTransformerService {
return entity; 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(); var entity = new PackagingDimension();
entity.setId(dto.getId()); entity.setId(dto.getId());
@ -139,4 +173,14 @@ public class PackagingTransformerService {
} }
public List<PackagingProperty> convertFromPackagingPropertyPostDTO(PackagingPropertiesPostDTO properties) {
return properties.stream().map(p -> {
PackagingProperty entity = new PackagingProperty();
entity.set();
}).toList()
}
} }

View file

@ -0,0 +1,9 @@
package de.avatic.lcc.service.transformer;
import org.springframework.stereotype.Service;
@Service
public class PropertiesTransformerService {
}

View file

@ -44,10 +44,9 @@ CREATE TABLE IF NOT EXISTS `country`
`id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT,
`iso_code` CHAR(2) NOT NULL COMMENT 'ISO 3166-1 alpha-2 country code', `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)', `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, `is_deprecated` BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE INDEX `idx_country_iso_code` (`iso_code`), UNIQUE KEY `uk_country_iso_code` (`iso_code`),
CONSTRAINT `chk_country_region_code` CONSTRAINT `chk_country_region_code`
CHECK (`region_code` IN ('EMEA', 'LATAM', 'APAC', 'NAM')) CHECK (`region_code` IN ('EMEA', 'LATAM', 'APAC', 'NAM'))
) COMMENT 'Master data table for country information and regional classification'; ) 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), `property_value` VARCHAR(500),
FOREIGN KEY (`country_id`) REFERENCES `country` (`id`), FOREIGN KEY (`country_id`) REFERENCES `country` (`id`),
FOREIGN KEY (`country_property_type_id`) REFERENCES `country_property_type` (`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'; ) COMMENT 'Stores country-specific property values with versioning support';
-- Main table for user information -- Main table for user information
@ -88,8 +88,8 @@ CREATE TABLE IF NOT EXISTS `sys_user`
`firstname` VARCHAR(100) NOT NULL, `firstname` VARCHAR(100) NOT NULL,
`lastname` VARCHAR(100) NOT NULL, `lastname` VARCHAR(100) NOT NULL,
`is_active` BOOLEAN NOT NULL DEFAULT TRUE, `is_active` BOOLEAN NOT NULL DEFAULT TRUE,
UNIQUE INDEX `idx_user_email` (`email`), UNIQUE KEY `idx_user_email` (`email`),
UNIQUE INDEX `idx_user_workday` (`workday_id`) UNIQUE KEY `idx_user_workday` (`workday_id`)
) COMMENT 'Stores basic information about system users'; ) COMMENT 'Stores basic information about system users';
-- Group definitions -- Group definitions
@ -98,7 +98,7 @@ CREATE TABLE IF NOT EXISTS `sys_group`
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`group_name` VARCHAR(64) NOT NULL, `group_name` VARCHAR(64) NOT NULL,
`group_description` VARCHAR(128) 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'; ) COMMENT 'Defines user groups for access management';
-- Junction table for user-group assignments -- Junction table for user-group assignments
@ -168,7 +168,7 @@ CREATE TABLE IF NOT EXISTS outbound_country_mapping
country_id INT NOT NULL, country_id INT NOT NULL,
FOREIGN KEY (node_id) REFERENCES node (id), FOREIGN KEY (node_id) REFERENCES node (id),
FOREIGN KEY (country_id) REFERENCES country (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_node_id (node_id),
INDEX idx_country_id (country_id) INDEX idx_country_id (country_id)
); );
@ -245,7 +245,7 @@ CREATE TABLE IF NOT EXISTS material
hs_code CHAR(8), hs_code CHAR(8),
name VARCHAR(500) NOT NULL, name VARCHAR(500) NOT NULL,
is_deprecated BOOLEAN NOT NULL DEFAULT FALSE, 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 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, `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL, `name` VARCHAR(255) NOT NULL,
external_mapping_id VARCHAR(16) NOT NULL,
`data_type` VARCHAR(16), `data_type` VARCHAR(16),
`validation_rule` VARCHAR(64), `validation_rule` VARCHAR(64),
`is_required` BOOLEAN NOT NULL DEFAULT FALSE, `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 CONSTRAINT `chk_packaging_data_type_values` CHECK (`data_type` IN
('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION', ('INT', 'PERCENTAGE', 'BOOLEAN', 'CURRENCY', 'ENUMERATION',
'TEXT')) '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_property_type_id) REFERENCES packaging_property_type (id),
FOREIGN KEY (packaging_id) REFERENCES packaging (id), FOREIGN KEY (packaging_id) REFERENCES packaging (id),
INDEX idx_packaging_property_type_id (packaging_property_type_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 CREATE TABLE IF NOT EXISTS premiss