From 96d75b324a69274ff8ede97b497ab415eaf99e9e Mon Sep 17 00:00:00 2001 From: luklpz Date: Thu, 14 May 2026 23:26:28 +0200 Subject: [PATCH] fix: use plain String for PS multilingual fields; add Dolibarr diagnostic endpoint PS WebService GET responses return name/description as plain strings, not language-array objects. Using List caused Jackson to throw HttpMessageConversionException on every getProductByReference call. Also adds GET /api/sync/diagnostics/dolibarr to verify Dolibarr connectivity and product count from the Railway environment. Co-Authored-By: Claude Sonnet 4.6 --- .../api/controller/SyncController.java | 15 +++++++++++++++ .../integration/prestashop/PrestashopClient.java | 12 +++--------- .../prestashop/dto/PrestashopProductDto.java | 16 +++++++--------- .../sync_service/sync/ProductSyncService.java | 6 +++--- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/api/controller/SyncController.java b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/api/controller/SyncController.java index fbc93d4..32126c9 100644 --- a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/api/controller/SyncController.java +++ b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/api/controller/SyncController.java @@ -1,6 +1,8 @@ package com.teterialosjuanjos.tfg.sync_service.api.controller; import com.teterialosjuanjos.tfg.sync_service.api.dto.SyncTriggerResponse; +import com.teterialosjuanjos.tfg.sync_service.integration.dolibarr.DolibarrClient; +import com.teterialosjuanjos.tfg.sync_service.integration.dolibarr.dto.DolibarrProductDto; import com.teterialosjuanjos.tfg.sync_service.sync.OrderSyncService; import com.teterialosjuanjos.tfg.sync_service.sync.ProductSyncService; import com.teterialosjuanjos.tfg.sync_service.sync.StockSyncService; @@ -8,10 +10,14 @@ import com.teterialosjuanjos.tfg.sync_service.sync.SyncResult; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; +import java.util.Map; + /** * REST endpoints for manually triggering synchronization flows. * Useful in development (where scheduling is disabled) and for on-demand resync in production. @@ -25,6 +31,7 @@ import org.springframework.web.bind.annotation.RestController; @RequiredArgsConstructor public class SyncController { + private final DolibarrClient dolibarrClient; private final ProductSyncService productSyncService; private final StockSyncService stockSyncService; private final OrderSyncService orderSyncService; @@ -47,6 +54,14 @@ public class SyncController { return toResponse("ORDER_PULL", orderSyncService.synchronize()); } + @Operation(summary = "Diagnostic: list products returned by Dolibarr API (verifies connectivity)") + @GetMapping("/diagnostics/dolibarr") + public Map dolibarrDiagnostics() { + List products = dolibarrClient.getProducts(); + List refs = products.stream().map(DolibarrProductDto::ref).toList(); + return Map.of("count", products.size(), "refs", refs); + } + private static SyncTriggerResponse toResponse(String syncType, SyncResult result) { return new SyncTriggerResponse( syncType, diff --git a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/PrestashopClient.java b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/PrestashopClient.java index 9735506..7648e34 100644 --- a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/PrestashopClient.java +++ b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/PrestashopClient.java @@ -209,9 +209,9 @@ public class PrestashopClient { // PS WebService requires XML body for writes; output_format=JSON only affects the response. private String toProductXml(PrestashopProductDto dto) { - String name = firstLangValue(dto.name()); - String description = firstLangValue(dto.description()); - String descShort = firstLangValue(dto.descriptionShort()); + String name = dto.name() != null ? dto.name() : ""; + String description = dto.description() != null ? dto.description() : ""; + String descShort = dto.descriptionShort() != null ? dto.descriptionShort() : ""; String slug = toSlug(dto.reference()); StringBuilder sb = new StringBuilder(512); @@ -260,12 +260,6 @@ public class PrestashopClient { return sb.toString(); } - private static String firstLangValue(List langs) { - if (langs == null || langs.isEmpty()) return ""; - String v = langs.get(0).value(); - return v != null ? v : ""; - } - /** Generates a URL-safe slug from any string (used for PS link_rewrite). */ private static String toSlug(String text) { if (text == null || text.isBlank()) return "product"; diff --git a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/dto/PrestashopProductDto.java b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/dto/PrestashopProductDto.java index baa5595..deef4ca 100644 --- a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/dto/PrestashopProductDto.java +++ b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/prestashop/dto/PrestashopProductDto.java @@ -9,8 +9,10 @@ import java.util.List; /** * Represents a PrestaShop product. * - *

Multilingual fields (name, description) are returned as arrays of {@link LangValue} - * objects, one per configured shop language.

+ *

The PS WebService GET response (both list and single) returns multilingual fields + * ({@code name}, {@code description}, {@code description_short}) as plain {@link String} + * values — NOT as language-array objects. The XML request bodies we send for create/update + * wrap these strings inside {@code } elements.

* *

Response wrappers ({@link ListResponse}, {@link SingleResponse}) match the JSON envelope * PrestaShop adds around resources: {@code {"products":[...]}} and {@code {"product":{...}}}.

@@ -25,15 +27,11 @@ public record PrestashopProductDto( /** "1" = active, "0" = inactive */ String active, @JsonProperty("id_category_default") String idCategoryDefault, - List name, - List description, - @JsonProperty("description_short") List descriptionShort + String name, + String description, + @JsonProperty("description_short") String descriptionShort ) { - /** One language entry for a multilingual field, e.g. {@code {"id":"1","value":"Name"}}. */ - @JsonIgnoreProperties(ignoreUnknown = true) - public record LangValue(String id, String value) {} - /** Envelope for {@code GET /api/products?display=full} */ @JsonIgnoreProperties(ignoreUnknown = true) public record ListResponse(List products) {} diff --git a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/ProductSyncService.java b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/ProductSyncService.java index 0e0404f..061c4e6 100644 --- a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/ProductSyncService.java +++ b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/ProductSyncService.java @@ -144,9 +144,9 @@ public class ProductSyncService { src.price(), active, categoryId, - List.of(new PrestashopProductDto.LangValue("1", label)), - List.of(new PrestashopProductDto.LangValue("1", description)), - List.of(new PrestashopProductDto.LangValue("1", "")) + label, + description, + "" ); } }