From ae10417c445d06d8424b8cf09e01fdc73cdf7130 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 6 Nov 2025 20:22:48 +0100 Subject: [PATCH] Added bulk material update endpoint and support for deprecation handling logic: - **Controller**: Introduced `updateMaterial` method in `MaterialController` for batch material updates. - **Service**: Implemented update logic in `MaterialService` to handle both updates and deprecations based on the new `MaterialUpdateDTO`. - **Transformer**: Updated `MaterialUpdateDTOTransformer` to map deprecation status and remove unused fields. - **Repository**: Added `updateByPartNumber` and `deleteByIds` methods in `MaterialRepository` for efficient updates and deprecations. --- .../configuration/MaterialController.java | 11 +++- .../material/update/MaterialUpdateDTO.java | 57 +++++-------------- .../lcc/repositories/MaterialRepository.java | 16 ++++++ .../lcc/service/access/MaterialService.java | 29 ++++++++-- .../MaterialUpdateDTOTransformer.java | 5 +- 5 files changed, 67 insertions(+), 51 deletions(-) diff --git a/src/main/java/de/avatic/lcc/controller/configuration/MaterialController.java b/src/main/java/de/avatic/lcc/controller/configuration/MaterialController.java index c5e3b98..b754194 100644 --- a/src/main/java/de/avatic/lcc/controller/configuration/MaterialController.java +++ b/src/main/java/de/avatic/lcc/controller/configuration/MaterialController.java @@ -1,10 +1,12 @@ package de.avatic.lcc.controller.configuration; +import de.avatic.lcc.dto.configuration.material.update.MaterialUpdateDTO; import de.avatic.lcc.dto.configuration.material.view.MaterialDetailDTO; import de.avatic.lcc.dto.generic.MaterialDTO; import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.service.access.MaterialService; import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -44,7 +46,7 @@ public class MaterialController { @RequestParam(defaultValue = "1") @Min(1) int page, @RequestParam(required = false) Optional filter) { - SearchQueryResult materials = materialService.listMaterial(filter, page, limit,Boolean.parseBoolean(excludeDeprecated)); + SearchQueryResult materials = materialService.listMaterial(filter, page, limit, Boolean.parseBoolean(excludeDeprecated)); return ResponseEntity.ok() .header("X-Total-Count", String.valueOf(materials.getTotalElements())) @@ -65,4 +67,11 @@ public class MaterialController { public ResponseEntity getMaterialDetails(@PathVariable Integer id) { return ResponseEntity.ok(materialService.getMaterial(id)); } + + @PutMapping({"/", ""}) + @PreAuthorize("hasRole('MATERIAL')") + public ResponseEntity updateMaterial(List<@Size(max = 100, min = 1) MaterialUpdateDTO> materials) { + materialService.updateMaterial(materials); + return ResponseEntity.ok().build(); + } } \ No newline at end of file diff --git a/src/main/java/de/avatic/lcc/dto/configuration/material/update/MaterialUpdateDTO.java b/src/main/java/de/avatic/lcc/dto/configuration/material/update/MaterialUpdateDTO.java index a67f1c1..61f4103 100644 --- a/src/main/java/de/avatic/lcc/dto/configuration/material/update/MaterialUpdateDTO.java +++ b/src/main/java/de/avatic/lcc/dto/configuration/material/update/MaterialUpdateDTO.java @@ -5,38 +5,20 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Objects; public class MaterialUpdateDTO { - private Integer id; + @JsonProperty("part_number") private String partNumber; + private String name; + + @JsonProperty("hs_code") private String hsCode; + private boolean delete; + public MaterialUpdateDTO() { } - public MaterialUpdateDTO(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; } @@ -53,28 +35,19 @@ public class MaterialUpdateDTO { this.name = name; } - @Override - public String toString() { - return "MaterialSummaryDTO{" + - "id='" + id + '\'' + - ", partNumber='" + partNumber + '\'' + - ", name='" + name + '\'' + - '}'; + public String getHsCode() { + return hsCode; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MaterialUpdateDTO that = (MaterialUpdateDTO) o; - return Objects.equals(id, that.id) && - Objects.equals(partNumber, that.partNumber) && - Objects.equals(name, that.name); + public void setHsCode(String hsCode) { + this.hsCode = hsCode; } - @Override - public int hashCode() { - return Objects.hash(id, partNumber, name); + public boolean isDelete() { + return delete; } + public void setDelete(boolean delete) { + this.delete = delete; + } } diff --git a/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java b/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java index 49d824d..8582b0a 100644 --- a/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java +++ b/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java @@ -155,6 +155,12 @@ public class MaterialRepository { return Optional.ofNullable(jdbcTemplate.update(updateQuery, material.getName(), material.getPartNumber(), material.getNormalizedPartNumber(), material.getHsCode(), material.getId()) == 0 ? null : material.getId()); } + @Transactional + public void updateByPartNumber(Material material) { + String updateQuery = "UPDATE material SET name = ?, part_number = ?, normalized_part_number = ?, hs_code = ? WHERE normalized_part_number = ?"; + jdbcTemplate.update(updateQuery, material.getName(), material.getPartNumber(), material.getNormalizedPartNumber(), material.getHsCode(), material.getNormalizedPartNumber()); + } + /** * Returns all IDs from the input list that don't exist in the material table * @param ids List of integers to check @@ -198,6 +204,16 @@ public class MaterialRepository { ); } + public void deleteByIds(List ids) { + String placeholders = ids.stream() + .map(id -> "?") + .collect(Collectors.joining(",")); + + String sql = "UPDATE material SET is_deprecated = TRUE WHERE id IN ("+placeholders+")"; + + jdbcTemplate.update(sql, ids); + } + private static class MaterialMapper implements RowMapper { diff --git a/src/main/java/de/avatic/lcc/service/access/MaterialService.java b/src/main/java/de/avatic/lcc/service/access/MaterialService.java index 02e378f..739bb50 100644 --- a/src/main/java/de/avatic/lcc/service/access/MaterialService.java +++ b/src/main/java/de/avatic/lcc/service/access/MaterialService.java @@ -1,5 +1,6 @@ package de.avatic.lcc.service.access; +import de.avatic.lcc.dto.configuration.material.update.MaterialUpdateDTO; import de.avatic.lcc.dto.configuration.material.view.MaterialDetailDTO; import de.avatic.lcc.dto.generic.MaterialDTO; import de.avatic.lcc.model.db.materials.Material; @@ -8,10 +9,13 @@ import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.service.transformer.generic.MaterialTransformer; import de.avatic.lcc.service.transformer.material.MaterialDetailTransformer; +import de.avatic.lcc.service.transformer.material.MaterialUpdateDTOTransformer; import de.avatic.lcc.util.exception.badrequest.MaterialNotFoundException; import de.avatic.lcc.util.exception.badrequest.NotFoundException; +import jakarta.validation.constraints.Size; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Optional; /** @@ -25,6 +29,7 @@ public class MaterialService { private final MaterialRepository materialRepository; private final MaterialTransformer materialTransformer; private final MaterialDetailTransformer materialDetailTransformer; + private final MaterialUpdateDTOTransformer materialUpdateDTOTransformer; /** * Constructor for MaterialService. @@ -33,19 +38,20 @@ public class MaterialService { * @param materialTransformer transformer to convert material entities to DTOs * @param materialDetailTransformer transformer to convert material entities to detail DTOs */ - public MaterialService(MaterialRepository materialRepository, MaterialTransformer materialTransformer, MaterialDetailTransformer materialDetailTransformer) { + public MaterialService(MaterialRepository materialRepository, MaterialTransformer materialTransformer, MaterialDetailTransformer materialDetailTransformer, MaterialUpdateDTOTransformer materialUpdateDTOTransformer) { this.materialRepository = materialRepository; this.materialTransformer = materialTransformer; this.materialDetailTransformer = materialDetailTransformer; + this.materialUpdateDTOTransformer = materialUpdateDTOTransformer; } /** * Lists materials based on the provided criteria, including optional filtering, * pagination, and exclusion of deprecated entries. * - * @param filter an optional filter to apply to the material list, such as a search term - * @param page the page number for pagination - * @param limit the maximum number of materials to include in the result + * @param filter an optional filter to apply to the material list, such as a search term + * @param page the page number for pagination + * @param limit the maximum number of materials to include in the result * @param excludeDeprecated a flag indicating whether to exclude deprecated materials * @return a {@code SearchQueryResult} containing the paginated list of materials */ @@ -62,7 +68,20 @@ public class MaterialService { * @throws MaterialNotFoundException if no material with the given ID is found */ public MaterialDetailDTO getMaterial(Integer id) { - return materialDetailTransformer.toMaterialDetailDTO(materialRepository.getByIdIncludeDeprecated(id).orElseThrow(() -> new NotFoundException(NotFoundException.NotFoundType.MATERIAL,id.toString()))); + return materialDetailTransformer.toMaterialDetailDTO(materialRepository.getByIdIncludeDeprecated(id).orElseThrow(() -> new NotFoundException(NotFoundException.NotFoundType.MATERIAL, id.toString()))); + } + + public void updateMaterial(List<@Size(max = 100, min = 1) MaterialUpdateDTO> dtos) { + var materials = dtos.stream().map(materialUpdateDTOTransformer::fromMaterialUpdateDTO).toList(); + var toBeDeleted = materials.stream().filter(m -> m.getDeprecated() != null && m.getDeprecated()).map(Material::getId).toList(); + var toBeUpdated = materials.stream().filter(m -> m.getDeprecated() != null && m.getDeprecated()).toList(); + + if (!toBeDeleted.isEmpty()) + toBeDeleted.forEach(materialRepository::setDeprecatedById); + + if (!toBeUpdated.isEmpty()) + toBeUpdated.forEach(materialRepository::updateByPartNumber); + } /** diff --git a/src/main/java/de/avatic/lcc/service/transformer/material/MaterialUpdateDTOTransformer.java b/src/main/java/de/avatic/lcc/service/transformer/material/MaterialUpdateDTOTransformer.java index f6a70dd..2edfa74 100644 --- a/src/main/java/de/avatic/lcc/service/transformer/material/MaterialUpdateDTOTransformer.java +++ b/src/main/java/de/avatic/lcc/service/transformer/material/MaterialUpdateDTOTransformer.java @@ -4,7 +4,7 @@ import de.avatic.lcc.dto.configuration.material.update.MaterialUpdateDTO; import de.avatic.lcc.model.db.materials.Material; import org.springframework.stereotype.Service; -@Deprecated + @Service public class MaterialUpdateDTOTransformer { @@ -15,8 +15,7 @@ public class MaterialUpdateDTOTransformer { entity.setNormalizedPartNumber(normalizePartNumber(dto.getPartNumber())); entity.setPartNumber(dto.getPartNumber()); entity.setName(dto.getName()); - entity.setDeprecated(false); - entity.setId(dto.getId()); + entity.setDeprecated(!dto.isDelete()); entity.setHsCode(dto.getHsCode()); return entity;