feat: add DELETE /api/mappings/products/{id} for broken mapping cleanup
Deletes the PS product via Webservice and removes the local mapping. Use this to clean up incomplete PS products (missing ps_product_shop entry) that block re-creation on next sync. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9926f37015
commit
9fd11219af
|
|
@ -2,14 +2,16 @@ package com.teterialosjuanjos.tfg.sync_service.api.controller;
|
||||||
|
|
||||||
import com.teterialosjuanjos.tfg.sync_service.api.dto.OrderMappingResponse;
|
import com.teterialosjuanjos.tfg.sync_service.api.dto.OrderMappingResponse;
|
||||||
import com.teterialosjuanjos.tfg.sync_service.api.dto.ProductMappingResponse;
|
import com.teterialosjuanjos.tfg.sync_service.api.dto.ProductMappingResponse;
|
||||||
|
import com.teterialosjuanjos.tfg.sync_service.integration.prestashop.PrestashopClient;
|
||||||
|
import com.teterialosjuanjos.tfg.sync_service.integration.prestashop.exception.PrestashopApiException;
|
||||||
import com.teterialosjuanjos.tfg.sync_service.mapping.*;
|
import com.teterialosjuanjos.tfg.sync_service.mapping.*;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -17,6 +19,7 @@ import java.util.List;
|
||||||
* REST endpoints for inspecting the Dolibarr ↔ PrestaShop ID mappings stored locally.
|
* REST endpoints for inspecting the Dolibarr ↔ PrestaShop ID mappings stored locally.
|
||||||
*/
|
*/
|
||||||
@Tag(name = "Mappings", description = "Inspect Dolibarr ↔ PrestaShop ID mappings")
|
@Tag(name = "Mappings", description = "Inspect Dolibarr ↔ PrestaShop ID mappings")
|
||||||
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/mappings")
|
@RequestMapping("/api/mappings")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|
@ -24,6 +27,7 @@ public class MappingController {
|
||||||
|
|
||||||
private final ProductMappingRepository productMappingRepository;
|
private final ProductMappingRepository productMappingRepository;
|
||||||
private final OrderMappingRepository orderMappingRepository;
|
private final OrderMappingRepository orderMappingRepository;
|
||||||
|
private final PrestashopClient prestashopClient;
|
||||||
|
|
||||||
@Operation(summary = "List product mappings, optionally filtered by sync status")
|
@Operation(summary = "List product mappings, optionally filtered by sync status")
|
||||||
@GetMapping("/products")
|
@GetMapping("/products")
|
||||||
|
|
@ -36,6 +40,24 @@ public class MappingController {
|
||||||
return mappings.stream().map(MappingController::toProductResponse).toList();
|
return mappings.stream().map(MappingController::toProductResponse).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Delete a product mapping and its corresponding PS product. Use to clean up broken/stale mappings before re-syncing.")
|
||||||
|
@DeleteMapping("/products/{id}")
|
||||||
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
public void deleteProductMapping(@PathVariable Long id) {
|
||||||
|
ProductMapping mapping = productMappingRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Mapping not found: " + id));
|
||||||
|
if (mapping.getPrestashopId() != null) {
|
||||||
|
try {
|
||||||
|
prestashopClient.deleteProduct(mapping.getPrestashopId());
|
||||||
|
log.info("Deleted PS product id={} (sku={})", mapping.getPrestashopId(), mapping.getSku());
|
||||||
|
} catch (PrestashopApiException e) {
|
||||||
|
log.warn("Could not delete PS product id={}: {} — removing mapping anyway", mapping.getPrestashopId(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
productMappingRepository.delete(mapping);
|
||||||
|
log.info("Deleted product mapping id={} sku={}", id, mapping.getSku());
|
||||||
|
}
|
||||||
|
|
||||||
@Operation(summary = "List order mappings")
|
@Operation(summary = "List order mappings")
|
||||||
@GetMapping("/orders")
|
@GetMapping("/orders")
|
||||||
public List<OrderMappingResponse> getOrderMappings() {
|
public List<OrderMappingResponse> getOrderMappings() {
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,18 @@ public class PrestashopClient {
|
||||||
return getProductByReference(dto.reference()).orElse(null);
|
return getProductByReference(dto.reference()).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Permanently deletes a product from PrestaShop by its internal ID. */
|
||||||
|
public void deleteProduct(Integer id) {
|
||||||
|
log.debug("Deleting PrestaShop product id={}", id);
|
||||||
|
restClient.delete()
|
||||||
|
.uri(u -> u.path("/products/{id}")
|
||||||
|
.queryParam("ws_key", wsKey)
|
||||||
|
.queryParam("output_format", "JSON")
|
||||||
|
.build(id))
|
||||||
|
.retrieve()
|
||||||
|
.toBodilessEntity();
|
||||||
|
}
|
||||||
|
|
||||||
/** Updates an existing product by its PrestaShop internal ID. */
|
/** Updates an existing product by its PrestaShop internal ID. */
|
||||||
public void updateProduct(Integer id, PrestashopProductDto dto) {
|
public void updateProduct(Integer id, PrestashopProductDto dto) {
|
||||||
log.debug("Updating PrestaShop product id={}", id);
|
log.debug("Updating PrestaShop product id={}", id);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue