diff --git a/docs/flows.md b/docs/flows.md index e8de6a1c237..80e5ed56cc0 100644 --- a/docs/flows.md +++ b/docs/flows.md @@ -517,6 +517,8 @@ An EPP flow that creates a new domain resource. * Service extension(s) must be declared at login. * The current registry phase does not allow for general registrations. * 2003 + * Fees must be explicitly acknowledged when creating domains during the + Early Access Program. * Fees must be explicitly acknowledged when performing any operations on a premium name. * Admin contact is required. diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java index cf49d028623..724f94ec1db 100644 --- a/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/java/google/registry/flows/domain/DomainCreateFlow.java @@ -133,6 +133,7 @@ * @error {@link DomainFlowUtils.ExceedsMaxRegistrationYearsException} * @error {@link DomainFlowUtils.ExpiredClaimException} * @error {@link DomainFlowUtils.FeesMismatchException} + * @error {@link DomainFlowUtils.FeesRequiredDuringEarlyAccessProgramException} * @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException} * @error {@link DomainFlowUtils.InvalidIdnDomainLabelException} * @error {@link DomainFlowUtils.InvalidLrpTokenException} diff --git a/java/google/registry/flows/domain/DomainFlowUtils.java b/java/google/registry/flows/domain/DomainFlowUtils.java index 02dc9d329ab..67b1077f1b7 100644 --- a/java/google/registry/flows/domain/DomainFlowUtils.java +++ b/java/google/registry/flows/domain/DomainFlowUtils.java @@ -631,6 +631,9 @@ && isDomainPremium(domainName, priceTime) // This only happens when the total fees are non-zero and include custom fees requiring the // extension. if (feeCommand == null) { + if (!feesAndCredits.getEapCost().isZero()) { + throw new FeesRequiredDuringEarlyAccessProgramException(feesAndCredits.getEapCost()); + } if (feesAndCredits.getTotalCost().isZero() || !feesAndCredits.isFeeExtensionRequired()) { return; } @@ -1167,9 +1170,6 @@ static class FeesRequiredForPremiumNameException extends RequiredParameterMissin /** Fees must be explicitly acknowledged when performing an operation which is not free. */ static class FeesRequiredForNonFreeOperationException extends RequiredParameterMissingException { - FeesRequiredForNonFreeOperationException() { - super("Fees must be explicitly acknowledged when performing an operation which is not free."); - } public FeesRequiredForNonFreeOperationException(Money expectedFee) { super( @@ -1179,6 +1179,18 @@ public FeesRequiredForNonFreeOperationException(Money expectedFee) { } } + /** Fees must be explicitly acknowledged when creating domains during the Early Access Program. */ + static class FeesRequiredDuringEarlyAccessProgramException + extends RequiredParameterMissingException { + + public FeesRequiredDuringEarlyAccessProgramException(Money expectedFee) { + super( + "Fees must be explicitly acknowledged when creating domains " + + "during the Early Access Program. The EAP fee is: " + + expectedFee); + } + } + /** The 'grace-period', 'applied' and 'refundable' fields are disallowed by server policy. */ static class UnsupportedFeeAttributeException extends UnimplementedOptionException { UnsupportedFeeAttributeException() { diff --git a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java index 003aaf65be3..c2f0ee66f83 100644 --- a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java @@ -43,6 +43,7 @@ import static google.registry.testing.DatastoreHelper.persistResource; import static google.registry.testing.DomainResourceSubject.assertAboutDomains; import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; +import static google.registry.testing.JUnitBackports.expectThrows; import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued; import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued; import static google.registry.testing.TaskQueueHelper.assertNoTasksEnqueued; @@ -82,6 +83,7 @@ import google.registry.flows.domain.DomainFlowUtils.ExceedsMaxRegistrationYearsException; import google.registry.flows.domain.DomainFlowUtils.ExpiredClaimException; import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; +import google.registry.flows.domain.DomainFlowUtils.FeesRequiredDuringEarlyAccessProgramException; import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForPremiumNameException; import google.registry.flows.domain.DomainFlowUtils.InvalidIdnDomainLabelException; import google.registry.flows.domain.DomainFlowUtils.InvalidLrpTokenException; @@ -1967,6 +1969,27 @@ public void testSuccess_eapFeeApplied_v12() throws Exception { "tld", "domain_create_response_eap_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12")); } + @Test + public void testFailure_domainInEap_failsWithoutFeeExtension() throws Exception { + persistContactsAndHosts(); + persistResource( + Registry.get("tld") + .asBuilder() + .setEapFeeSchedule( + ImmutableSortedMap.of( + START_OF_TIME, Money.of(USD, 0), + clock.nowUtc().minusDays(1), Money.of(USD, 100), + clock.nowUtc().plusDays(1), Money.of(USD, 0))) + .build()); + Exception e = expectThrows(FeesRequiredDuringEarlyAccessProgramException.class, this::runFlow); + assertThat(e) + .hasMessageThat() + .isEqualTo( + "Fees must be explicitly acknowledged when creating domains " + + "during the Early Access Program. The EAP fee is: USD 100.00"); + + } + @Test public void testSuccess_eapFee_beforeEntireSchedule() throws Exception { persistContactsAndHosts();