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) { private void pushProduct(DolibarrProductDto dolProduct) {
String sku = dolProduct.ref(); 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)); PrestashopProductDto created = prestashopClient.createProduct(toPrestashopDto(dolProduct, null));
if (created == null) { if (created == null) {
throw new PrestashopApiException( throw new PrestashopApiException(
"Product created in PS but not found via GET (reference=" + sku + ")"); "Product created in PS but not found via GET (reference=" + sku + ")");
} }
productMappingRepository.save(ProductMapping.builder() upsertMapping(sku, dolProduct.id(), created.id());
.sku(sku)
.dolibarrId(dolProduct.id())
.prestashopId(created.id())
.lastSyncedAt(Instant.now())
.syncStatus(SyncStatus.SYNCED)
.build());
log.debug("ProductSync: created PS product reference={} id={}", sku, 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.setLastSyncedAt(Instant.now());
mapping.setSyncStatus(SyncStatus.SYNCED); mapping.setSyncStatus(SyncStatus.SYNCED);
mapping.setErrorMessage(null); mapping.setErrorMessage(null);
productMappingRepository.save(mapping); productMappingRepository.save(mapping);
log.debug("ProductSync: updated PS product reference={}", sku);
}
} }
private void markError(String sku, String message) { private void markError(String sku, String message) {
@ -140,7 +143,7 @@ public class ProductSyncService {
String categoryId = String.valueOf(integrationProperties.prestashop().defaultCategoryId()); String categoryId = String.valueOf(integrationProperties.prestashop().defaultCategoryId());
String label = src.label() != null ? src.label() : ""; String label = src.label() != null ? src.label() : "";
String description = src.description() != null ? src.description() : ""; 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( return new PrestashopProductDto(
prestashopId, prestashopId,

View File

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