diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java index e3dfd7cb4..638b0c245 100644 --- a/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/java/google/registry/flows/domain/DomainCreateFlow.java @@ -295,6 +295,7 @@ public class DomainCreateFlow implements TransactionalFlow { years, feesAndCredits, historyEntry, + allocationToken, now); // Create a new autorenew billing event and poll message starting at the expiration time. BillingEvent.Recurring autorenewBillingEvent = @@ -477,6 +478,7 @@ public class DomainCreateFlow implements TransactionalFlow { int years, FeesAndCredits feesAndCredits, HistoryEntry historyEntry, + Optional allocationToken, DateTime now) { ImmutableSet.Builder flagsBuilder = new ImmutableSet.Builder<>(); // Sunrise and anchor tenancy are orthogonal tags and thus both can be present together. @@ -497,6 +499,7 @@ public class DomainCreateFlow implements TransactionalFlow { .setPeriodYears(years) .setCost(feesAndCredits.getCreateCost()) .setEventTime(now) + .setAllocationToken(allocationToken.map(Key::create).orElse(null)) .setBillingTime( now.plus( isAnchorTenant diff --git a/java/google/registry/model/billing/BillingEvent.java b/java/google/registry/model/billing/BillingEvent.java index 1bd18747b..696cb3285 100644 --- a/java/google/registry/model/billing/BillingEvent.java +++ b/java/google/registry/model/billing/BillingEvent.java @@ -40,6 +40,7 @@ import google.registry.model.annotations.ReportedOn; import google.registry.model.common.TimeOfYear; import google.registry.model.domain.GracePeriod; import google.registry.model.domain.rgp.GracePeriodStatus; +import google.registry.model.domain.token.AllocationToken; import google.registry.model.reporting.HistoryEntry; import google.registry.model.transfer.TransferData.TransferServerApproveEntity; import java.util.Objects; @@ -244,6 +245,11 @@ public abstract class BillingEvent extends ImmutableObject */ Key cancellationMatchingBillingEvent; + /** + * The {@link AllocationToken} used in the creation of this event, or null if one was not used. + */ + @Index @Nullable Key allocationToken; + public Money getCost() { return cost; } @@ -264,6 +270,10 @@ public abstract class BillingEvent extends ImmutableObject return cancellationMatchingBillingEvent; } + public Optional> getAllocationToken() { + return Optional.ofNullable(allocationToken); + } + @Override public Builder asBuilder() { return new Builder(clone(this)); @@ -306,6 +316,11 @@ public abstract class BillingEvent extends ImmutableObject return this; } + public Builder setAllocationToken(@Nullable Key allocationToken) { + getInstance().allocationToken = allocationToken; + return this; + } + @Override public OneTime build() { OneTime instance = getInstance(); diff --git a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java index db61245b4..6eae42145 100644 --- a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth8.assertThat; import static google.registry.flows.FlowTestCase.UserPrivileges.SUPERUSER; import static google.registry.model.billing.BillingEvent.Flag.ANCHOR_TENANT; +import static google.registry.model.billing.BillingEvent.Flag.RESERVED; import static google.registry.model.billing.BillingEvent.Flag.SUNRISE; import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS; import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; @@ -151,6 +152,7 @@ import google.registry.model.reporting.HistoryEntry; import google.registry.monitoring.whitebox.EppMetric; import google.registry.testing.TaskQueueHelper.TaskMatcher; import java.util.Map; +import javax.annotation.Nullable; import org.joda.money.Money; import org.joda.time.DateTime; import org.joda.time.Duration; @@ -162,6 +164,8 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase expectedBillingFlags) throws Exception { + assertSuccessfulCreate(domainTld, expectedBillingFlags, null); + } + + private void assertSuccessfulCreate( + String domainTld, + ImmutableSet expectedBillingFlags, + @Nullable AllocationToken allocationToken) + throws Exception { DomainBase domain = reloadResourceByForeignKey(); boolean isAnchorTenant = expectedBillingFlags.contains(ANCHOR_TENANT); @@ -252,6 +265,7 @@ public class DomainCreateFlowTest extends ResourceFlowTestCasenaturalOrder() + .put(DateTimeUtils.START_OF_TIME, TokenStatus.NOT_STARTED) + .put(DateTime.now(UTC), TokenStatus.VALID) + .put(DateTime.now(UTC).plusWeeks(8), TokenStatus.ENDED) + .build()) + .build()); + + oneTime = + persistResource( + commonInit( + new BillingEvent.OneTime.Builder() + .setParent(historyEntry) + .setReason(Reason.CREATE) + .setFlags(ImmutableSet.of(BillingEvent.Flag.ANCHOR_TENANT)) + .setPeriodYears(2) + .setCost(Money.of(USD, 1)) + .setEventTime(now) + .setBillingTime(now.plusDays(5)) + .setAllocationToken(Key.create(allocationToken)))); + recurring = + persistResource( + commonInit( + new BillingEvent.Recurring.Builder() + .setParent(historyEntry) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setReason(Reason.RENEW) + .setEventTime(now.plusYears(1)) + .setRecurrenceEndTime(END_OF_TIME))); oneTimeSynthetic = persistResource(commonInit( new BillingEvent.OneTime.Builder() .setParent(historyEntry) @@ -166,9 +190,20 @@ public class BillingEventTest extends EntityTestCase { @Test public void testIndexing() throws Exception { - verifyIndexing(oneTime, "clientId", "eventTime", "billingTime", "syntheticCreationTime"); verifyIndexing( - oneTimeSynthetic, "clientId", "eventTime", "billingTime", "syntheticCreationTime"); + oneTime, + "clientId", + "eventTime", + "billingTime", + "syntheticCreationTime", + "allocationToken"); + verifyIndexing( + oneTimeSynthetic, + "clientId", + "eventTime", + "billingTime", + "syntheticCreationTime", + "allocationToken"); verifyIndexing( recurring, "clientId", "eventTime", "recurrenceEndTime", "recurrenceTimeOfYear.timeString"); verifyIndexing(cancellationOneTime, "clientId", "eventTime", "billingTime"); diff --git a/javatests/google/registry/model/testdata/schema.txt b/javatests/google/registry/model/testdata/schema.txt index 58dab4b79..eaf0b7e1a 100644 --- a/javatests/google/registry/model/testdata/schema.txt +++ b/javatests/google/registry/model/testdata/schema.txt @@ -41,6 +41,7 @@ class google.registry.model.billing.BillingEvent$OneTime { @Id long id; @Parent com.googlecode.objectify.Key parent; com.googlecode.objectify.Key cancellationMatchingBillingEvent; + com.googlecode.objectify.Key allocationToken; google.registry.model.billing.BillingEvent$Reason reason; java.lang.Integer periodYears; java.lang.String clientId;