diff --git a/core/src/main/java/google/registry/model/registry/Registry.java b/core/src/main/java/google/registry/model/registry/Registry.java index 64819879a..dab5f7499 100644 --- a/core/src/main/java/google/registry/model/registry/Registry.java +++ b/core/src/main/java/google/registry/model/registry/Registry.java @@ -133,6 +133,7 @@ public class Registry extends ImmutableObject implements Buildable { public static final Money DEFAULT_RENEW_BILLING_COST = Money.of(USD, 8); public static final Money DEFAULT_RESTORE_BILLING_COST = Money.of(USD, 100); public static final Money DEFAULT_SERVER_STATUS_CHANGE_BILLING_COST = Money.of(USD, 20); + public static final Money DEFAULT_REGISTRY_LOCK_OR_UNLOCK_BILLING_COST = Money.of(USD, 0); /** The type of TLD, which determines things like backups and escrow policy. */ public enum TldType { @@ -478,6 +479,9 @@ public class Registry extends ImmutableObject implements Buildable { }) Money serverStatusChangeBillingCost = DEFAULT_SERVER_STATUS_CHANGE_BILLING_COST; + /** The one-time billing cost for a registry lock/unlock action initiated by a registrar. */ + Money registryLockOrUnlockBillingCost = DEFAULT_REGISTRY_LOCK_OR_UNLOCK_BILLING_COST; + /** * A property that transitions to different renew billing costs at different times. Stored as a * list of BillingCostTransition embedded objects using the @Mapify annotation. @@ -631,6 +635,11 @@ public class Registry extends ImmutableObject implements Buildable { return serverStatusChangeBillingCost; } + /** Returns the cost of a registry lock/unlock. */ + public Money getRegistryLockOrUnlockBillingCost() { + return registryLockOrUnlockBillingCost; + } + public ImmutableSortedMap getTldStateTransitions() { return tldStateTransitions.toValueMap(); } @@ -932,6 +941,12 @@ public class Registry extends ImmutableObject implements Buildable { return this; } + public Builder setRegistryLockOrUnlockBillingCost(Money amount) { + checkArgument(amount.isPositiveOrZero(), "Registry lock/unlock cost cannot be negative"); + getInstance().registryLockOrUnlockBillingCost = amount; + return this; + } + public Builder setLordnUsername(String username) { getInstance().lordnUsername = username; return this; @@ -983,6 +998,9 @@ public class Registry extends ImmutableObject implements Buildable { checkArgument( instance.getServerStatusChangeCost().getCurrencyUnit().equals(instance.currency), "Server status change cost must be in the registry's currency"); + checkArgument( + instance.getRegistryLockOrUnlockBillingCost().getCurrencyUnit().equals(instance.currency), + "Registry lock/unlock cost must be in the registry's currency"); Predicate currencyCheck = (Money money) -> money.getCurrencyUnit().equals(instance.currency); checkArgument( diff --git a/core/src/main/java/google/registry/tools/CreateOrUpdateTldCommand.java b/core/src/main/java/google/registry/tools/CreateOrUpdateTldCommand.java index 2f283cc77..d95f183e2 100644 --- a/core/src/main/java/google/registry/tools/CreateOrUpdateTldCommand.java +++ b/core/src/main/java/google/registry/tools/CreateOrUpdateTldCommand.java @@ -110,6 +110,12 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand { description = "One-time billing cost for a server status change") private Money serverStatusChangeCost; + @Nullable + @Parameter( + names = "--registry_lock_or_unlock_cost", + description = "One-time billing cost for a registry lock or unlock") + private Money registryLockOrUnlockCost; + @Nullable @Parameter( names = "--tld_type", @@ -326,6 +332,8 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand { Optional.ofNullable(roidSuffix).ifPresent(builder::setRoidSuffix); Optional.ofNullable(serverStatusChangeCost) .ifPresent(builder::setServerStatusChangeBillingCost); + Optional.ofNullable(registryLockOrUnlockCost) + .ifPresent(builder::setRegistryLockOrUnlockBillingCost); Optional.ofNullable(tldType).ifPresent(builder::setTldType); Optional.ofNullable(invoicingEnabled).ifPresent(builder::setInvoicingEnabled); Optional.ofNullable(lordnUsername).ifPresent(u -> builder.setLordnUsername(u.orElse(null))); diff --git a/core/src/main/java/google/registry/tools/DomainLockUtils.java b/core/src/main/java/google/registry/tools/DomainLockUtils.java index db71b6fad..f1cf8497e 100644 --- a/core/src/main/java/google/registry/tools/DomainLockUtils.java +++ b/core/src/main/java/google/registry/tools/DomainLockUtils.java @@ -380,7 +380,7 @@ public final class DomainLockUtils { .setReason(Reason.SERVER_STATUS) .setTargetId(domain.getForeignKey()) .setClientId(domain.getCurrentSponsorClientId()) - .setCost(Registry.get(domain.getTld()).getServerStatusChangeCost()) + .setCost(Registry.get(domain.getTld()).getRegistryLockOrUnlockBillingCost()) .setEventTime(now) .setBillingTime(now) .setParent(historyEntry) diff --git a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java index 797d34c77..5307ab1a2 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java @@ -597,6 +597,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase { assertThat(registry.getRedemptionGracePeriodLength()) .isEqualTo(Registry.DEFAULT_REDEMPTION_GRACE_PERIOD); assertThat(registry.getPendingDeleteLength()).isEqualTo(Registry.DEFAULT_PENDING_DELETE_LENGTH); + assertThat(registry.getRegistryLockOrUnlockBillingCost()) + .isEqualTo(Registry.DEFAULT_REGISTRY_LOCK_OR_UNLOCK_BILLING_COST); } @Test @@ -230,6 +232,17 @@ class CreateTldCommandTest extends CommandTestCase { .isEqualTo(Money.of(USD, 42.42)); } + @Test + void testSuccess_registryLockOrUnlockCostFlag() throws Exception { + runCommandForced( + "--registry_lock_or_unlock_cost=\"USD 42.42\"", + "--roid_suffix=Q9JYB4C", + "--dns_writers=VoidDnsWriter", + "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getRegistryLockOrUnlockBillingCost()) + .isEqualTo(Money.of(USD, 42.42)); + } + @Test void testSuccess_nonUsdBillingCostFlag() throws Exception { runCommandForced( @@ -237,6 +250,7 @@ class CreateTldCommandTest extends CommandTestCase { "--restore_billing_cost=\"JPY 67890\"", "--initial_renew_billing_cost=\"JPY 101112\"", "--server_status_change_cost=\"JPY 97865\"", + "--registry_lock_or_unlock_cost=\"JPY 9001\"", "--roid_suffix=Q9JYB4C", "--dns_writers=VoidDnsWriter", "xn--q9jyb4c"); diff --git a/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java b/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java index bc4f89658..77f4899df 100644 --- a/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java +++ b/core/src/test/java/google/registry/tools/DomainLockUtilsTest.java @@ -528,7 +528,7 @@ public final class DomainLockUtilsTest { .setReason(Reason.SERVER_STATUS) .setTargetId(domain.getForeignKey()) .setClientId(domain.getCurrentSponsorClientId()) - .setCost(Registry.get(domain.getTld()).getServerStatusChangeCost()) + .setCost(Registry.get(domain.getTld()).getRegistryLockOrUnlockBillingCost()) .setEventTime(clock.nowUtc()) .setBillingTime(clock.nowUtc()) .setParent(entry) diff --git a/core/src/test/java/google/registry/tools/UpdateTldCommandTest.java b/core/src/test/java/google/registry/tools/UpdateTldCommandTest.java index 25794fdcd..726a6c46f 100644 --- a/core/src/test/java/google/registry/tools/UpdateTldCommandTest.java +++ b/core/src/test/java/google/registry/tools/UpdateTldCommandTest.java @@ -212,19 +212,21 @@ class UpdateTldCommandTest extends CommandTestCase { ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 1))) .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(JPY))) .setServerStatusChangeBillingCost(Money.ofMajor(JPY, 1)) + .setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 1)) .build()); runCommandForced( "--create_billing_cost=\"JPY 12345\"", "--restore_billing_cost=\"JPY 67890\"", "--renew_billing_cost_transitions=\"0=JPY 101112\"", "--server_status_change_cost=\"JPY 97865\"", + "--registry_lock_or_unlock_cost=\"JPY 9001\"", "xn--q9jyb4c"); - assertThat(Registry.get("xn--q9jyb4c").getStandardCreateCost()) - .isEqualTo(Money.ofMajor(JPY, 12345)); - assertThat(Registry.get("xn--q9jyb4c").getStandardRestoreCost()) - .isEqualTo(Money.ofMajor(JPY, 67890)); - assertThat(Registry.get("xn--q9jyb4c").getStandardRenewCost(START_OF_TIME)) - .isEqualTo(Money.ofMajor(JPY, 101112)); + Registry registry = Registry.get("xn--q9jyb4c"); + assertThat(registry.getStandardCreateCost()).isEqualTo(Money.ofMajor(JPY, 12345)); + assertThat(registry.getStandardRestoreCost()).isEqualTo(Money.ofMajor(JPY, 67890)); + assertThat(registry.getStandardRenewCost(START_OF_TIME)).isEqualTo(Money.ofMajor(JPY, 101112)); + assertThat(registry.getServerStatusChangeCost()).isEqualTo(Money.ofMajor(JPY, 97865)); + assertThat(registry.getRegistryLockOrUnlockBillingCost()).isEqualTo(Money.ofMajor(JPY, 9001)); } @Test diff --git a/core/src/test/java/google/registry/ui/server/registrar/RegistryLockVerifyActionTest.java b/core/src/test/java/google/registry/ui/server/registrar/RegistryLockVerifyActionTest.java index 9458681d3..cb2be1b48 100644 --- a/core/src/test/java/google/registry/ui/server/registrar/RegistryLockVerifyActionTest.java +++ b/core/src/test/java/google/registry/ui/server/registrar/RegistryLockVerifyActionTest.java @@ -317,7 +317,7 @@ final class RegistryLockVerifyActionTest { .setReason(Reason.SERVER_STATUS) .setTargetId(domain.getForeignKey()) .setClientId(domain.getCurrentSponsorClientId()) - .setCost(Registry.get(domain.getTld()).getServerStatusChangeCost()) + .setCost(Registry.get(domain.getTld()).getRegistryLockOrUnlockBillingCost()) .setEventTime(fakeClock.nowUtc()) .setBillingTime(fakeClock.nowUtc()) .setParent(historyEntry) diff --git a/core/src/test/resources/google/registry/model/schema.txt b/core/src/test/resources/google/registry/model/schema.txt index fe487b033..da603505d 100644 --- a/core/src/test/resources/google/registry/model/schema.txt +++ b/core/src/test/resources/google/registry/model/schema.txt @@ -640,6 +640,7 @@ class google.registry.model.registry.Registry { java.util.Set dnsWriters; org.joda.money.CurrencyUnit currency; org.joda.money.Money createBillingCost; + org.joda.money.Money registryLockOrUnlockBillingCost; org.joda.money.Money restoreBillingCost; org.joda.money.Money serverStatusChangeBillingCost; org.joda.time.DateTime claimsPeriodEnd;