Add models, DTOs, repository, and controller for materials

Integrated Material domain entities with DTOs, repository, and controller, enabling CRUD functionality, pagination, and validation. Added utility classes like `UnitConverter`, and exception handling via global handlers. New classes include models for packaging, countries, and error handling structures.
This commit is contained in:
Jan 2025-03-23 20:36:28 +01:00
parent 332fd96eee
commit a1c8ef6b1b
20 changed files with 1207 additions and 10 deletions

View file

@ -0,0 +1,70 @@
package de.avatic.lcc.controller;
import de.avatic.lcc.dto.error.ErrorDTO;
import de.avatic.lcc.dto.error.ErrorResponseDTO;
import de.avatic.lcc.util.InvalidArgumentException;
import jakarta.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.HashMap;
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponseDTO> handleMethodArgumentNotValid(MethodArgumentNotValidException exception) {
ErrorDTO error = new ErrorDTO(
"BAD_REQUEST",
"Invalid Arguments",
new HashMap<>() {{
put("errorMessage", exception.getMessage());
}}
);
return new ResponseEntity<>(new ErrorResponseDTO(error), HttpStatus.BAD_REQUEST);
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(InvalidArgumentException.class)
public ResponseEntity<ErrorResponseDTO> handleMethodArgumentNotValid(InvalidArgumentException exception) {
ErrorDTO error = new ErrorDTO(
"BAD_REQUEST",
exception.getMessage(),
new HashMap<>() {{
put("errorMessage", exception.getStackTrace());
}}
);
return new ResponseEntity<>(new ErrorResponseDTO(error), HttpStatus.BAD_REQUEST);
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public String handleConstraintViolation(ConstraintViolationException exception) { //
// TODO you can choose to return your custom object here, which will then get transformed to json/xml etc.
return "Sorry, that was not quite right: " + exception.getMessage();
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponseDTO> handleGenericException(Exception ex) {
ErrorDTO error = new ErrorDTO(
"INTERNAL_SERVER_ERROR",
"An unexpected error occurred",
new HashMap<>() {{
put("errorMessage", ex.getMessage());
}}
);
return new ResponseEntity<>(new ErrorResponseDTO(error), HttpStatus.INTERNAL_SERVER_ERROR);
}
}

View file

@ -0,0 +1,92 @@
package de.avatic.lcc.controller;
import de.avatic.lcc.model.materials.Material;
import de.avatic.lcc.model.materials.MaterialListEntry;
import de.avatic.lcc.repositories.MaterialRepository;
import de.avatic.lcc.repositories.utils.SearchQueryPagination;
import de.avatic.lcc.repositories.utils.SearchQueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/materials")
public class MaterialController {
private final MaterialRepository materialRepository;
@Autowired
public MaterialController(MaterialRepository materialRepository) {
this.materialRepository = materialRepository;
}
/**
* List all materials with pagination support.
*
* @param limit Maximum number of items to return (default: 20)
* @param page Page number for pagination (default: 0)
* @param filter Optional search filter (default: empty string)
* @return A list of material summaries. Pagination details are returned in response headers:
* X-Total-Count (total elements), X-Page-Count (total pages), and X-Current-Page (current page).
*/
@GetMapping("/")
public ResponseEntity<List<MaterialListEntry>> listMaterials(
@RequestParam(defaultValue = "20") int limit,
@RequestParam(defaultValue = "0") int page,
@RequestParam(required = false, defaultValue = "") String filter) {
SearchQueryResult<MaterialListEntry> materials = materialRepository.listMaterials(filter, new SearchQueryPagination(page, limit));
return ResponseEntity.ok()
.header("X-Total-Count", String.valueOf(materials.getTotalElements()))
.header("X-Page-Count", String.valueOf(materials.getTotalPages()))
.header("X-Current-Page", String.valueOf(page))
.body(materials.toList());
}
/**
* Get detailed information about a specific material.
*
* @param id Material ID
* @return Detailed information about the material
* @throws RuntimeException if the material with the given ID is not found.
*/
@GetMapping("/{id}")
public ResponseEntity<Material> getMaterialDetails(@PathVariable Integer id) {
return ResponseEntity.ok(materialRepository.getMaterialDetails(id).orElseThrow(() -> new RuntimeException("Material not found with id " + id)));
}
/**
* Update a material with the specified ID.
*
* @param id Material ID to update
* @param material The updated material details
* @return The updated material
*/
@PutMapping("/{id}")
public ResponseEntity<Material> updateMaterial(
@PathVariable Integer id,
@RequestBody Material material) {
material.setId(id);
Material updatedMaterial = materialRepository.update(material);
return ResponseEntity.ok(updatedMaterial);
}
/**
* Soft delete a material by marking it as deprecated.
*
* @param id Material ID
* @return Empty response with status 204 No Content
* @throws RuntimeException if the material with the given ID cannot be found or deleted.
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteMaterial(@PathVariable Integer id) {
materialRepository.deleteById(id);
return ResponseEntity.noContent().build();
}
}

View file

@ -0,0 +1,53 @@
package de.avatic.lcc.dto.countries;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CountryDTO {
//TODO add country properties
@JsonProperty("id")
private String id;
@JsonProperty("iso_code")
private String isoCode;
@JsonProperty("region_code")
private String regionCode;
@JsonProperty("name")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getIsoCode() {
return isoCode;
}
public void setIsoCode(String isoCode) {
this.isoCode = isoCode;
}
public String getRegionCode() {
return regionCode;
}
public void setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View file

@ -0,0 +1,50 @@
package de.avatic.lcc.dto.countries;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CountryOverviewDTO {
@JsonProperty("id")
private String id;
@JsonProperty("iso_code")
private String isoCode;
@JsonProperty("region_code")
private String regionCode;
@JsonProperty("name")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getIsoCode() {
return isoCode;
}
public void setIsoCode(String isoCode) {
this.isoCode = isoCode;
}
public String getRegionCode() {
return regionCode;
}
public void setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View file

@ -0,0 +1,68 @@
package de.avatic.lcc.dto.error;
import java.util.Map;
import java.util.Objects;
public class ErrorDTO {
private String code;
private String message;
private Map<String, Object> details;
public ErrorDTO() {
}
public ErrorDTO(String code, String message, Map<String, Object> details) {
this.code = code;
this.message = message;
this.details = details;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Map<String, Object> getDetails() {
return details;
}
public void setDetails(Map<String, Object> details) {
this.details = details;
}
@Override
public String toString() {
return "ErrorDTO{" +
"code='" + code + '\'' +
", message='" + message + '\'' +
", details=" + details +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ErrorDTO errorDTO = (ErrorDTO) o;
return Objects.equals(code, errorDTO.code) &&
Objects.equals(message, errorDTO.message) &&
Objects.equals(details, errorDTO.details);
}
@Override
public int hashCode() {
return Objects.hash(code, message, details);
}
}

View file

@ -0,0 +1,42 @@
package de.avatic.lcc.dto.error;
import java.util.Objects;
public class ErrorResponseDTO {
private ErrorDTO error;
public ErrorResponseDTO() {
}
public ErrorResponseDTO(ErrorDTO error) {
this.error = error;
}
public ErrorDTO getError() {
return error;
}
public void setError(ErrorDTO error) {
this.error = error;
}
@Override
public String toString() {
return "ErrorResponseDTO{" +
"error=" + error +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ErrorResponseDTO that = (ErrorResponseDTO) o;
return Objects.equals(error, that.error);
}
@Override
public int hashCode() {
return Objects.hash(error);
}
}

View file

@ -0,0 +1,105 @@
package de.avatic.lcc.dto.material;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Objects;
public class MaterialDTO {
private String id;
@JsonProperty("part_number")
private String partNumber;
private String name;
@JsonProperty("hs_code")
private String hsCode;
@JsonProperty("handling_units")
private List<PackagingDTO> handlingUnits;
public MaterialDTO() {
}
public MaterialDTO(String id, String partNumber, String name, String hs_code, List<PackagingDTO> handling_units) {
this.id = id;
this.partNumber = partNumber;
this.name = name;
this.hsCode = hs_code;
this.handlingUnits = handling_units;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@JsonProperty("part_number")
public String getPartNumber() {
return partNumber;
}
@JsonProperty("part_number")
public void setPartNumber(String part_number) {
this.partNumber = part_number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@JsonProperty("hs_code")
public String getHsCode() {
return hsCode;
}
@JsonProperty("hs_code")
public void setHsCode(String hsCode) {
this.hsCode = hsCode;
}
@JsonProperty("handling_units")
public List<PackagingDTO> getHandlingUnits() {
return handlingUnits;
}
public void setHandlingUnits(List<PackagingDTO> handlingUnits) {
this.handlingUnits = handlingUnits;
}
@Override
public String toString() {
return "MaterialDetailDTO{" +
"id='" + id + '\'' +
", part_number='" + partNumber + '\'' +
", name='" + name + '\'' +
", hs_code='" + hsCode + '\'' +
", handling_units=" + handlingUnits +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MaterialDTO that = (MaterialDTO) o;
return Objects.equals(id, that.id) &&
Objects.equals(partNumber, that.partNumber) &&
Objects.equals(name, that.name) &&
Objects.equals(hsCode, that.hsCode) &&
Objects.equals(handlingUnits, that.handlingUnits);
}
@Override
public int hashCode() {
return Objects.hash(id, partNumber, name, hsCode, handlingUnits);
}
}

View file

@ -0,0 +1,148 @@
package de.avatic.lcc.dto.material;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
public class PackagingDTO {
private String id;
@JsonProperty("supplier_name")
private SupplierDTO supplierName;
@JsonProperty("parent_id")
private String parentId;
private double length;
private double width;
private double height;
@JsonProperty("dimension_unit")
private String dimensionUnit;
private double weight;
@JsonProperty("weight_unit")
private String weightUnit;
@JsonProperty("content_unit_count")
private int contentUnitCount;
public PackagingDTO() {
}
public PackagingDTO(String id, String supplierName, String parentId, double length, double width, double height,
String dimensionUnit, double weight, String weightUnit, int contentUnitCount) {
this.id = id;
this.supplierName = supplierName;
this.parentId = parentId;
this.length = length;
this.width = width;
this.height = height;
this.dimensionUnit = dimensionUnit;
this.weight = weight;
this.weightUnit = weightUnit;
this.contentUnitCount = contentUnitCount;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@JsonProperty("supplier_name")
public String getSupplierName() {
return supplierName;
}
@JsonProperty("supplier_name")
public void setSupplierName(String supplierName) {
this.supplierName = supplierName;
}
@JsonProperty("parent_id")
public String getParentId() {
return parentId;
}
@JsonProperty("parent_id")
public void setParentId(String parentId) {
this.parentId = parentId;
}
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;
}
@JsonProperty("dimension_unit")
public String getDimensionUnit() {
return dimensionUnit;
}
@JsonProperty("dimension_unit")
public void setDimensionUnit(String dimensionUnit) {
this.dimensionUnit = dimensionUnit;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
@JsonProperty("weight_unit")
public String getWeightUnit() {
return weightUnit;
}
@JsonProperty("weight_unit")
public void setWeightUnit(String weightUnit) {
this.weightUnit = weightUnit;
}
@JsonProperty("content_unit_count")
public int getContentUnitCount() {
return contentUnitCount;
}
@JsonProperty("content_unit_count")
public void setContentUnitCount(int contentUnitCount) {
this.contentUnitCount = contentUnitCount;
}
@Override
public String toString() {
// Implementation omitted for shortness
return "HandlingUnitDTO{" + /* fields */ "}";
}
@Override
public boolean equals(Object o) {
// Implementation omitted for shortness
return true;
}
@Override
public int hashCode() {
// Implementation omitted for shortness
return Objects.hash(id, supplierName, parentId, length, width, height, dimensionUnit,
weight, weightUnit, contentUnitCount);
}
}

View file

@ -0,0 +1,7 @@
package de.avatic.lcc.dto.nodes;
public class NodeDTO {
// TODO
}

View file

@ -0,0 +1,46 @@
package de.avatic.lcc.model.country;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CountryListEntry {
private Integer id;
@JsonProperty("iso_code")
private String isoCode;
@JsonProperty("region_code")
private String regionCode;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getIsoCode() {
return isoCode;
}
public void setIsoCode(String isoCode) {
this.isoCode = isoCode;
}
public String getRegionCode() {
return regionCode;
}
public void setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View file

@ -1,35 +1,33 @@
package de.avatic.lcc.model.materials; package de.avatic.lcc.model.materials;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.avatic.lcc.model.packaging.PackagingListEntry;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.relational.core.mapping.Table;
@Table("material")
public class Material { public class Material {
@Id
private Integer id; private Integer id;
@NotNull @JsonProperty("part_number")
@Size(max = 12)
private String partNumber; private String partNumber;
@NotNull @JsonProperty("normalized_part_number")
@Size(max = 12)
private String normalizedPartNumber; private String normalizedPartNumber;
@Size(max = 8)
private String hsCode; private String hsCode;
@NotNull
@Size(max = 500)
private String name; private String name;
@NotNull @JsonProperty("is_deprecated")
private Boolean isDeprecated; private Boolean isDeprecated;
private PackagingListEntry packaging;
public Integer getId() { public Integer getId() {
return id; return id;
} }
@ -77,4 +75,12 @@ public class Material {
public void setDeprecated(Boolean deprecated) { public void setDeprecated(Boolean deprecated) {
isDeprecated = deprecated; isDeprecated = deprecated;
} }
public PackagingListEntry getPackaging() {
return packaging;
}
public void setPackaging(PackagingListEntry packaging) {
this.packaging = packaging;
}
} }

View file

@ -0,0 +1,82 @@
package de.avatic.lcc.model.materials;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
public class MaterialListEntry {
private Integer id;
@JsonProperty("part_number")
private String partNumber;
private String name;
private String hsCode;
public MaterialListEntry() {
}
public MaterialListEntry(Integer id, String partNumber, String name, String hsCode) {
this.id = id;
this.partNumber = partNumber;
this.name = name;
this.hsCode = hsCode;
}
public String getHsCode() {
return hsCode;
}
public void setHsCode(String hsCode) {
this.hsCode = hsCode;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getPartNumber() {
return partNumber;
}
public void setPartNumber(String partNumber) {
this.partNumber = partNumber;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MaterialSummaryDTO{" +
"id='" + id + '\'' +
", partNumber='" + partNumber + '\'' +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MaterialListEntry that = (MaterialListEntry) o;
return Objects.equals(id, that.id) &&
Objects.equals(partNumber, that.partNumber) &&
Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(id, partNumber, name);
}
}

View file

@ -0,0 +1,8 @@
package de.avatic.lcc.model.nodes;
public class Location {
private Double longitude;
private Double latitude;
// Getters and setters
}

View file

@ -0,0 +1,64 @@
package de.avatic.lcc.model.nodes;
import de.avatic.lcc.model.country.CountryListEntry;
import java.util.List;
public class NodeListEntry {
private Integer id;
private String name;
private CountryListEntry country;
private String address;
private Location location;
private List<String> types;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public CountryListEntry getCountry() {
return country;
}
public void setCountry(CountryListEntry country) {
this.country = country;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public List<String> getTypes() {
return types;
}
public void setTypes(List<String> types) {
this.types = types;
}
}

View file

@ -0,0 +1,119 @@
package de.avatic.lcc.model.packaging;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.avatic.lcc.model.nodes.NodeListEntry;
public class PackagingListEntry {
private Integer id;
private NodeListEntry supplier;
@JsonProperty("parent_id")
private Integer parentId;
private Double width;
private Double height;
private Double length;
@JsonProperty("dimension_unit")
private String dimensionUnit;
private Double weight;
@JsonProperty("weight_unit")
private String weightUnit;
@JsonProperty("content_unit_count")
private Integer contentUnitCount;
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public NodeListEntry getSupplier() {
return supplier;
}
public void setSupplier(NodeListEntry supplier) {
this.supplier = supplier;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
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 Double getLength() {
return length;
}
public void setLength(Double length) {
this.length = length;
}
public String getDimensionUnit() {
return dimensionUnit;
}
public void setDimensionUnit(String dimensionUnit) {
this.dimensionUnit = dimensionUnit;
}
public Double getWeight() {
return weight;
}
public void setWeight(Double weight) {
this.weight = weight;
}
public String getWeightUnit() {
return weightUnit;
}
public void setWeightUnit(String weightUnit) {
this.weightUnit = weightUnit;
}
public Integer getContentUnitCount() {
return contentUnitCount;
}
public void setContentUnitCount(Integer contentUnitCount) {
this.contentUnitCount = contentUnitCount;
}
}

View file

@ -0,0 +1,137 @@
package de.avatic.lcc.repositories;
import de.avatic.lcc.model.country.CountryListEntry;
import de.avatic.lcc.model.materials.Material;
import de.avatic.lcc.model.materials.MaterialListEntry;
import de.avatic.lcc.model.nodes.NodeListEntry;
import de.avatic.lcc.model.packaging.PackagingListEntry;
import de.avatic.lcc.repositories.utils.SearchQueryPagination;
import de.avatic.lcc.repositories.utils.SearchQueryResult;
import de.avatic.lcc.repositories.utils.UnitConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@Repository
public class MaterialRepository {
JdbcTemplate jdbcTemplate;
@Autowired
public MaterialRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Transactional
public SearchQueryResult<MaterialListEntry> listMaterials(String filter, SearchQueryPagination pagination) {
String query = "SELECT id, name, part_number FROM material WHERE name LIKE ? OR part_number LIKE ? LIMIT ? OFFSET ?";
var entries = jdbcTemplate.query(query, (rs, rowNum) -> {
MaterialListEntry entry = new MaterialListEntry();
entry.setId(rs.getInt("id"));
entry.setName(rs.getString("name"));
entry.setPartNumber(rs.getString("part_number"));
return entry;
}, "%" + filter + "%", "%" + filter + "%", pagination.getLimit(), pagination.getOffset());
Integer totalCount = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM material WHERE name LIKE ? OR part_number LIKE ?",
Integer.class, "%" + filter + "%", "%" + filter + "%"
);
return new SearchQueryResult<>(entries, totalCount, pagination.getLimit(), pagination.getOffset());
}
@Transactional
public Optional<Material> getMaterialDetails(Integer id) {
String query = "SELECT * FROM material WHERE id = ? AND is_deprecated = FALSE";
Material material = jdbcTemplate.queryForObject(query, (rs, rowNum) -> {
Material foundMaterial = new Material();
foundMaterial.setId(rs.getInt("id"));
foundMaterial.setName(rs.getString("name"));
foundMaterial.setPartNumber(rs.getString("part_number"));
foundMaterial.setNormalizedPartNumber(rs.getString("normalized_part_number"));
foundMaterial.setHsCode(rs.getString("hs_code"));
foundMaterial.setDeprecated(rs.getBoolean("is_deprecated"));
return foundMaterial;
}, id);
if(null == material) {
return Optional.empty();
}
// Query packaging data for the material
String packagingQuery = """
SELECT packaging.id, parent_id, width, height, length, packaging.displayed_dimension_unit, weight, displayed_weight_unit,
content_unit_count, type,
node.id AS supplier_id, node.name AS supplier_name, node.address AS supplier_address,
country.id AS country_id, country.name AS country_name, country.iso_code AS country_iso_code, country.region_code AS country_region_code
FROM packaging
LEFT JOIN node ON packaging.supplier_node_id = node.id
LEFT JOIN country ON node.country_id = country.id
WHERE material_id = ? AND packaging.is_deprecated = FALSE
""";
if (material != null) {
PackagingListEntry packaging = jdbcTemplate.queryForObject(packagingQuery, (packagingRs, packagingRowNum) -> {
PackagingListEntry packagingEntry = new PackagingListEntry();
String dimensionUnit = packagingRs.getString("displayed_dimension_unit");
String weightUnit = packagingRs.getString("displayed_weight_unit");
packagingEntry.setId(packagingRs.getInt("id"));
packagingEntry.setParentId(packagingRs.getInt("parent_id"));
packagingEntry.setWidth(UnitConverter.convert(packagingRs.getInt("width"), dimensionUnit));
packagingEntry.setHeight(UnitConverter.convert(packagingRs.getInt("height"), dimensionUnit));
packagingEntry.setLength(UnitConverter.convert(packagingRs.getInt("length"), dimensionUnit));
packagingEntry.setDimensionUnit(dimensionUnit);
packagingEntry.setWeight(UnitConverter.convert(packagingRs.getInt("weight"), weightUnit));
packagingEntry.setWeightUnit(weightUnit);
packagingEntry.setContentUnitCount(packagingRs.getInt("content_unit_count"));
packagingEntry.setType(packagingRs.getString("type"));
if (packagingRs.getObject("supplier_id") != null) {
NodeListEntry supplier = new NodeListEntry();
supplier.setId(packagingRs.getInt("supplier_id"));
supplier.setName(packagingRs.getString("supplier_name"));
if(packagingRs.getObject("country_id") != null) {
CountryListEntry country = new CountryListEntry();
country.setId(packagingRs.getInt("country_id"));
country.setName(packagingRs.getString("country_name"));
country.setIsoCode(packagingRs.getString("country_iso_code"));
country.setRegionCode(packagingRs.getString("country_region_code"));
supplier.setCountry(country);
}
packagingEntry.setSupplier(supplier);
}
return packagingEntry;
}, material.getId());
material.setPackaging(packaging);
}
return Optional.of(material);
}
@Transactional
public void deleteById(Integer id) {
String deleteQuery = "UPDATE material SET is_deprecated = TRUE WHERE id = ?";
jdbcTemplate.update(deleteQuery, id);
}
@Transactional
public Material update(Material material) {
String updateQuery = "UPDATE material SET name = ?, part_number = ?, normalized_part_number = ?, hs_code = ? WHERE id = ?";
jdbcTemplate.update(updateQuery, material.getName(), material.getPartNumber(), material.getNormalizedPartNumber(), material.getHsCode(), material.getId());
return material;
}
}

View file

@ -0,0 +1,21 @@
package de.avatic.lcc.repositories.utils;
public class SearchQueryPagination {
private final Integer page;
private final Integer size;
public SearchQueryPagination(Integer page, Integer size) {
this.page = page;
this.size = size;
}
public Integer getLimit() {
return size;
}
public Integer getOffset() {
return page * size;
}
}

View file

@ -0,0 +1,49 @@
package de.avatic.lcc.repositories.utils;
import java.util.List;
public class SearchQueryResult<T> {
private List<T> result;
private Integer page, totalPages, totalElements;
public SearchQueryResult(List<T> result, Integer page, Integer totalPages, Integer totalElements) {
this.result = result;
this.page = page;
this.totalPages = totalPages;
this.totalElements = totalElements;
}
public List<T> toList() {
return result;
}
public void setResult(List<T> result) {
this.result = result;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
public int getTotalElements() {
return totalElements;
}
public void setTotalElements(int totalElements) {
this.totalElements = totalElements;
}
}

View file

@ -0,0 +1,16 @@
package de.avatic.lcc.repositories.utils;
public class UnitConverter {
public static double convert(Integer value, String unit) {
return switch (unit) {
case "MM", "G" -> Math.round(value * 100.0) / 100.0;
case "CM" -> Math.round((value / 10.0) * 100.0) / 100.0;
case "M", "KG" -> Math.round((value / 1000.0) * 100.0) / 100.0;
case "T" -> Math.round((value / 1000000.0) * 100.0) / 100.0;
default -> throw new IllegalArgumentException("Unknown unit: " + unit);
};
}
}

View file

@ -0,0 +1,14 @@
package de.avatic.lcc.util;
public class InvalidArgumentException extends RuntimeException{
public InvalidArgumentException() {
super();
}
public InvalidArgumentException(final String parameterName) {
super("Invalid parameter: " + parameterName );
}
}