fix: use PS as source of truth in product sync; fix active default

ProductSyncService now queries PS by reference before deciding
create vs update, preventing stale local mappings from causing
silent no-ops when PS products are deleted externally.

Also fix active field default: tosell=null now maps to active=1
instead of active=0, so products without an explicit sell flag
are created as visible in PrestaShop.

Add server.forward-headers-strategy=framework so Spring reads
X-Forwarded-Proto from Railway's reverse proxy; fixes Swagger UI
generating http:// URLs instead of https://.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
luklpz 2026-05-17 17:36:26 +02:00
parent f50f64dcdf
commit 60dba82f32
2 changed files with 25 additions and 19 deletions

View File

@ -94,32 +94,35 @@ public class ProductSyncService {
private void pushProduct(DolibarrProductDto dolProduct) {
String sku = dolProduct.ref();
Optional<ProductMapping> existing = productMappingRepository.findBySku(sku);
if (existing.isEmpty()) {
// PS is source of truth: local mapping may be stale if PS products were deleted
Optional<PrestashopProductDto> existingPs = prestashopClient.getProductByReference(sku);
if (existingPs.isPresent()) {
Integer psId = existingPs.get().id();
prestashopClient.updateProduct(psId, toPrestashopDto(dolProduct, psId));
upsertMapping(sku, dolProduct.id(), psId);
log.debug("ProductSync: updated PS product reference={} id={}", sku, psId);
} else {
PrestashopProductDto created = prestashopClient.createProduct(toPrestashopDto(dolProduct, null));
if (created == null) {
throw new PrestashopApiException(
"Product created in PS but not found via GET (reference=" + sku + ")");
}
productMappingRepository.save(ProductMapping.builder()
.sku(sku)
.dolibarrId(dolProduct.id())
.prestashopId(created.id())
.lastSyncedAt(Instant.now())
.syncStatus(SyncStatus.SYNCED)
.build());
upsertMapping(sku, dolProduct.id(), created.id());
log.debug("ProductSync: created PS product reference={} id={}", sku, created.id());
} else {
ProductMapping mapping = existing.get();
prestashopClient.updateProduct(mapping.getPrestashopId(),
toPrestashopDto(dolProduct, mapping.getPrestashopId()));
}
}
private void upsertMapping(String sku, Integer dolibarrId, Integer prestashopId) {
ProductMapping mapping = productMappingRepository.findBySku(sku)
.orElseGet(() -> ProductMapping.builder().sku(sku).build());
mapping.setDolibarrId(dolibarrId);
mapping.setPrestashopId(prestashopId);
mapping.setLastSyncedAt(Instant.now());
mapping.setSyncStatus(SyncStatus.SYNCED);
mapping.setErrorMessage(null);
productMappingRepository.save(mapping);
log.debug("ProductSync: updated PS product reference={}", sku);
}
}
private void markError(String sku, String message) {
@ -140,7 +143,7 @@ public class ProductSyncService {
String categoryId = String.valueOf(integrationProperties.prestashop().defaultCategoryId());
String label = src.label() != null ? src.label() : "";
String description = src.description() != null ? src.description() : "";
String active = (src.toSell() != null && src.toSell() == 1) ? "1" : "0";
String active = (src.toSell() != null && src.toSell() == 0) ? "0" : "1";
return new PrestashopProductDto(
prestashopId,

View File

@ -4,6 +4,9 @@ spring:
profiles:
active: dev
server:
forward-headers-strategy: framework
integration:
dolibarr:
base-url: ${DOLIBARR_BASE_URL:https://prestashop.loading.net/dolibarr/api/index.php}