Generate sql schema for BillingEvent (#565)

* Generate sql schema for BillingEvent

* Change to use sequence

* Address comments

* Resolve warnings and remove duplicate cost related fields

* Increase the flayway file version to V25

* Remove extra space

* Split to 3 tables, merge VKey

* Rename talbes

* Rename repoId to domainRepoId

* Exclude VKey in schema.txt

* Rename target_id to domain_name

* Fix javadoc

* Resolve comments
This commit is contained in:
Shicong Huang 2020-05-27 15:59:19 -04:00 committed by GitHub
parent 02e43ab134
commit cf092c7e50
22 changed files with 941 additions and 179 deletions

View file

@ -155,15 +155,21 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
}
int numBillingEventsSaved = 0;
try {
numBillingEventsSaved = tm().transactNew(() -> {
numBillingEventsSaved =
tm().transactNew(
() -> {
ImmutableSet.Builder<OneTime> syntheticOneTimesBuilder =
new ImmutableSet.Builder<>();
final Registry tld = Registry.get(getTldFromDomainName(recurring.getTargetId()));
final Registry tld =
Registry.get(getTldFromDomainName(recurring.getTargetId()));
// Determine the complete set of times at which this recurring event should occur
// (up to and including the runtime of the mapreduce).
// Determine the complete set of times at which this recurring event should
// occur (up to and including the runtime of the mapreduce).
Iterable<DateTime> eventTimes =
recurring.getRecurrenceTimeOfYear().getInstancesInRange(Range.closed(
recurring
.getRecurrenceTimeOfYear()
.getInstancesInRange(
Range.closed(
recurring.getEventTime(),
earliestOf(recurring.getRecurrenceEndTime(), executeTime)));
@ -181,28 +187,32 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
ImmutableSet.Builder<HistoryEntry> historyEntriesBuilder =
new ImmutableSet.Builder<>();
// Create synthetic OneTime events for all billing times that do not yet have an event
// persisted.
// Create synthetic OneTime events for all billing times that do not yet have
// an event persisted.
for (DateTime billingTime : difference(billingTimes, existingBillingTimes)) {
// Construct a new HistoryEntry that parents over the OneTime
HistoryEntry historyEntry = new HistoryEntry.Builder()
HistoryEntry historyEntry =
new HistoryEntry.Builder()
.setBySuperuser(false)
.setClientId(recurring.getClientId())
.setModificationTime(tm().getTransactionTime())
.setParent(domainKey)
.setPeriod(Period.create(1, YEARS))
.setReason("Domain autorenewal by ExpandRecurringBillingEventsAction")
.setReason(
"Domain autorenewal by ExpandRecurringBillingEventsAction")
.setRequestedByRegistrar(false)
.setType(DOMAIN_AUTORENEW)
// Don't write a domain transaction record if the recurrence was ended prior to the
// billing time (i.e. a domain was deleted during the autorenew grace period).
// Don't write a domain transaction record if the recurrence was
// ended prior to the billing time (i.e. a domain was deleted
// during the autorenew grace period).
.setDomainTransactionRecords(
recurring.getRecurrenceEndTime().isBefore(billingTime)
? ImmutableSet.of()
: ImmutableSet.of(
DomainTransactionRecord.create(
tld.getTldStr(),
// We report this when the autorenew grace period ends
// We report this when the autorenew grace period
// ends
billingTime,
TransactionReportField.netRenewsFieldFromYears(1),
1)))
@ -212,7 +222,8 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
DateTime eventTime = billingTime.minus(tld.getAutoRenewGracePeriodLength());
// Determine the cost for a one-year renewal.
Money renewCost = getDomainRenewCost(recurring.getTargetId(), eventTime, 1);
syntheticOneTimesBuilder.add(new OneTime.Builder()
syntheticOneTimesBuilder.add(
new OneTime.Builder()
.setBillingTime(billingTime)
.setClientId(recurring.getClientId())
.setCost(renewCost)
@ -222,7 +233,7 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
.setPeriodYears(1)
.setReason(recurring.getReason())
.setSyntheticCreationTime(executeTime)
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.setTargetId(recurring.getTargetId())
.build());
}
@ -279,7 +290,8 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
return Streams.stream(oneTimesForDomain)
.filter(
billingEvent ->
Key.create(recurringEvent)
recurringEvent
.createVKey()
.equals(billingEvent.getCancellationMatchingBillingEvent()))
.map(OneTime::getBillingTime)
.collect(toImmutableSet());

View file

@ -534,7 +534,7 @@ public class DomainCreateFlow implements TransactionalFlow {
.setPeriodYears(years)
.setCost(feesAndCredits.getCreateCost())
.setEventTime(now)
.setAllocationToken(allocationToken.map(Key::create).orElse(null))
.setAllocationToken(allocationToken.map(AllocationToken::createVKey).orElse(null))
.setBillingTime(
now.plus(
isAnchorTenant

View file

@ -34,6 +34,7 @@ import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.Parent;
import google.registry.persistence.VKey;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@ -139,10 +140,13 @@ public class ModelUtils {
// If the field's type is the same as the field's class object, then it's a non-parameterized
// type, and thus we just add it directly. We also don't bother looking at the parameterized
// types of Key objects, since they are just references to other objects and don't actually
// embed themselves in the persisted object anyway.
// types of Key and VKey objects, since they are just references to other objects and don't
// actually embed themselves in the persisted object anyway.
Class<?> fieldClazz = field.getType();
Type fieldType = field.getGenericType();
if (VKey.class.equals(fieldClazz)) {
continue;
}
builder.add(fieldClazz);
if (fieldType.equals(fieldClazz) || Key.class.equals(clazz)) {
continue;

View file

@ -30,6 +30,7 @@ import com.google.common.collect.Sets;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.Parent;
@ -43,14 +44,28 @@ 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 google.registry.persistence.VKey;
import google.registry.persistence.WithLongVKey;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.joda.money.Money;
import org.joda.time.DateTime;
/** A billable event in a domain's lifecycle. */
@MappedSuperclass
@WithLongVKey
public abstract class BillingEvent extends ImmutableObject
implements Buildable, TransferServerApproveEntity {
@ -93,24 +108,41 @@ public abstract class BillingEvent extends ImmutableObject
/** Entity id. */
@Id
long id;
@javax.persistence.Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@Parent
@DoNotHydrate
Key<HistoryEntry> parent;
@Parent @DoNotHydrate @Transient Key<HistoryEntry> parent;
/** The registrar to bill. */
@Index
@Column(nullable = false)
String clientId;
/** Revision id of the entry in DomainHistory table that ths bill belongs to. */
// TODO(shicong): Add foreign key constraint when DomainHistory table is generated
@Ignore
@Column(nullable = false)
Long domainHistoryRevisionId;
/** ID of the EPP resource that the bill is for. */
// TODO(shicong): Add foreign key constraint when we expand DatastoreHelp for Postgresql
@Ignore
@Column(nullable = false)
String domainRepoId;
/** When this event was created. For recurring events, this is also the recurrence start time. */
@Index
@Column(nullable = false)
DateTime eventTime;
/** The reason for the bill. */
@Enumerated(EnumType.STRING)
@Column(nullable = false)
Reason reason;
/** The fully qualified domain name of the domain that the bill is for. */
@Column(name = "domain_name", nullable = false)
String targetId;
@Nullable
@ -120,6 +152,14 @@ public abstract class BillingEvent extends ImmutableObject
return clientId;
}
public long getDomainHistoryRevisionId() {
return domainHistoryRevisionId;
}
public String getDomainRepoId() {
return domainRepoId;
}
public DateTime getEventTime() {
return eventTime;
}
@ -163,7 +203,7 @@ public abstract class BillingEvent extends ImmutableObject
return thisCastToDerived();
}
public B setId(Long id) {
public B setId(long id) {
getInstance().id = id;
return thisCastToDerived();
}
@ -173,6 +213,16 @@ public abstract class BillingEvent extends ImmutableObject
return thisCastToDerived();
}
public B setDomainHistoryRevisionId(long domainHistoryRevisionId) {
getInstance().domainHistoryRevisionId = domainHistoryRevisionId;
return thisCastToDerived();
}
public B setDomainRepoId(String domainRepoId) {
getInstance().domainRepoId = domainRepoId;
return thisCastToDerived();
}
public B setEventTime(DateTime eventTime) {
getInstance().eventTime = eventTime;
return thisCastToDerived();
@ -194,6 +244,7 @@ public abstract class BillingEvent extends ImmutableObject
}
public B setParent(Key<HistoryEntry> parentKey) {
// TODO(shicong): Figure out how to set domainHistoryRevisionId and domainRepoId
getInstance().parent = parentKey;
return thisCastToDerived();
}
@ -213,9 +264,23 @@ public abstract class BillingEvent extends ImmutableObject
/** A one-time billable event. */
@ReportedOn
@Entity
@javax.persistence.Entity(name = "BillingEvent")
@javax.persistence.Table(
indexes = {
@javax.persistence.Index(columnList = "clientId"),
@javax.persistence.Index(columnList = "eventTime"),
@javax.persistence.Index(columnList = "billingTime"),
@javax.persistence.Index(columnList = "syntheticCreationTime"),
@javax.persistence.Index(columnList = "allocation_token_id")
})
@AttributeOverride(name = "id", column = @Column(name = "billing_event_id"))
public static class OneTime extends BillingEvent {
/** The billable value. */
@AttributeOverrides({
@AttributeOverride(name = "money.amount", column = @Column(name = "cost_amount")),
@AttributeOverride(name = "money.currency", column = @Column(name = "cost_currency"))
})
Money cost;
/** When the cost should be billed. */
@ -223,8 +288,8 @@ public abstract class BillingEvent extends ImmutableObject
DateTime billingTime;
/**
* The period in years of the action being billed for, if applicable, otherwise null.
* Used for financial reporting.
* The period in years of the action being billed for, if applicable, otherwise null. Used for
* financial reporting.
*/
@IgnoreSave(IfNull.class)
Integer periodYears = null;
@ -240,15 +305,21 @@ public abstract class BillingEvent extends ImmutableObject
/**
* For {@link Flag#SYNTHETIC} events, a {@link Key} to the {@link BillingEvent} from which this
* OneTime was created. This is needed in order to properly match billing events against
* {@link Cancellation}s.
* OneTime was created. This is needed in order to properly match billing events against {@link
* Cancellation}s.
*/
Key<? extends BillingEvent> cancellationMatchingBillingEvent;
@Column(name = "cancellation_matching_billing_recurrence_id")
VKey<? extends BillingEvent> cancellationMatchingBillingEvent;
/**
* The {@link AllocationToken} used in the creation of this event, or null if one was not used.
*
* <p>TODO(shicong): Add foreign key constraint when AllocationToken schema is generated
*/
@Index @Nullable Key<AllocationToken> allocationToken;
@Column(name = "allocation_token_id")
@Index
@Nullable
VKey<AllocationToken> allocationToken;
public Money getCost() {
return cost;
@ -266,14 +337,18 @@ public abstract class BillingEvent extends ImmutableObject
return syntheticCreationTime;
}
public Key<? extends BillingEvent> getCancellationMatchingBillingEvent() {
public VKey<? extends BillingEvent> getCancellationMatchingBillingEvent() {
return cancellationMatchingBillingEvent;
}
public Optional<Key<AllocationToken>> getAllocationToken() {
public Optional<VKey<AllocationToken>> getAllocationToken() {
return Optional.ofNullable(allocationToken);
}
public VKey<OneTime> createVKey() {
return VKey.createOfy(getClass(), Key.create(this));
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
@ -311,12 +386,12 @@ public abstract class BillingEvent extends ImmutableObject
}
public Builder setCancellationMatchingBillingEvent(
Key<? extends BillingEvent> cancellationMatchingBillingEvent) {
VKey<? extends BillingEvent> cancellationMatchingBillingEvent) {
getInstance().cancellationMatchingBillingEvent = cancellationMatchingBillingEvent;
return this;
}
public Builder setAllocationToken(@Nullable Key<AllocationToken> allocationToken) {
public Builder setAllocationToken(@Nullable VKey<AllocationToken> allocationToken) {
getInstance().allocationToken = allocationToken;
return this;
}
@ -361,6 +436,15 @@ public abstract class BillingEvent extends ImmutableObject
*/
@ReportedOn
@Entity
@javax.persistence.Entity(name = "BillingRecurrence")
@javax.persistence.Table(
indexes = {
@javax.persistence.Index(columnList = "clientId"),
@javax.persistence.Index(columnList = "eventTime"),
@javax.persistence.Index(columnList = "recurrenceEndTime"),
@javax.persistence.Index(columnList = "recurrence_time_of_year")
})
@AttributeOverride(name = "id", column = @Column(name = "billing_recurrence_id"))
public static class Recurring extends BillingEvent {
/**
@ -384,6 +468,10 @@ public abstract class BillingEvent extends ImmutableObject
* model, whereas the billing time is a fixed {@link org.joda.time.Duration} later.
*/
@Index
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "timeString", column = @Column(name = "recurrence_time_of_year"))
})
TimeOfYear recurrenceTimeOfYear;
public DateTime getRecurrenceEndTime() {
@ -394,6 +482,10 @@ public abstract class BillingEvent extends ImmutableObject
return recurrenceTimeOfYear;
}
public VKey<Recurring> createVKey() {
return VKey.createOfy(getClass(), Key.create(this));
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
@ -434,6 +526,14 @@ public abstract class BillingEvent extends ImmutableObject
*/
@ReportedOn
@Entity
@javax.persistence.Entity(name = "BillingCancellation")
@javax.persistence.Table(
indexes = {
@javax.persistence.Index(columnList = "clientId"),
@javax.persistence.Index(columnList = "eventTime"),
@javax.persistence.Index(columnList = "billingTime")
})
@AttributeOverride(name = "id", column = @Column(name = "billing_cancellation_id"))
public static class Cancellation extends BillingEvent {
/** The billing time of the charge that is being cancelled. */
@ -446,7 +546,8 @@ public abstract class BillingEvent extends ImmutableObject
* <p>Although the type is {@link Key} the name "ref" is preserved for historical reasons.
*/
@IgnoreSave(IfNull.class)
Key<BillingEvent.OneTime> refOneTime = null;
@Column(name = "billing_event_id")
VKey<BillingEvent.OneTime> refOneTime = null;
/**
* The recurring billing event to cancel, or null for non-autorenew cancellations.
@ -454,13 +555,14 @@ public abstract class BillingEvent extends ImmutableObject
* <p>Although the type is {@link Key} the name "ref" is preserved for historical reasons.
*/
@IgnoreSave(IfNull.class)
Key<BillingEvent.Recurring> refRecurring = null;
@Column(name = "billing_recurrence_id")
VKey<BillingEvent.Recurring> refRecurring = null;
public DateTime getBillingTime() {
return billingTime;
}
public Key<? extends BillingEvent> getEventKey() {
public VKey<? extends BillingEvent> getEventKey() {
return firstNonNull(refOneTime, refRecurring);
}
@ -492,13 +594,19 @@ public abstract class BillingEvent extends ImmutableObject
.setParent(historyEntry);
// Set the grace period's billing event using the appropriate Cancellation builder method.
if (gracePeriod.getOneTimeBillingEvent() != null) {
builder.setOneTimeEventKey(gracePeriod.getOneTimeBillingEvent());
builder.setOneTimeEventKey(
VKey.createOfy(BillingEvent.OneTime.class, gracePeriod.getOneTimeBillingEvent()));
} else if (gracePeriod.getRecurringBillingEvent() != null) {
builder.setRecurringEventKey(gracePeriod.getRecurringBillingEvent());
builder.setRecurringEventKey(
VKey.createOfy(BillingEvent.Recurring.class, gracePeriod.getRecurringBillingEvent()));
}
return builder.build();
}
public VKey<Cancellation> createVKey() {
return VKey.createOfy(getClass(), Key.create(this));
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
@ -518,12 +626,12 @@ public abstract class BillingEvent extends ImmutableObject
return this;
}
public Builder setOneTimeEventKey(Key<BillingEvent.OneTime> eventKey) {
public Builder setOneTimeEventKey(VKey<BillingEvent.OneTime> eventKey) {
getInstance().refOneTime = eventKey;
return this;
}
public Builder setRecurringEventKey(Key<BillingEvent.Recurring> eventKey) {
public Builder setRecurringEventKey(VKey<BillingEvent.Recurring> eventKey) {
getInstance().refRecurring = eventKey;
return this;
}
@ -540,9 +648,7 @@ public abstract class BillingEvent extends ImmutableObject
}
}
/**
* An event representing a modification of an existing one-time billing event.
*/
/** An event representing a modification of an existing one-time billing event. */
@ReportedOn
@Entity
public static class Modification extends BillingEvent {

View file

@ -29,20 +29,22 @@ import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Index;
import google.registry.model.ImmutableObject;
import java.util.List;
import javax.persistence.Embeddable;
import org.joda.time.DateTime;
/**
* A time of year (month, day, millis of day) that can be stored in a sort-friendly format.
*
* <p>This is conceptually similar to {@code MonthDay} in Joda or more generally to Joda's
* {@code Partial}, but the parts we need are too simple to justify a full implementation of
* {@code Partial}.
* <p>This is conceptually similar to {@code MonthDay} in Joda or more generally to Joda's {@code
* Partial}, but the parts we need are too simple to justify a full implementation of {@code
* Partial}.
*
* <p>For simplicity, the native representation of this class's data is its stored format. This
* allows it to be embeddable with no translation needed and also delays parsing of the string on
* load until it's actually needed.
*/
@Embed
@Embeddable
public class TimeOfYear extends ImmutableObject {
/**

View file

@ -45,6 +45,8 @@ import google.registry.model.common.TimedTransitionProperty;
import google.registry.model.common.TimedTransitionProperty.TimeMapper;
import google.registry.model.common.TimedTransitionProperty.TimedTransition;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
@ -53,6 +55,7 @@ import org.joda.time.DateTime;
/** An entity representing an allocation token. */
@ReportedOn
@Entity
@WithStringVKey
public class AllocationToken extends BackupGroupRoot implements Buildable {
// Promotions should only move forward, and ENDED / CANCELLED are terminal states.
@ -179,6 +182,10 @@ public class AllocationToken extends BackupGroupRoot implements Buildable {
return tokenStatusTransitions;
}
public VKey<AllocationToken> createVKey() {
return VKey.createOfy(getClass(), Key.create(this));
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));

View file

@ -34,6 +34,7 @@ import com.googlecode.objectify.annotation.EntitySubclass;
import com.googlecode.objectify.impl.translate.TranslatorFactory;
import com.googlecode.objectify.impl.translate.opt.joda.MoneyStringTranslatorFactory;
import google.registry.config.RegistryEnvironment;
import google.registry.model.Buildable;
import google.registry.model.EntityClasses;
import google.registry.model.ImmutableObject;
import google.registry.model.translators.BloomFilterOfStringTranslatorFactory;
@ -167,10 +168,16 @@ public class ObjectifyService {
}
com.googlecode.objectify.ObjectifyService.register(clazz);
// Autogenerated ids make the commit log code very difficult since we won't always be able
// to create a key for an entity immediately when requesting a save. Disallow that here.
// to create a key for an entity immediately when requesting a save. So, we require such
// entities to implement google.registry.model.Buildable as its build() function allocates the
// id to the entity.
if (factory().getMetadata(clazz).getKeyMetadata().isIdGeneratable()) {
checkState(
!factory().getMetadata(clazz).getKeyMetadata().isIdGeneratable(),
"Can't register %s: Autogenerated ids (@Id on a Long) are not supported.", kind);
Buildable.class.isAssignableFrom(clazz),
"Can't register %s: Entity with autogenerated ids (@Id on a Long) must implement"
+ " google.registry.model.Buildable.",
kind);
}
}
}

View file

@ -0,0 +1,35 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.persistence.converter;
import google.registry.model.billing.BillingEvent.Flag;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** JPA {@link AttributeConverter} for storing/retrieving {@link Set}. */
@Converter(autoApply = true)
public class BillingEventFlagSetConverter extends StringSetConverterBase<Flag> {
@Override
String toString(Flag element) {
return element.name();
}
@Override
Flag fromString(String value) {
return Flag.valueOf(value);
}
}

View file

@ -19,6 +19,9 @@
* Move tests to another (sub)project. This is not a big problem, but feels unnatural.
* Use Hibernate's ServiceRegistry for bootstrapping (not JPA-compliant)
-->
<class>google.registry.model.billing.BillingEvent$Cancellation</class>
<class>google.registry.model.billing.BillingEvent$OneTime</class>
<class>google.registry.model.billing.BillingEvent$Recurring</class>
<class>google.registry.model.contact.ContactResource</class>
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.model.host.HostResource</class>
@ -36,6 +39,7 @@
<!-- Customized type converters -->
<class>google.registry.persistence.converter.BillingCostTransitionConverter</class>
<class>google.registry.persistence.converter.BillingEventFlagSetConverter</class>
<class>google.registry.persistence.converter.BloomFilterConverter</class>
<class>google.registry.persistence.converter.CidrAddressBlockListConverter</class>
<class>google.registry.persistence.converter.CreateAutoTimestampConverter</class>
@ -53,6 +57,8 @@
<class>google.registry.persistence.converter.ZonedDateTimeConverter</class>
<!-- Generated converters for VKey -->
<class>google.registry.model.billing.VKeyConverter_BillingEvent</class>
<class>google.registry.model.domain.token.VKeyConverter_AllocationToken</class>
<class>google.registry.model.host.VKeyConverter_HostResource</class>
<class>google.registry.model.contact.VKeyConverter_ContactResource</class>

View file

@ -155,7 +155,7 @@ public class ExpandRecurringBillingEventsActionTest
.setPeriodYears(1)
.setReason(Reason.RENEW)
.setSyntheticCreationTime(beginningOfTest)
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.setTargetId(domain.getFullyQualifiedDomainName());
}
@ -274,9 +274,11 @@ public class ExpandRecurringBillingEventsActionTest
.setParent(persistedEntries.get(0))
.build();
// Persist an otherwise identical billing event that differs only in recurring event key.
BillingEvent.OneTime persisted = expected.asBuilder()
BillingEvent.OneTime persisted =
expected
.asBuilder()
.setParent(persistedEntries.get(1))
.setCancellationMatchingBillingEvent(Key.create(recurring2))
.setCancellationMatchingBillingEvent(recurring2.createVKey())
.build();
assertCursorAt(beginningOfTest);
assertBillingEventsForResource(domain, persisted, expected, recurring, recurring2);
@ -604,18 +606,20 @@ public class ExpandRecurringBillingEventsActionTest
assertHistoryEntryMatches(
domain, persistedEntries.get(0), "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"),
true);
BillingEvent.OneTime expected = defaultOneTimeBuilder()
BillingEvent.OneTime expected =
defaultOneTimeBuilder()
.setParent(persistedEntries.get(0))
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.build();
assertHistoryEntryMatches(
domain, persistedEntries.get(1), "TheRegistrar", DateTime.parse("2000-05-20T00:00:00Z"),
true);
BillingEvent.OneTime expected2 = defaultOneTimeBuilder()
BillingEvent.OneTime expected2 =
defaultOneTimeBuilder()
.setBillingTime(DateTime.parse("2000-05-20T00:00:00Z"))
.setEventTime(DateTime.parse("2000-04-05T00:00:00Z"))
.setParent(persistedEntries.get(1))
.setCancellationMatchingBillingEvent(Key.create(recurring2))
.setCancellationMatchingBillingEvent(recurring2.createVKey())
.build();
assertBillingEventsForResource(domain, expected, expected2, recurring, recurring2);
assertCursorAt(beginningOfTest);

View file

@ -41,6 +41,7 @@ import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.persistence.VKey;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.FakeResponse;
@ -339,7 +340,8 @@ public class EppTestCase extends ShardableTestCase {
.setTargetId(domain.getFullyQualifiedDomainName())
.setClientId(domain.getCurrentSponsorClientId())
.setEventTime(deleteTime)
.setOneTimeEventKey(findKeyToActualOneTimeBillingEvent(billingEventToCancel))
.setOneTimeEventKey(
VKey.createOfy(OneTime.class, findKeyToActualOneTimeBillingEvent(billingEventToCancel)))
.setBillingTime(createTime.plus(Registry.get(domain.getTld()).getAddGracePeriodLength()))
.setReason(Reason.CREATE)
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_DELETE))
@ -353,7 +355,8 @@ public class EppTestCase extends ShardableTestCase {
.setTargetId(domain.getFullyQualifiedDomainName())
.setClientId(domain.getCurrentSponsorClientId())
.setEventTime(deleteTime)
.setOneTimeEventKey(findKeyToActualOneTimeBillingEvent(billingEventToCancel))
.setOneTimeEventKey(
VKey.createOfy(OneTime.class, findKeyToActualOneTimeBillingEvent(billingEventToCancel)))
.setBillingTime(renewTime.plus(Registry.get(domain.getTld()).getRenewGracePeriodLength()))
.setReason(Reason.RENEW)
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_DELETE))

View file

@ -276,7 +276,7 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
.setBillingTime(billingTime)
.setFlags(expectedBillingFlags)
.setParent(historyEntry)
.setAllocationToken(allocationToken == null ? null : Key.create(allocationToken))
.setAllocationToken(allocationToken == null ? null : allocationToken.createVKey())
.build();
BillingEvent.Recurring renewBillingEvent =

View file

@ -214,7 +214,7 @@ public class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow,
.setClientId("TheRegistrar")
.setEventTime(eventTime)
.setBillingTime(TIME_BEFORE_FLOW.plusDays(1))
.setOneTimeEventKey(Key.create(graceBillingEvent))
.setOneTimeEventKey(graceBillingEvent.createVKey())
.setParent(historyEntryDomainDelete)
.build());
}

View file

@ -71,6 +71,7 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import java.util.Arrays;
import java.util.stream.Stream;
import org.joda.money.Money;
@ -402,7 +403,8 @@ public class DomainTransferApproveFlowTest
.setEventTime(clock.nowUtc()) // The cancellation happens at the moment of transfer.
.setBillingTime(
oldExpirationTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()))
.setRecurringEventKey(domain.getAutorenewBillingEvent()));
.setRecurringEventKey(
VKey.createOfy(BillingEvent.Recurring.class, domain.getAutorenewBillingEvent())));
}
@Test

View file

@ -100,6 +100,7 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import java.util.Map;
import java.util.Optional;
@ -1136,7 +1137,8 @@ public class DomainTransferRequestFlowTest
.setEventTime(clock.nowUtc().plus(Registry.get("tld").getAutomaticTransferLength()))
.setBillingTime(autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()))
// The cancellation should refer to the old autorenew billing event.
.setRecurringEventKey(existingAutorenewEvent));
.setRecurringEventKey(
VKey.createOfy(BillingEvent.Recurring.class, existingAutorenewEvent)));
}
@Test
@ -1164,7 +1166,8 @@ public class DomainTransferRequestFlowTest
.setBillingTime(
expirationTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()))
// The cancellation should refer to the old autorenew billing event.
.setRecurringEventKey(existingAutorenewEvent));
.setRecurringEventKey(
VKey.createOfy(BillingEvent.Recurring.class, existingAutorenewEvent)));
}
@Test

View file

@ -17,9 +17,11 @@ package google.registry.model.billing;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
import static org.joda.time.DateTimeZone.UTC;
@ -37,19 +39,25 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.util.DateTimeUtils;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link BillingEvent}. */
public class BillingEventTest extends EntityTestCase {
private final DateTime now = DateTime.now(UTC);
public BillingEventTest() {
super(true);
}
HistoryEntry historyEntry;
HistoryEntry historyEntry2;
DomainBase domain;
BillingEvent.OneTime sqlOneTime;
BillingEvent.OneTime oneTime;
BillingEvent.OneTime oneTimeSynthetic;
BillingEvent.Recurring recurring;
@ -57,7 +65,7 @@ public class BillingEventTest extends EntityTestCase {
BillingEvent.Cancellation cancellationRecurring;
BillingEvent.Modification modification;
@Before
@BeforeEach
public void setUp() {
createTld("tld");
domain = persistActiveDomain("foo.tld");
@ -97,7 +105,18 @@ public class BillingEventTest extends EntityTestCase {
.setCost(Money.of(USD, 1))
.setEventTime(now)
.setBillingTime(now.plusDays(5))
.setAllocationToken(Key.create(allocationToken))));
.setAllocationToken(allocationToken.createVKey())));
sqlOneTime =
oneTime
.asBuilder()
.setDomainRepoId(domain.getRepoId())
.setDomainHistoryRevisionId(1L)
.setAllocationToken(
VKey.create(
AllocationToken.class, allocationToken.getToken(), Key.create(allocationToken)))
.build();
recurring =
persistResource(
commonInit(
@ -107,31 +126,41 @@ public class BillingEventTest extends EntityTestCase {
.setReason(Reason.RENEW)
.setEventTime(now.plusYears(1))
.setRecurrenceEndTime(END_OF_TIME)));
oneTimeSynthetic = persistResource(commonInit(
oneTimeSynthetic =
persistResource(
commonInit(
new BillingEvent.OneTime.Builder()
.setParent(historyEntry)
.setReason(Reason.CREATE)
.setFlags(ImmutableSet.of(BillingEvent.Flag.ANCHOR_TENANT, BillingEvent.Flag.SYNTHETIC))
.setFlags(
ImmutableSet.of(
BillingEvent.Flag.ANCHOR_TENANT, BillingEvent.Flag.SYNTHETIC))
.setSyntheticCreationTime(now.plusDays(10))
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.setPeriodYears(2)
.setCost(Money.of(USD, 1))
.setEventTime(now)
.setBillingTime(now.plusDays(5))));
cancellationOneTime = persistResource(commonInit(
cancellationOneTime =
persistResource(
commonInit(
new BillingEvent.Cancellation.Builder()
.setParent(historyEntry2)
.setReason(Reason.CREATE)
.setEventTime(now.plusDays(1))
.setBillingTime(now.plusDays(5))
.setOneTimeEventKey(Key.create(oneTime))));
cancellationRecurring = persistResource(commonInit(
.setOneTimeEventKey(oneTime.createVKey())));
cancellationRecurring =
persistResource(
commonInit(
new BillingEvent.Cancellation.Builder()
.setParent(historyEntry2)
.setReason(Reason.RENEW)
.setEventTime(now.plusDays(1))
.setBillingTime(now.plusYears(1).plusDays(45))
.setRecurringEventKey(Key.create(recurring))));
.setRecurringEventKey(recurring.createVKey())));
modification = persistResource(commonInit(
new BillingEvent.Modification.Builder()
.setParent(historyEntry2)
@ -149,6 +178,83 @@ public class BillingEventTest extends EntityTestCase {
.build();
}
private void saveNewBillingEvent(BillingEvent billingEvent) {
billingEvent.id = null;
jpaTm().transact(() -> jpaTm().saveNew(billingEvent));
}
@Test
public void testCloudSqlPersistence_OneTime() {
saveRegistrar("a registrar");
saveNewBillingEvent(sqlOneTime);
BillingEvent.OneTime persisted =
jpaTm()
.transact(
() -> jpaTm().load(VKey.createSql(BillingEvent.OneTime.class, sqlOneTime.id)));
// TODO(shicong): Remove these fixes after the entities are fully compatible
BillingEvent.OneTime fixed =
persisted
.asBuilder()
.setParent(sqlOneTime.getParentKey())
.setAllocationToken(sqlOneTime.getAllocationToken().get())
.build();
assertThat(fixed).isEqualTo(sqlOneTime);
}
@Test
public void testCloudSqlPersistence_Cancellation() {
saveRegistrar("a registrar");
saveNewBillingEvent(sqlOneTime);
VKey<BillingEvent.OneTime> sqlVKey = VKey.createSql(BillingEvent.OneTime.class, sqlOneTime.id);
BillingEvent sqlCancellationOneTime =
cancellationOneTime
.asBuilder()
.setOneTimeEventKey(sqlVKey)
.setDomainRepoId(domain.getRepoId())
.setDomainHistoryRevisionId(1L)
.build();
saveNewBillingEvent(sqlCancellationOneTime);
BillingEvent.Cancellation persisted =
jpaTm()
.transact(
() ->
jpaTm()
.load(
VKey.createSql(
BillingEvent.Cancellation.class, sqlCancellationOneTime.id)));
// TODO(shicong): Remove these fixes after the entities are fully compatible
BillingEvent.Cancellation fixed =
persisted
.asBuilder()
.setParent(sqlCancellationOneTime.getParentKey())
.setOneTimeEventKey(sqlVKey)
.build();
assertThat(fixed).isEqualTo(sqlCancellationOneTime);
}
@Test
public void testCloudSqlPersistence_Recurring() {
saveRegistrar("a registrar");
BillingEvent.Recurring sqlRecurring =
recurring
.asBuilder()
.setDomainRepoId(domain.getRepoId())
.setDomainHistoryRevisionId(1L)
.build();
saveNewBillingEvent(sqlRecurring);
BillingEvent.Recurring persisted =
jpaTm()
.transact(
() -> jpaTm().load(VKey.createSql(BillingEvent.Recurring.class, sqlRecurring.id)));
// TODO(shicong): Remove these fixes after the entities are fully compatible
BillingEvent.Recurring fixed =
persisted.asBuilder().setParent(sqlRecurring.getParentKey()).build();
assertThat(fixed).isEqualTo(sqlRecurring);
}
@Test
public void testPersistence() {
assertThat(ofy().load().entity(oneTime).now()).isEqualTo(oneTime);
@ -183,8 +289,13 @@ public class BillingEventTest extends EntityTestCase {
@Test
public void testCancellationMatching() {
Key<?> recurringKey = ofy().load().entity(oneTimeSynthetic).now()
.getCancellationMatchingBillingEvent();
Key<?> recurringKey =
ofy()
.load()
.entity(oneTimeSynthetic)
.now()
.getCancellationMatchingBillingEvent()
.getOfyKey();
assertThat(ofy().load().key(recurringKey).now()).isEqualTo(recurring);
}
@ -219,7 +330,7 @@ public class BillingEventTest extends EntityTestCase {
oneTime
.asBuilder()
.setFlags(ImmutableSet.of(BillingEvent.Flag.SYNTHETIC))
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.build());
assertThat(thrown)
.hasMessageThat()
@ -263,7 +374,7 @@ public class BillingEventTest extends EntityTestCase {
() ->
oneTime
.asBuilder()
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.build());
assertThat(thrown)
.hasMessageThat()
@ -334,8 +445,8 @@ public class BillingEventTest extends EntityTestCase {
() ->
cancellationOneTime
.asBuilder()
.setOneTimeEventKey(Key.create(oneTime))
.setRecurringEventKey(Key.create(recurring))
.setOneTimeEventKey(oneTime.createVKey())
.setRecurringEventKey(recurring.createVKey())
.build());
assertThat(thrown).hasMessageThat().contains("exactly one billing event");
}

View file

@ -45,7 +45,7 @@ public class JpaEntityCoverage extends ExternalResource {
private static final ImmutableSet<Class> ALL_JPA_ENTITIES =
PersistenceXmlUtility.getManagedClasses().stream()
.filter(e -> !IGNORE_ENTITIES.contains(e.getSimpleName()))
.filter(e -> e.getAnnotation(Entity.class) != null)
.filter(e -> e.isAnnotationPresent(Entity.class))
.collect(ImmutableSet.toImmutableSet());
private static final Set<Class> allCoveredJpaEntities = Sets.newHashSet();
// Map of test class name to boolean flag indicating if it tests any JPA entities.

View file

@ -16,6 +16,7 @@ package google.registry.schema.integration;
import static com.google.common.truth.Truth.assert_;
import google.registry.model.billing.BillingEventTest;
import google.registry.model.contact.ContactResourceTest;
import google.registry.model.domain.DomainBaseSqlTest;
import google.registry.model.registry.RegistryLockDaoTest;
@ -68,6 +69,7 @@ import org.junit.runner.RunWith;
@SelectClasses({
// BeforeSuiteTest must be the first entry. See class javadoc for details.
BeforeSuiteTest.class,
BillingEventTest.class,
ClaimsListDaoTest.class,
ContactResourceTest.class,
CursorDaoTest.class,

View file

@ -5,11 +5,11 @@ class google.registry.model.UpdateAutoTimestamp {
org.joda.time.DateTime timestamp;
}
class google.registry.model.billing.BillingEvent$Cancellation {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
com.googlecode.objectify.Key<google.registry.model.billing.BillingEvent$OneTime> refOneTime;
com.googlecode.objectify.Key<google.registry.model.billing.BillingEvent$Recurring> refRecurring;
google.registry.model.billing.BillingEvent$Reason reason;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$OneTime> refOneTime;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> refRecurring;
java.lang.String clientId;
java.lang.String targetId;
java.util.Set<google.registry.model.billing.BillingEvent$Flag> flags;
@ -26,7 +26,7 @@ enum google.registry.model.billing.BillingEvent$Flag {
SYNTHETIC;
}
class google.registry.model.billing.BillingEvent$Modification {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
com.googlecode.objectify.Key<google.registry.model.billing.BillingEvent$OneTime> eventRef;
google.registry.model.billing.BillingEvent$Reason reason;
@ -38,11 +38,11 @@ class google.registry.model.billing.BillingEvent$Modification {
org.joda.time.DateTime eventTime;
}
class google.registry.model.billing.BillingEvent$OneTime {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
com.googlecode.objectify.Key<? extends google.registry.model.billing.BillingEvent> cancellationMatchingBillingEvent;
com.googlecode.objectify.Key<google.registry.model.domain.token.AllocationToken> allocationToken;
google.registry.model.billing.BillingEvent$Reason reason;
google.registry.persistence.VKey<? extends google.registry.model.billing.BillingEvent> cancellationMatchingBillingEvent;
google.registry.persistence.VKey<google.registry.model.domain.token.AllocationToken> allocationToken;
java.lang.Integer periodYears;
java.lang.String clientId;
java.lang.String targetId;
@ -62,7 +62,7 @@ enum google.registry.model.billing.BillingEvent$Reason {
TRANSFER;
}
class google.registry.model.billing.BillingEvent$Recurring {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
google.registry.model.billing.BillingEvent$Reason reason;
google.registry.model.common.TimeOfYear recurrenceTimeOfYear;

View file

@ -0,0 +1,104 @@
-- Copyright 2020 The Nomulus Authors. All Rights Reserved.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
create table "BillingCancellation" (
billing_cancellation_id bigserial not null,
client_id text not null,
domain_history_revision_id int8 not null,
domain_repo_id text not null,
event_time timestamptz not null,
flags text[],
reason text not null,
domain_name text not null,
billing_time timestamptz,
billing_event_id int8,
billing_recurrence_id int8,
primary key (billing_cancellation_id)
);
create table "BillingEvent" (
billing_event_id bigserial not null,
client_id text not null,
domain_history_revision_id int8 not null,
domain_repo_id text not null,
event_time timestamptz not null,
flags text[],
reason text not null,
domain_name text not null,
allocation_token_id text,
billing_time timestamptz,
cancellation_matching_billing_recurrence_id int8,
cost_amount numeric(19, 2),
cost_currency text,
period_years int4,
synthetic_creation_time timestamptz,
primary key (billing_event_id)
);
create table "BillingRecurrence" (
billing_recurrence_id bigserial not null,
client_id text not null,
domain_history_revision_id int8 not null,
domain_repo_id text not null,
event_time timestamptz not null,
flags text[],
reason text not null,
domain_name text not null,
recurrence_end_time timestamptz,
recurrence_time_of_year text,
primary key (billing_recurrence_id)
);
create index IDXeokttmxtpq2hohcioe5t2242b on "BillingCancellation" (client_id);
create index IDX2exdfbx6oiiwnhr8j6gjpqt2j on "BillingCancellation" (event_time);
create index IDXqa3g92jc17e8dtiaviy4fet4x on "BillingCancellation" (billing_time);
create index IDX73l103vc5900ig3p4odf0cngt on "BillingEvent" (client_id);
create index IDX5yfbr88439pxw0v3j86c74fp8 on "BillingEvent" (event_time);
create index IDX6py6ocrab0ivr76srcd2okpnq on "BillingEvent" (billing_time);
create index IDXplxf9v56p0wg8ws6qsvd082hk on "BillingEvent" (synthetic_creation_time);
create index IDXhmv411mdqo5ibn4vy7ykxpmlv on "BillingEvent" (allocation_token_id);
create index IDXn898pb9mwcg359cdwvolb11ck on "BillingRecurrence" (client_id);
create index IDX6syykou4nkc7hqa5p8r92cpch on "BillingRecurrence" (event_time);
create index IDXp3usbtvk0v1m14i5tdp4xnxgc on "BillingRecurrence" (recurrence_end_time);
create index IDXjny8wuot75b5e6p38r47wdawu on "BillingRecurrence" (recurrence_time_of_year);
alter table if exists "BillingEvent"
add constraint fk_billing_event_client_id
foreign key (client_id)
references "Registrar";
alter table if exists "BillingEvent"
add constraint fk_billing_event_cancellation_matching_billing_recurrence_id
foreign key (cancellation_matching_billing_recurrence_id)
references "BillingRecurrence";
alter table if exists "BillingCancellation"
add constraint fk_billing_cancellation_client_id
foreign key (client_id)
references "Registrar";
alter table if exists "BillingCancellation"
add constraint fk_billing_cancellation_billing_event_id
foreign key (billing_event_id)
references "BillingEvent";
alter table if exists "BillingCancellation"
add constraint fk_billing_cancellation_billing_recurrence_id
foreign key (billing_recurrence_id)
references "BillingRecurrence";
alter table if exists "BillingRecurrence"
add constraint fk_billing_recurrence_client_id
foreign key (client_id)
references "Registrar";

View file

@ -12,6 +12,54 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
create table "BillingCancellation" (
billing_cancellation_id bigserial not null,
client_id text not null,
domain_history_revision_id int8 not null,
domain_repo_id text not null,
event_time timestamptz not null,
flags text[],
reason text not null,
domain_name text not null,
billing_time timestamptz,
billing_event_id int8,
billing_recurrence_id int8,
primary key (billing_cancellation_id)
);
create table "BillingEvent" (
billing_event_id bigserial not null,
client_id text not null,
domain_history_revision_id int8 not null,
domain_repo_id text not null,
event_time timestamptz not null,
flags text[],
reason text not null,
domain_name text not null,
allocation_token_id text,
billing_time timestamptz,
cancellation_matching_billing_recurrence_id int8,
cost_amount numeric(19, 2),
cost_currency text,
period_years int4,
synthetic_creation_time timestamptz,
primary key (billing_event_id)
);
create table "BillingRecurrence" (
billing_recurrence_id bigserial not null,
client_id text not null,
domain_history_revision_id int8 not null,
domain_repo_id text not null,
event_time timestamptz not null,
flags text[],
reason text not null,
domain_name text not null,
recurrence_end_time timestamptz,
recurrence_time_of_year text,
primary key (billing_recurrence_id)
);
create table "ClaimsEntry" (
revision_id int8 not null,
claim_key text not null,
@ -280,6 +328,18 @@
should_publish boolean not null,
primary key (revision_id)
);
create index IDXeokttmxtpq2hohcioe5t2242b on "BillingCancellation" (client_id);
create index IDX2exdfbx6oiiwnhr8j6gjpqt2j on "BillingCancellation" (event_time);
create index IDXqa3g92jc17e8dtiaviy4fet4x on "BillingCancellation" (billing_time);
create index IDX73l103vc5900ig3p4odf0cngt on "BillingEvent" (client_id);
create index IDX5yfbr88439pxw0v3j86c74fp8 on "BillingEvent" (event_time);
create index IDX6py6ocrab0ivr76srcd2okpnq on "BillingEvent" (billing_time);
create index IDXplxf9v56p0wg8ws6qsvd082hk on "BillingEvent" (synthetic_creation_time);
create index IDXhmv411mdqo5ibn4vy7ykxpmlv on "BillingEvent" (allocation_token_id);
create index IDXn898pb9mwcg359cdwvolb11ck on "BillingRecurrence" (client_id);
create index IDX6syykou4nkc7hqa5p8r92cpch on "BillingRecurrence" (event_time);
create index IDXp3usbtvk0v1m14i5tdp4xnxgc on "BillingRecurrence" (recurrence_end_time);
create index IDXjny8wuot75b5e6p38r47wdawu on "BillingRecurrence" (recurrence_time_of_year);
create index IDX3y752kr9uh4kh6uig54vemx0l on "Contact" (creation_time);
create index IDXbn8t4wp85fgxjl8q4ctlscx55 on "Contact" (current_sponsor_client_id);
create index IDXn1f711wicdnooa2mqb7g1m55o on "Contact" (deletion_time);

View file

@ -34,6 +34,123 @@ SET default_tablespace = '';
SET default_with_oids = false;
--
-- Name: BillingCancellation; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."BillingCancellation" (
billing_cancellation_id bigint NOT NULL,
client_id text NOT NULL,
domain_history_revision_id bigint NOT NULL,
domain_repo_id text NOT NULL,
event_time timestamp with time zone NOT NULL,
flags text[],
reason text NOT NULL,
domain_name text NOT NULL,
billing_time timestamp with time zone,
billing_event_id bigint,
billing_recurrence_id bigint
);
--
-- Name: BillingCancellation_billing_cancellation_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public."BillingCancellation_billing_cancellation_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: BillingCancellation_billing_cancellation_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public."BillingCancellation_billing_cancellation_id_seq" OWNED BY public."BillingCancellation".billing_cancellation_id;
--
-- Name: BillingEvent; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."BillingEvent" (
billing_event_id bigint NOT NULL,
client_id text NOT NULL,
domain_history_revision_id bigint NOT NULL,
domain_repo_id text NOT NULL,
event_time timestamp with time zone NOT NULL,
flags text[],
reason text NOT NULL,
domain_name text NOT NULL,
allocation_token_id text,
billing_time timestamp with time zone,
cancellation_matching_billing_recurrence_id bigint,
cost_amount numeric(19,2),
cost_currency text,
period_years integer,
synthetic_creation_time timestamp with time zone
);
--
-- Name: BillingEvent_billing_event_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public."BillingEvent_billing_event_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: BillingEvent_billing_event_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public."BillingEvent_billing_event_id_seq" OWNED BY public."BillingEvent".billing_event_id;
--
-- Name: BillingRecurrence; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."BillingRecurrence" (
billing_recurrence_id bigint NOT NULL,
client_id text NOT NULL,
domain_history_revision_id bigint NOT NULL,
domain_repo_id text NOT NULL,
event_time timestamp with time zone NOT NULL,
flags text[],
reason text NOT NULL,
domain_name text NOT NULL,
recurrence_end_time timestamp with time zone,
recurrence_time_of_year text
);
--
-- Name: BillingRecurrence_billing_recurrence_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public."BillingRecurrence_billing_recurrence_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: BillingRecurrence_billing_recurrence_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public."BillingRecurrence_billing_recurrence_id_seq" OWNED BY public."BillingRecurrence".billing_recurrence_id;
--
-- Name: ClaimsEntry; Type: TABLE; Schema: public; Owner: -
--
@ -427,6 +544,27 @@ CREATE SEQUENCE public."ReservedList_revision_id_seq"
ALTER SEQUENCE public."ReservedList_revision_id_seq" OWNED BY public."ReservedList".revision_id;
--
-- Name: BillingCancellation billing_cancellation_id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingCancellation" ALTER COLUMN billing_cancellation_id SET DEFAULT nextval('public."BillingCancellation_billing_cancellation_id_seq"'::regclass);
--
-- Name: BillingEvent billing_event_id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingEvent" ALTER COLUMN billing_event_id SET DEFAULT nextval('public."BillingEvent_billing_event_id_seq"'::regclass);
--
-- Name: BillingRecurrence billing_recurrence_id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingRecurrence" ALTER COLUMN billing_recurrence_id SET DEFAULT nextval('public."BillingRecurrence_billing_recurrence_id_seq"'::regclass);
--
-- Name: ClaimsList revision_id; Type: DEFAULT; Schema: public; Owner: -
--
@ -455,6 +593,30 @@ ALTER TABLE ONLY public."RegistryLock" ALTER COLUMN revision_id SET DEFAULT next
ALTER TABLE ONLY public."ReservedList" ALTER COLUMN revision_id SET DEFAULT nextval('public."ReservedList_revision_id_seq"'::regclass);
--
-- Name: BillingCancellation BillingCancellation_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingCancellation"
ADD CONSTRAINT "BillingCancellation_pkey" PRIMARY KEY (billing_cancellation_id);
--
-- Name: BillingEvent BillingEvent_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingEvent"
ADD CONSTRAINT "BillingEvent_pkey" PRIMARY KEY (billing_event_id);
--
-- Name: BillingRecurrence BillingRecurrence_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingRecurrence"
ADD CONSTRAINT "BillingRecurrence_pkey" PRIMARY KEY (billing_recurrence_id);
--
-- Name: ClaimsEntry ClaimsEntry_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -597,6 +759,13 @@ CREATE INDEX idx1p3esngcwwu6hstyua6itn6ff ON public."Contact" USING btree (searc
CREATE INDEX idx1rcgkdd777bpvj0r94sltwd5y ON public."Domain" USING btree (fully_qualified_domain_name);
--
-- Name: idx2exdfbx6oiiwnhr8j6gjpqt2j; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx2exdfbx6oiiwnhr8j6gjpqt2j ON public."BillingCancellation" USING btree (event_time);
--
-- Name: idx3y752kr9uh4kh6uig54vemx0l; Type: INDEX; Schema: public; Owner: -
--
@ -611,6 +780,34 @@ CREATE INDEX idx3y752kr9uh4kh6uig54vemx0l ON public."Contact" USING btree (creat
CREATE INDEX idx5mnf0wn20tno4b9do88j61klr ON public."Domain" USING btree (deletion_time);
--
-- Name: idx5yfbr88439pxw0v3j86c74fp8; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx5yfbr88439pxw0v3j86c74fp8 ON public."BillingEvent" USING btree (event_time);
--
-- Name: idx6py6ocrab0ivr76srcd2okpnq; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx6py6ocrab0ivr76srcd2okpnq ON public."BillingEvent" USING btree (billing_time);
--
-- Name: idx6syykou4nkc7hqa5p8r92cpch; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx6syykou4nkc7hqa5p8r92cpch ON public."BillingRecurrence" USING btree (event_time);
--
-- Name: idx73l103vc5900ig3p4odf0cngt; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx73l103vc5900ig3p4odf0cngt ON public."BillingEvent" USING btree (client_id);
--
-- Name: idx8nr0ke9mrrx4ewj6pd2ag4rmr; Type: INDEX; Schema: public; Owner: -
--
@ -639,6 +836,27 @@ CREATE INDEX idx_registry_lock_verification_code ON public."RegistryLock" USING
CREATE INDEX idxbn8t4wp85fgxjl8q4ctlscx55 ON public."Contact" USING btree (current_sponsor_client_id);
--
-- Name: idxeokttmxtpq2hohcioe5t2242b; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxeokttmxtpq2hohcioe5t2242b ON public."BillingCancellation" USING btree (client_id);
--
-- Name: idxhmv411mdqo5ibn4vy7ykxpmlv; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxhmv411mdqo5ibn4vy7ykxpmlv ON public."BillingEvent" USING btree (allocation_token_id);
--
-- Name: idxjny8wuot75b5e6p38r47wdawu; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxjny8wuot75b5e6p38r47wdawu ON public."BillingRecurrence" USING btree (recurrence_time_of_year);
--
-- Name: idxkjt9yaq92876dstimd93hwckh; Type: INDEX; Schema: public; Owner: -
--
@ -653,6 +871,34 @@ CREATE INDEX idxkjt9yaq92876dstimd93hwckh ON public."Domain" USING btree (curren
CREATE INDEX idxn1f711wicdnooa2mqb7g1m55o ON public."Contact" USING btree (deletion_time);
--
-- Name: idxn898pb9mwcg359cdwvolb11ck; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxn898pb9mwcg359cdwvolb11ck ON public."BillingRecurrence" USING btree (client_id);
--
-- Name: idxp3usbtvk0v1m14i5tdp4xnxgc; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxp3usbtvk0v1m14i5tdp4xnxgc ON public."BillingRecurrence" USING btree (recurrence_end_time);
--
-- Name: idxplxf9v56p0wg8ws6qsvd082hk; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxplxf9v56p0wg8ws6qsvd082hk ON public."BillingEvent" USING btree (synthetic_creation_time);
--
-- Name: idxqa3g92jc17e8dtiaviy4fet4x; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxqa3g92jc17e8dtiaviy4fet4x ON public."BillingCancellation" USING btree (billing_time);
--
-- Name: idxrwl38wwkli1j7gkvtywi9jokq; Type: INDEX; Schema: public; Owner: -
--
@ -751,6 +997,54 @@ ALTER TABLE ONLY public."Contact"
ADD CONSTRAINT fk93c185fx7chn68uv7nl6uv2s0 FOREIGN KEY (current_sponsor_client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: BillingCancellation fk_billing_cancellation_billing_event_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingCancellation"
ADD CONSTRAINT fk_billing_cancellation_billing_event_id FOREIGN KEY (billing_event_id) REFERENCES public."BillingEvent"(billing_event_id);
--
-- Name: BillingCancellation fk_billing_cancellation_billing_recurrence_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingCancellation"
ADD CONSTRAINT fk_billing_cancellation_billing_recurrence_id FOREIGN KEY (billing_recurrence_id) REFERENCES public."BillingRecurrence"(billing_recurrence_id);
--
-- Name: BillingCancellation fk_billing_cancellation_client_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingCancellation"
ADD CONSTRAINT fk_billing_cancellation_client_id FOREIGN KEY (client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: BillingEvent fk_billing_event_cancellation_matching_billing_recurrence_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingEvent"
ADD CONSTRAINT fk_billing_event_cancellation_matching_billing_recurrence_id FOREIGN KEY (cancellation_matching_billing_recurrence_id) REFERENCES public."BillingRecurrence"(billing_recurrence_id);
--
-- Name: BillingEvent fk_billing_event_client_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingEvent"
ADD CONSTRAINT fk_billing_event_client_id FOREIGN KEY (client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: BillingRecurrence fk_billing_recurrence_client_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BillingRecurrence"
ADD CONSTRAINT fk_billing_recurrence_client_id FOREIGN KEY (client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: Domain fk_domain_admin_contact; Type: FK CONSTRAINT; Schema: public; Owner: -
--