fix: fetch all Dolibarr products without tms sqlfilter

Incremental sync via t.tms filter breaks when products were created before
the service started running: their tms is older than lastSyncStart so they
are never returned. Since the sync is idempotent (ProductMapping handles
create-vs-update), always fetching all products is safe and simpler.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
luklpz 2026-05-14 21:04:09 +02:00
parent 359590b7d8
commit 806497b24d
2 changed files with 9 additions and 26 deletions

View File

@ -7,9 +7,6 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
@ -24,9 +21,6 @@ import java.util.Map;
@Component
public class DolibarrClient {
private static final DateTimeFormatter DOLIBARR_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);
private final RestClient restClient;
public DolibarrClient(@Qualifier("dolibarrRestClient") RestClient restClient) {
@ -36,20 +30,15 @@ public class DolibarrClient {
// ── Products ──────────────────────────────────────────────────────────
/**
* Returns all products, optionally filtered by last modification date.
* Returns all active products (up to 500).
*
* @param modifiedSince if non-null, only products with {@code tms >= modifiedSince} are returned
* <p>Full fetch on every run keeps sync idempotent and avoids timezone issues
* with Dolibarr's {@code tms} column filter. The service handles create-vs-update
* via {@code ProductMapping}, so re-processing unchanged products is safe.</p>
*/
public List<DolibarrProductDto> getProducts(Instant modifiedSince) {
public List<DolibarrProductDto> getProducts() {
return restClient.get()
.uri(u -> {
u.path("/products").queryParam("limit", 500);
if (modifiedSince != null) {
u.queryParam("sqlfilters",
"(t.tms:>=:'%s')".formatted(DOLIBARR_DATE_FORMAT.format(modifiedSince)));
}
return u.build();
})
.uri(u -> u.path("/products").queryParam("limit", 500).build())
.retrieve()
.body(new ParameterizedTypeReference<List<DolibarrProductDto>>() {});
}

View File

@ -40,15 +40,9 @@ public class ProductSyncService {
private final IntegrationProperties integrationProperties;
/**
* Executes a full incremental product push and returns a summary.
* Fetches all Dolibarr products and pushes them to PrestaShop (create or update by SKU).
*/
public SyncResult synchronize() {
// Determine cutoff BEFORE saving current log to avoid self-reference
Instant lastSyncStart = syncLogRepository
.findFirstBySyncTypeOrderByStartedAtDesc(SyncType.PRODUCT_PUSH)
.map(SyncLog::getStartedAt)
.orElse(null);
SyncLog syncLog = syncLogRepository.save(SyncLog.builder()
.syncType(SyncType.PRODUCT_PUSH)
.startedAt(Instant.now())
@ -59,8 +53,8 @@ public class ProductSyncService {
List<String> errors = new ArrayList<>();
try {
List<DolibarrProductDto> products = dolibarrClient.getProducts(lastSyncStart);
log.info("ProductSync: {} products to process (since {})", products.size(), lastSyncStart);
List<DolibarrProductDto> products = dolibarrClient.getProducts();
log.info("ProductSync: {} products to process", products.size());
for (DolibarrProductDto product : products) {
if (product.ref() == null || product.ref().isBlank()) {