From 40184689ca8d8f75ddf90bbc1cf04e56a17d7668 Mon Sep 17 00:00:00 2001 From: gbrodman Date: Wed, 7 Jan 2026 14:12:20 -0700 Subject: [PATCH] Allow for a currency unit in fee:check responses (#2922) This is / will be required in https://datatracker.ietf.org/doc/rfc8748/. I split this out from the rest of the fee-extension testing so that it can be easily visible. --- .../flows/domain/DomainCheckFlow.java | 6 ++- .../domain/fee/FeeCheckCommandExtension.java | 9 ++++ .../FeeCheckCommandExtensionStdV1.java | 29 ++++++++++-- .../flows/domain/DomainCheckFlowTest.java | 26 +++++++++++ ...k_fee_multiple_currencies_response_v12.xml | 45 +++++++++++++++++++ ...main_check_fee_multiple_currencies_v12.xml | 16 +++++++ 6 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_response_v12.xml create mode 100644 core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_v12.xml diff --git a/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java b/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java index d93da4fa1..b77e6596e 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainCheckFlow.java @@ -88,6 +88,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import org.joda.money.CurrencyUnit; import org.joda.time.DateTime; /** @@ -298,11 +299,13 @@ public final class DomainCheckFlow implements TransactionalFlow { boolean shouldUseTieredPricingPromotion = RegistryConfig.getTieredPricingPromotionRegistrarIds().contains(registrarId); + ImmutableSet.Builder currenciesBuilder = new ImmutableSet.Builder<>(); for (FeeCheckCommandExtensionItem feeCheckItem : feeCheck.getItems()) { for (String domainName : getDomainNamesToCheckForFee(feeCheckItem, domainNames.keySet())) { FeeCheckResponseExtensionItem.Builder builder = feeCheckItem.createResponseBuilder(); Optional domain = Optional.ofNullable(domainObjs.get(domainName)); Tld tld = Tld.get(domainNames.get(domainName).parent().toString()); + currenciesBuilder.add(tld.getCurrency()); Optional token; try { // The precise token to use for this fee request may vary based on the domain or even the @@ -385,7 +388,8 @@ public final class DomainCheckFlow implements TransactionalFlow { responseItems.add(builder.setDomainNameIfSupported(domainName).build()); } } - return ImmutableList.of(feeCheck.createResponse(responseItems.build())); + return ImmutableList.of( + feeCheck.createResponse(responseItems.build(), currenciesBuilder.build())); } /** diff --git a/core/src/main/java/google/registry/model/domain/fee/FeeCheckCommandExtension.java b/core/src/main/java/google/registry/model/domain/fee/FeeCheckCommandExtension.java index 9787abfa5..d8c79b58a 100644 --- a/core/src/main/java/google/registry/model/domain/fee/FeeCheckCommandExtension.java +++ b/core/src/main/java/google/registry/model/domain/fee/FeeCheckCommandExtension.java @@ -15,6 +15,8 @@ package google.registry.model.domain.fee; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import google.registry.flows.EppException; import google.registry.model.eppinput.EppInput.CommandExtension; import org.joda.money.CurrencyUnit; @@ -42,4 +44,11 @@ public interface FeeCheckCommandExtension< ImmutableList getItems(); R createResponse(ImmutableList items); + + default R createResponse( + ImmutableList items, + ImmutableSet currenciesSeen) + throws EppException { + return createResponse(items); + } } diff --git a/core/src/main/java/google/registry/model/domain/feestdv1/FeeCheckCommandExtensionStdV1.java b/core/src/main/java/google/registry/model/domain/feestdv1/FeeCheckCommandExtensionStdV1.java index aaa2ba016..144ccf26d 100644 --- a/core/src/main/java/google/registry/model/domain/feestdv1/FeeCheckCommandExtensionStdV1.java +++ b/core/src/main/java/google/registry/model/domain/feestdv1/FeeCheckCommandExtensionStdV1.java @@ -17,6 +17,9 @@ package google.registry.model.domain.feestdv1; import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import google.registry.flows.EppException; +import google.registry.flows.EppException.ParameterValuePolicyErrorException; import google.registry.model.ImmutableObject; import google.registry.model.domain.fee.FeeCheckCommandExtension; import google.registry.model.domain.fee.FeeCheckResponseExtensionItem; @@ -51,13 +54,33 @@ public class FeeCheckCommandExtensionStdV1 extends ImmutableObject @Override public FeeCheckResponseExtensionStdV1 createResponse( ImmutableList items) { + throw new UnsupportedOperationException("FeeCheckCommandExtensionStdV1 requires a currency"); + } + + @Override + public FeeCheckResponseExtensionStdV1 createResponse( + ImmutableList items, + ImmutableSet currenciesSeen) + throws EppException { ImmutableList.Builder builder = new ImmutableList.Builder<>(); for (FeeCheckResponseExtensionItem item : items) { - if (item instanceof FeeCheckResponseExtensionItemStdV1) { - builder.add((FeeCheckResponseExtensionItemStdV1) item); + if (item instanceof FeeCheckResponseExtensionItemStdV1 stdv1Item) { + builder.add(stdv1Item); } } - return FeeCheckResponseExtensionStdV1.create(currency, builder.build()); + if (currenciesSeen.size() > 1) { + throw new MultipleCurrenciesCannotBeCheckedException(); + } + return FeeCheckResponseExtensionStdV1.create(currenciesSeen.iterator().next(), builder.build()); + } + + /** Domains across multiple currencies cannot be checked simultaneously. */ + static class MultipleCurrenciesCannotBeCheckedException + extends ParameterValuePolicyErrorException { + public MultipleCurrenciesCannotBeCheckedException() { + // The fee extension 1.0 only supports one currency shared across all results + super("Domains across multiple currencies cannot be checked simultaneously"); + } } } diff --git a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java index c2b9ac8ae..d302932fc 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java @@ -80,6 +80,7 @@ import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName import google.registry.model.domain.token.AllocationToken; import google.registry.model.domain.token.AllocationToken.TokenStatus; import google.registry.model.eppcommon.StatusValue; +import google.registry.model.registrar.Registrar; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry.HistoryEntryId; import google.registry.model.tld.Tld; @@ -788,6 +789,31 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase + + + Command completed successfully + + + + + example.example + + + example.tld + + + + + + + + example.example + + + 1 + 800 + 800 + + + + + example.tld + + + 1 + 13.00 + + + + + + ABC-12345 + server-trid + + + \ No newline at end of file diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_v12.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_v12.xml new file mode 100644 index 000000000..f066161f7 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_v12.xml @@ -0,0 +1,16 @@ + + + + + example.example + example.tld + + + + + + + + ABC-12345 + +