fix: map Dolibarr tva_tx to PS id_tax_rules_group on product sync

Price with VAT was showing the same value as price without VAT because
id_tax_rules_group was hardcoded to 1 (no-tax group in this PS instance).

Now reads tva_tx from Dolibarr product, resolves the PS tax rule group
via a configurable map (integration.prestashop.tax-rule-groups), and
sets the correct group in the product XML. Defaults to
default-tax-rules-group-id when no mapping is found.

ES groups configured: 21% → 53, 10% → 54, 4% → 55.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
luklpz 2026-05-28 18:47:55 +02:00
parent c59d2048db
commit df3775d96b
7 changed files with 52 additions and 10 deletions

View File

@ -3,8 +3,11 @@ package com.teterialosjuanjos.tfg.sync_service.config;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.validation.annotation.Validated;
import java.util.Map;
/**
* Externalized configuration for Dolibarr and PrestaShop integration endpoints.
* Bound from {@code integration.*} properties in application.yml; validated at startup.
@ -28,16 +31,23 @@ public record IntegrationProperties(
) {}
/**
* @param baseUrl full API base URL, e.g. {@code https://host/tienda/api}
* @param apiKey webservice key sent as {@code ws_key} query param
* @param defaultCategoryId PrestaShop category ID assigned to new products (default: 2 = Home)
* @param languageId PrestaShop language ID used for all multilingual fields (name, description, etc.)
* Check yours at GET /api/languages. Default 1 is usually English; set to Spanish ID.
* @param baseUrl full API base URL, e.g. {@code https://host/tienda/api}
* @param apiKey webservice key sent as {@code ws_key} query param
* @param defaultCategoryId PrestaShop category ID assigned to new products (default: 2 = Home)
* @param languageId PrestaShop language ID used for all multilingual fields (name, description, etc.)
* Check yours at GET /api/languages. Default 1 is usually English; set to Spanish ID.
* @param defaultTaxRulesGroupId Fallback PS {@code id_tax_rules_group} when the product's Dolibarr {@code tva_tx}
* has no entry in {@code taxRuleGroups}. Defaults to 1.
* Check your PS tax groups at GET /api/tax_rule_groups.
* @param taxRuleGroups Map of Dolibarr VAT rate (integer key, e.g. "21") to PS {@code id_tax_rules_group}.
* Configure in application-dev/prod.yml. If empty, {@code defaultTaxRulesGroupId} is used.
*/
public record Prestashop(
@NotBlank String baseUrl,
@NotBlank String apiKey,
int defaultCategoryId,
int languageId
int languageId,
@DefaultValue("1") int defaultTaxRulesGroupId,
Map<String, Integer> taxRuleGroups
) {}
}

View File

@ -26,5 +26,7 @@ public record DolibarrProductDto(
@JsonProperty("tosell") Integer toSell,
/** 0 = physical product, 1 = service */
Integer type,
Double weight
Double weight,
/** VAT rate in percent, e.g. 21.0 for 21% IVA */
@JsonProperty("tva_tx") Double tvaTx
) {}

View File

@ -371,7 +371,8 @@ public class PrestashopClient {
sb.append("<id_category_default>").append(escapeXml(dto.idCategoryDefault())).append("</id_category_default>");
}
sb.append("<state>1</state>");
sb.append("<id_tax_rules_group>1</id_tax_rules_group>");
int taxRulesGroupId = dto.taxRulesGroupId() != null ? dto.taxRulesGroupId() : 1;
sb.append("<id_tax_rules_group>").append(taxRulesGroupId).append("</id_tax_rules_group>");
sb.append("<id_shop_default>1</id_shop_default>");
sb.append("<available_for_order>1</available_for_order>");
sb.append("<show_price>1</show_price>");

View File

@ -34,7 +34,9 @@ public record PrestashopProductDto(
@JsonProperty("description_short")
@JsonDeserialize(using = MultilangStringDeserializer.class) String descriptionShort,
/** PS category IDs to set on write; not present in PS JSON responses (ignored on read). */
@JsonIgnore List<String> categoryIds
@JsonIgnore List<String> categoryIds,
/** PS tax rule group ID; resolved from Dolibarr tva_tx at sync time, write-only. */
@JsonIgnore Integer taxRulesGroupId
) {
/** Envelope for {@code GET /api/products?display=full} */

View File

@ -19,6 +19,7 @@ import org.springframework.web.client.RestClientException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@ -249,6 +250,7 @@ public class ProductSyncService {
String description = src.description() != null ? src.description() : "";
String descriptionShort = src.notePublic() != null ? src.notePublic() : "";
String active = (src.toSell() != null && src.toSell() == 0) ? "0" : "1";
Integer taxRulesGroupId = resolveTaxRulesGroup(src.tvaTx());
return new PrestashopProductDto(
prestashopId,
@ -259,7 +261,22 @@ public class ProductSyncService {
label,
description,
descriptionShort,
allCategoryIds
allCategoryIds,
taxRulesGroupId
);
}
/**
* Resolves the PrestaShop {@code id_tax_rules_group} from the Dolibarr VAT rate.
* Looks up {@code tvaTx} (truncated to int, e.g. 21.0 → "21") in the configured map.
* Falls back to {@code defaultTaxRulesGroupId} when no mapping exists.
*/
private Integer resolveTaxRulesGroup(Double tvaTx) {
Map<String, Integer> map = integrationProperties.prestashop().taxRuleGroups();
if (tvaTx != null && map != null && !map.isEmpty()) {
Integer groupId = map.get(String.valueOf(tvaTx.intValue()));
if (groupId != null) return groupId;
}
return integrationProperties.prestashop().defaultTaxRulesGroupId();
}
}

View File

@ -29,6 +29,11 @@ integration:
api-key: DOLIBARR_API_KEY_AQUI
prestashop:
api-key: PRESTASHOP_API_KEY_AQUI
default-tax-rules-group-id: 53 # ES Standard rate (21%) — fallback
tax-rule-groups:
21: 53 # ES Standard rate (21%)
10: 54 # ES Reduced Rate (10%)
4: 55 # ES Super Reduced Rate (4%)
logging:
level:

View File

@ -17,6 +17,11 @@ integration:
api-key: ${PRESTASHOP_API_KEY}
default-category-id: 2
language-id: ${PRESTASHOP_LANGUAGE_ID:1} # set to your Spanish language ID (check GET /api/languages)
default-tax-rules-group-id: 53 # ES Standard rate (21%) — fallback
tax-rule-groups:
21: 53 # ES Standard rate (21%)
10: 54 # ES Reduced Rate (10%)
4: 55 # ES Super Reduced Rate (4%)
api:
security: