fix: handle Dolibarr/PS 404 on empty filter results

Both APIs return 404 (not 200+empty) when a filter finds no results.
Catch DolibarrApiException(404) in getOrCreateThirdparty and
getProductByRef; catch PrestashopApiException(404) in
getProductByReference — treat as empty/not-found instead of error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
luklpz 2026-05-15 08:14:21 +02:00
parent fa20b7cc91
commit db4db1741d
2 changed files with 48 additions and 28 deletions

View File

@ -1,6 +1,7 @@
package com.teterialosjuanjos.tfg.sync_service.integration.dolibarr; package com.teterialosjuanjos.tfg.sync_service.integration.dolibarr;
import com.teterialosjuanjos.tfg.sync_service.integration.dolibarr.dto.*; import com.teterialosjuanjos.tfg.sync_service.integration.dolibarr.dto.*;
import com.teterialosjuanjos.tfg.sync_service.integration.dolibarr.exception.DolibarrApiException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
@ -50,6 +51,7 @@ public class DolibarrClient {
*/ */
public DolibarrProductDto getProductByRef(String ref) { public DolibarrProductDto getProductByRef(String ref) {
String filter = "(t.ref:=:'%s')".formatted(ref); String filter = "(t.ref:=:'%s')".formatted(ref);
try {
List<DolibarrProductDto> results = restClient.get() List<DolibarrProductDto> results = restClient.get()
.uri(u -> u.path("/products") .uri(u -> u.path("/products")
.queryParam("sqlfilters", filter) .queryParam("sqlfilters", filter)
@ -57,8 +59,11 @@ public class DolibarrClient {
.build()) .build())
.retrieve() .retrieve()
.body(new ParameterizedTypeReference<List<DolibarrProductDto>>() {}); .body(new ParameterizedTypeReference<List<DolibarrProductDto>>() {});
return (results != null && !results.isEmpty()) ? results.get(0) : null; return (results != null && !results.isEmpty()) ? results.get(0) : null;
} catch (DolibarrApiException e) {
if (e.getStatusCode().value() == 404) return null;
throw e;
}
} }
/** /**
@ -119,13 +124,21 @@ public class DolibarrClient {
*/ */
public DolibarrThirdpartyDto getOrCreateThirdparty(String email, String name) { public DolibarrThirdpartyDto getOrCreateThirdparty(String email, String name) {
log.debug("Looking up Dolibarr thirdparty email={}", email); log.debug("Looking up Dolibarr thirdparty email={}", email);
List<DolibarrThirdpartyDto> matches = restClient.get() List<DolibarrThirdpartyDto> matches = null;
try {
matches = restClient.get()
.uri(u -> u.path("/thirdparties") .uri(u -> u.path("/thirdparties")
.queryParam("sqlfilters", "(t.email:=:'%s')".formatted(email)) .queryParam("sqlfilters", "(t.email:=:'%s')".formatted(email))
.queryParam("limit", 1) .queryParam("limit", 1)
.build()) .build())
.retrieve() .retrieve()
.body(new ParameterizedTypeReference<List<DolibarrThirdpartyDto>>() {}); .body(new ParameterizedTypeReference<List<DolibarrThirdpartyDto>>() {});
} catch (DolibarrApiException e) {
// Dolibarr returns 404 (not 200 + empty array) when filter finds no results
if (e.getStatusCode().value() != 404) {
throw e;
}
}
if (matches != null && !matches.isEmpty()) { if (matches != null && !matches.isEmpty()) {
return matches.get(0); return matches.get(0);

View File

@ -2,6 +2,7 @@ package com.teterialosjuanjos.tfg.sync_service.integration.prestashop;
import com.teterialosjuanjos.tfg.sync_service.config.IntegrationProperties; import com.teterialosjuanjos.tfg.sync_service.config.IntegrationProperties;
import com.teterialosjuanjos.tfg.sync_service.integration.prestashop.dto.*; import com.teterialosjuanjos.tfg.sync_service.integration.prestashop.dto.*;
import com.teterialosjuanjos.tfg.sync_service.integration.prestashop.exception.PrestashopApiException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -66,6 +67,7 @@ public class PrestashopClient {
public Optional<PrestashopProductDto> getProductByReference(String reference) { public Optional<PrestashopProductDto> getProductByReference(String reference) {
// PS WebService requires [value] brackets for exact-match filtering // PS WebService requires [value] brackets for exact-match filtering
String exactRef = "[" + reference + "]"; String exactRef = "[" + reference + "]";
try {
PrestashopProductDto.ListResponse response = restClient.get() PrestashopProductDto.ListResponse response = restClient.get()
.uri(u -> u.path("/products") .uri(u -> u.path("/products")
.queryParam("ws_key", wsKey) .queryParam("ws_key", wsKey)
@ -80,6 +82,11 @@ public class PrestashopClient {
return Optional.empty(); return Optional.empty();
} }
return Optional.of(response.products().get(0)); return Optional.of(response.products().get(0));
} catch (PrestashopApiException e) {
// PS may return 404 instead of 200+empty when filter finds no results
if (e.getStatusCode() != null && e.getStatusCode().value() == 404) return Optional.empty();
throw e;
}
} }
/** /**