diff --git a/java/google/registry/flows/domain/DomainAllocateFlow.java b/java/google/registry/flows/domain/DomainAllocateFlow.java index 959d464c5..19a744a5b 100644 --- a/java/google/registry/flows/domain/DomainAllocateFlow.java +++ b/java/google/registry/flows/domain/DomainAllocateFlow.java @@ -160,7 +160,7 @@ public class DomainAllocateFlow implements TransactionalFlow { String repoId = createDomainRepoId(ObjectifyService.allocateId(), registry.getTldStr()); ImmutableSet.Builder entitiesToSave = new ImmutableSet.Builder<>(); HistoryEntry historyEntry = buildHistoryEntry( - repoId, period, now, registry.getAddGracePeriodLength(), registry.getTldStr()); + repoId, registry.getTldStr(), now, period, registry.getAddGracePeriodLength()); entitiesToSave.add(historyEntry); ImmutableSet billsAndPolls = createBillingEventsAndPollMessages( domainName, application, historyEntry, isSunrushAddGracePeriod, registry, now, years); @@ -234,7 +234,7 @@ public class DomainAllocateFlow implements TransactionalFlow { } private HistoryEntry buildHistoryEntry( - String repoId, Period period, DateTime now, Duration addGracePeriod, String tld) { + String repoId, String tld, DateTime now, Period period, Duration addGracePeriod) { return historyBuilder .setType(HistoryEntry.Type.DOMAIN_ALLOCATE) .setPeriod(period) diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java index 07d3bbe6c..3dfd0f310 100644 --- a/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/java/google/registry/flows/domain/DomainCreateFlow.java @@ -262,7 +262,7 @@ public class DomainCreateFlow implements TransactionalFlow { String repoId = createDomainRepoId(ObjectifyService.allocateId(), registry.getTldStr()); DateTime registrationExpirationTime = leapSafeAddYears(now, years); HistoryEntry historyEntry = buildHistoryEntry( - repoId, period, now, registry.getAddGracePeriodLength(), registry.getTldStr()); + repoId, registry.getTldStr(), now, period, registry.getAddGracePeriodLength()); // Bill for the create. BillingEvent.OneTime createBillingEvent = createOneTimeBillingEvent( @@ -365,7 +365,7 @@ public class DomainCreateFlow implements TransactionalFlow { } private HistoryEntry buildHistoryEntry( - String repoId, Period period, DateTime now, Duration addGracePeriod, String tld) { + String repoId, String tld, DateTime now, Period period, Duration addGracePeriod) { return historyBuilder .setType(HistoryEntry.Type.DOMAIN_CREATE) .setPeriod(period) diff --git a/java/google/registry/flows/domain/DomainDeleteFlow.java b/java/google/registry/flows/domain/DomainDeleteFlow.java index 4f260a92b..f0aca615d 100644 --- a/java/google/registry/flows/domain/DomainDeleteFlow.java +++ b/java/google/registry/flows/domain/DomainDeleteFlow.java @@ -24,22 +24,22 @@ import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; -import static google.registry.flows.domain.DomainFlowUtils.createCancellingRecords; +import static google.registry.flows.domain.DomainFlowUtils.createCancelingRecords; import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime; import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPredelegation; import static google.registry.model.eppoutput.Result.Code.SUCCESS; import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING; import static google.registry.model.ofy.ObjectifyService.ofy; -import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.isAddsField; -import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.isRenewsField; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.ADD_FIELDS; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.RENEW_FIELDS; import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost; import static google.registry.util.CollectionUtils.nullToEmpty; import static google.registry.util.CollectionUtils.union; import com.google.common.base.Optional; -import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import com.googlecode.objectify.Key; import google.registry.dns.DnsQueue; import google.registry.flows.EppException; @@ -245,17 +245,11 @@ public final class DomainDeleteFlow implements TransactionalFlow { registry.getAutoRenewGracePeriodLength(), registry.getRenewGracePeriodLength())); ImmutableSet cancelledRecords = - createCancellingRecords( + createCancelingRecords( existingResource, now, maxGracePeriod, - new Predicate() { - @Override - public boolean apply(@Nullable DomainTransactionRecord domainTransactionRecord) { - return isAddsField(domainTransactionRecord.getReportField()) - || isRenewsField(domainTransactionRecord.getReportField()); - } - }); + Sets.immutableEnumSet(Sets.union(ADD_FIELDS, RENEW_FIELDS))); return historyBuilder .setType(HistoryEntry.Type.DOMAIN_DELETE) .setModificationTime(now) diff --git a/java/google/registry/flows/domain/DomainFlowUtils.java b/java/google/registry/flows/domain/DomainFlowUtils.java index e11ce3d63..aa3ce74c9 100644 --- a/java/google/registry/flows/domain/DomainFlowUtils.java +++ b/java/google/registry/flows/domain/DomainFlowUtils.java @@ -108,6 +108,7 @@ import google.registry.model.registry.Registry.TldState; import google.registry.model.registry.label.ReservationType; import google.registry.model.registry.label.ReservedList; import google.registry.model.reporting.DomainTransactionRecord; +import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField; import google.registry.model.reporting.HistoryEntry; import google.registry.model.tmch.ClaimsListShard; import google.registry.util.FormattingLogger; @@ -925,11 +926,11 @@ public class DomainFlowUtils { * hasn't been reported yet and b) matches the predicate 3. Return the transactionRecords under * the most recent HistoryEntry that fits the above criteria, with negated reportAmounts. */ - static ImmutableSet createCancellingRecords( + static ImmutableSet createCancelingRecords( DomainResource domainResource, final DateTime now, Duration maxSearchPeriod, - final Predicate isCancellable) { + final ImmutableSet cancelableFields) { List recentHistoryEntries = ofy().load() .type(HistoryEntry.class) @@ -937,22 +938,25 @@ public class DomainFlowUtils { .filter("modificationTime >=", now.minus(maxSearchPeriod)) .order("modificationTime") .list(); - Optional entryToCancel = FluentIterable.from(recentHistoryEntries) - .filter( - new Predicate() { - @Override - public boolean apply(HistoryEntry historyEntry) { - // Look for add and renew transaction records that have yet to be reported - for (DomainTransactionRecord record : historyEntry.getDomainTransactionRecords()) { - if (isCancellable.apply(record) && record.getReportingTime().isAfter(now)) { - return true; + Optional entryToCancel = + FluentIterable.from(recentHistoryEntries) + .filter( + new Predicate() { + @Override + public boolean apply(HistoryEntry historyEntry) { + // Look for add and renew transaction records that have yet to be reported + for (DomainTransactionRecord record : + historyEntry.getDomainTransactionRecords()) { + if (cancelableFields.contains(record.getReportField()) + && record.getReportingTime().isAfter(now)) { + return true; + } + } + return false; } - } - return false; - } - }) - // We only want to cancel out the most recent add or renewal - .last(); + }) + // We only want to cancel out the most recent add or renewal + .last(); ImmutableSet.Builder recordsBuilder = new ImmutableSet.Builder<>(); if (entryToCancel.isPresent()) { for (DomainTransactionRecord record : entryToCancel.get().getDomainTransactionRecords()) { diff --git a/java/google/registry/flows/domain/DomainRenewFlow.java b/java/google/registry/flows/domain/DomainRenewFlow.java index 7fcd252bc..c54bc5b88 100644 --- a/java/google/registry/flows/domain/DomainRenewFlow.java +++ b/java/google/registry/flows/domain/DomainRenewFlow.java @@ -156,7 +156,7 @@ public final class DomainRenewFlow implements TransactionalFlow { .build()); Registry registry = Registry.get(existingDomain.getTld()); HistoryEntry historyEntry = buildHistoryEntry( - existingDomain, command.getPeriod(), now, registry.getRenewGracePeriodLength()); + existingDomain, now, command.getPeriod(), registry.getRenewGracePeriodLength()); String tld = existingDomain.getTld(); // Bill for this explicit renew itself. BillingEvent.OneTime explicitRenewEvent = @@ -213,7 +213,7 @@ public final class DomainRenewFlow implements TransactionalFlow { } private HistoryEntry buildHistoryEntry( - DomainResource existingDomain, Period period, DateTime now, Duration renewGracePeriod) { + DomainResource existingDomain, DateTime now, Period period, Duration renewGracePeriod) { return historyBuilder .setType(HistoryEntry.Type.DOMAIN_RENEW) .setPeriod(period) diff --git a/java/google/registry/flows/domain/DomainTransferApproveFlow.java b/java/google/registry/flows/domain/DomainTransferApproveFlow.java index 8b2295d34..491d39545 100644 --- a/java/google/registry/flows/domain/DomainTransferApproveFlow.java +++ b/java/google/registry/flows/domain/DomainTransferApproveFlow.java @@ -22,12 +22,15 @@ import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; +import static google.registry.flows.domain.DomainFlowUtils.createCancelingRecords; import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime; import static google.registry.flows.domain.DomainTransferUtils.createGainingTransferPollMessage; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; import static google.registry.model.domain.DomainResource.extendRegistrationWithCap; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost; +import static google.registry.util.CollectionUtils.union; import static google.registry.util.DateTimeUtils.END_OF_TIME; import com.google.common.base.Optional; @@ -52,6 +55,7 @@ import google.registry.model.eppcommon.AuthInfo; import google.registry.model.eppoutput.EppResponse; import google.registry.model.poll.PollMessage; import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.transfer.TransferData; @@ -109,12 +113,8 @@ public final class DomainTransferApproveFlow implements TransactionalFlow { } TransferData transferData = existingDomain.getTransferData(); String gainingClientId = transferData.getGainingClientId(); - HistoryEntry historyEntry = historyBuilder - .setType(HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE) - .setModificationTime(now) - .setOtherClientId(gainingClientId) - .setParent(Key.create(existingDomain)) - .build(); + Registry registry = Registry.get(existingDomain.getTld()); + HistoryEntry historyEntry = buildHistoryEntry(existingDomain, registry, now, gainingClientId); // Bill for the transfer. BillingEvent.OneTime billingEvent = new BillingEvent.OneTime.Builder() .setReason(Reason.TRANSFER) @@ -191,4 +191,28 @@ public final class DomainTransferApproveFlow implements TransactionalFlow { targetId, newDomain.getTransferData(), newDomain.getRegistrationExpirationTime())) .build(); } + + private HistoryEntry buildHistoryEntry( + DomainResource existingDomain, Registry registry, DateTime now, String gainingClientId) { + ImmutableSet cancelingRecords = + createCancelingRecords( + existingDomain, + now, + registry.getAutomaticTransferLength().plus(registry.getTransferGracePeriodLength()), + ImmutableSet.of(TRANSFER_SUCCESSFUL)); + return historyBuilder + .setType(HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE) + .setModificationTime(now) + .setOtherClientId(gainingClientId) + .setParent(Key.create(existingDomain)) + .setDomainTransactionRecords( + union( + cancelingRecords, + DomainTransactionRecord.create( + existingDomain.getTld(), + now.plus(registry.getTransferGracePeriodLength()), + TRANSFER_SUCCESSFUL, + 1))) + .build(); + } } diff --git a/java/google/registry/flows/domain/DomainTransferCancelFlow.java b/java/google/registry/flows/domain/DomainTransferCancelFlow.java index 337ca68fc..05aebde98 100644 --- a/java/google/registry/flows/domain/DomainTransferCancelFlow.java +++ b/java/google/registry/flows/domain/DomainTransferCancelFlow.java @@ -21,13 +21,16 @@ import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyTransferInitiator; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; +import static google.registry.flows.domain.DomainFlowUtils.createCancelingRecords; import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime; import static google.registry.flows.domain.DomainTransferUtils.createLosingTransferPollMessage; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; import static google.registry.util.DateTimeUtils.END_OF_TIME; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; import com.googlecode.objectify.Key; import google.registry.flows.EppException; import google.registry.flows.ExtensionManager; @@ -41,6 +44,8 @@ import google.registry.model.domain.DomainResource; import google.registry.model.domain.metadata.MetadataExtension; import google.registry.model.eppcommon.AuthInfo; import google.registry.model.eppoutput.EppResponse; +import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.transfer.TransferStatus; @@ -90,12 +95,8 @@ public final class DomainTransferCancelFlow implements TransactionalFlow { if (!isSuperuser) { checkAllowedAccessToTld(clientId, existingDomain.getTld()); } - HistoryEntry historyEntry = historyBuilder - .setType(HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL) - .setOtherClientId(existingDomain.getTransferData().getLosingClientId()) - .setModificationTime(now) - .setParent(Key.create(existingDomain)) - .build(); + Registry registry = Registry.get(existingDomain.getTld()); + HistoryEntry historyEntry = buildHistoryEntry(existingDomain, registry, now); DomainResource newDomain = denyPendingTransfer(existingDomain, TransferStatus.CLIENT_CANCELLED, now); ofy().save().entities( @@ -113,4 +114,21 @@ public final class DomainTransferCancelFlow implements TransactionalFlow { .setResData(createTransferResponse(targetId, newDomain.getTransferData(), null)) .build(); } + + private HistoryEntry buildHistoryEntry( + DomainResource existingDomain, Registry registry, DateTime now) { + ImmutableSet cancelingRecords = + createCancelingRecords( + existingDomain, + now, + registry.getAutomaticTransferLength().plus(registry.getTransferGracePeriodLength()), + ImmutableSet.of(TRANSFER_SUCCESSFUL)); + return historyBuilder + .setType(HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL) + .setOtherClientId(existingDomain.getTransferData().getLosingClientId()) + .setModificationTime(now) + .setParent(Key.create(existingDomain)) + .setDomainTransactionRecords(cancelingRecords) + .build(); + } } diff --git a/java/google/registry/flows/domain/DomainTransferRejectFlow.java b/java/google/registry/flows/domain/DomainTransferRejectFlow.java index 589d0398a..bcd0e9036 100644 --- a/java/google/registry/flows/domain/DomainTransferRejectFlow.java +++ b/java/google/registry/flows/domain/DomainTransferRejectFlow.java @@ -21,13 +21,18 @@ import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; +import static google.registry.flows.domain.DomainFlowUtils.createCancelingRecords; import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime; import static google.registry.flows.domain.DomainTransferUtils.createGainingTransferPollMessage; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_NACKED; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; +import static google.registry.util.CollectionUtils.union; import static google.registry.util.DateTimeUtils.END_OF_TIME; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; import com.googlecode.objectify.Key; import google.registry.flows.EppException; import google.registry.flows.ExtensionManager; @@ -41,6 +46,8 @@ import google.registry.model.domain.DomainResource; import google.registry.model.domain.metadata.MetadataExtension; import google.registry.model.eppcommon.AuthInfo; import google.registry.model.eppoutput.EppResponse; +import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.transfer.TransferStatus; @@ -84,12 +91,8 @@ public final class DomainTransferRejectFlow implements TransactionalFlow { validateClientIsLoggedIn(clientId); DateTime now = ofy().getTransactionTime(); DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now); - HistoryEntry historyEntry = historyBuilder - .setType(HistoryEntry.Type.DOMAIN_TRANSFER_REJECT) - .setModificationTime(now) - .setOtherClientId(existingDomain.getTransferData().getGainingClientId()) - .setParent(Key.create(existingDomain)) - .build(); + Registry registry = Registry.get(existingDomain.getTld()); + HistoryEntry historyEntry = buildHistoryEntry(existingDomain, registry, now); verifyOptionalAuthInfo(authInfo, existingDomain); verifyHasPendingTransfer(existingDomain); verifyResourceOwnership(clientId, existingDomain); @@ -113,4 +116,25 @@ public final class DomainTransferRejectFlow implements TransactionalFlow { .setResData(createTransferResponse(targetId, newDomain.getTransferData(), null)) .build(); } + + private HistoryEntry buildHistoryEntry( + DomainResource existingDomain, Registry registry, DateTime now) { + ImmutableSet cancelingRecords = + createCancelingRecords( + existingDomain, + now, + registry.getAutomaticTransferLength().plus(registry.getTransferGracePeriodLength()), + ImmutableSet.of(TRANSFER_SUCCESSFUL)); + return historyBuilder + .setType(HistoryEntry.Type.DOMAIN_TRANSFER_REJECT) + .setModificationTime(now) + .setOtherClientId(existingDomain.getTransferData().getGainingClientId()) + .setParent(Key.create(existingDomain)) + .setDomainTransactionRecords( + union( + cancelingRecords, + DomainTransactionRecord.create( + existingDomain.getTld(), now, TRANSFER_NACKED, 1))) + .build(); + } } diff --git a/java/google/registry/flows/domain/DomainTransferRequestFlow.java b/java/google/registry/flows/domain/DomainTransferRequestFlow.java index a4375a591..46b9f4158 100644 --- a/java/google/registry/flows/domain/DomainTransferRequestFlow.java +++ b/java/google/registry/flows/domain/DomainTransferRequestFlow.java @@ -61,6 +61,8 @@ import google.registry.model.eppinput.ResourceCommand; import google.registry.model.eppoutput.EppResponse; import google.registry.model.poll.PollMessage; import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; +import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.transfer.TransferData; @@ -141,7 +143,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow { eppInput.getSingleExtension(FeeTransferCommandExtension.class); FeesAndCredits feesAndCredits = pricingLogic.getTransferPrice(registry, targetId, now); validateFeeChallenge(targetId, tld, now, feeTransfer, feesAndCredits); - HistoryEntry historyEntry = buildHistoryEntry(period, existingDomain, now); + HistoryEntry historyEntry = buildHistoryEntry(existingDomain, registry, now, period); DateTime automaticTransferTime = now.plus(registry.getAutomaticTransferLength()); // If the domain will be in the auto-renew grace period at the moment of transfer, the transfer @@ -252,13 +254,21 @@ public final class DomainTransferRequestFlow implements TransactionalFlow { } private HistoryEntry buildHistoryEntry( - Period period, DomainResource existingDomain, DateTime now) { + DomainResource existingDomain, Registry registry, DateTime now, Period period) { return historyBuilder .setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST) .setOtherClientId(existingDomain.getCurrentSponsorClientId()) .setPeriod(period) .setModificationTime(now) .setParent(Key.create(existingDomain)) + .setDomainTransactionRecords( + ImmutableSet.of( + DomainTransactionRecord.create( + registry.getTldStr(), + now.plus(registry.getAutomaticTransferLength()) + .plus(registry.getTransferGracePeriodLength()), + TransactionReportField.TRANSFER_SUCCESSFUL, + 1))) .build(); } diff --git a/java/google/registry/model/reporting/DomainTransactionRecord.java b/java/google/registry/model/reporting/DomainTransactionRecord.java index 3dddd393d..26c5a3a07 100644 --- a/java/google/registry/model/reporting/DomainTransactionRecord.java +++ b/java/google/registry/model/reporting/DomainTransactionRecord.java @@ -97,10 +97,8 @@ public class DomainTransactionRecord extends ImmutableObject implements Buildabl NET_RENEWS_8_YR, NET_RENEWS_9_YR, NET_RENEWS_10_YR, - TRANSFER_GAINING_SUCCESSFUL, - TRANSFER_GAINING_NACKED, - TRANSFER_LOSING_SUCCESSFUL, - TRANSFER_LOSING_NACKED, + TRANSFER_SUCCESSFUL, + TRANSFER_NACKED, DELETED_DOMAINS_GRACE, DELETED_DOMAINS_NOGRACE, RESTORED_DOMAINS; @@ -115,7 +113,7 @@ public class DomainTransactionRecord extends ImmutableObject implements Buildabl return nameToField("NET_RENEWS_%d_YR", years); } - private static final ImmutableSet ADD_FIELDS = + public static final ImmutableSet ADD_FIELDS = ImmutableSet.of( NET_ADDS_1_YR, NET_ADDS_2_YR, @@ -128,7 +126,7 @@ public class DomainTransactionRecord extends ImmutableObject implements Buildabl NET_ADDS_9_YR, NET_ADDS_10_YR); - private static final ImmutableSet RENEW_FIELDS = + public static final ImmutableSet RENEW_FIELDS = ImmutableSet.of( NET_RENEWS_1_YR, NET_RENEWS_2_YR, @@ -141,16 +139,6 @@ public class DomainTransactionRecord extends ImmutableObject implements Buildabl NET_RENEWS_9_YR, NET_RENEWS_10_YR); - - /** Boilerplate to determine if a field is one of the NET_ADDS fields. */ - public static boolean isAddsField(TransactionReportField field) { - return ADD_FIELDS.contains(field); - } - /** Boilerplate to determine if a field is one of the NET_ADDS fields. */ - public static boolean isRenewsField(TransactionReportField field) { - return RENEW_FIELDS.contains(field); - } - private static TransactionReportField nameToField(String enumTemplate, int years) { checkArgument( years >= 1 && years <= 10, "domain add and renew years must be between 1 and 10"); diff --git a/javatests/google/registry/flows/domain/DomainTransferApproveFlowTest.java b/javatests/google/registry/flows/domain/DomainTransferApproveFlowTest.java index 96dbfa2a4..586f74162 100644 --- a/javatests/google/registry/flows/domain/DomainTransferApproveFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainTransferApproveFlowTest.java @@ -17,6 +17,10 @@ package google.registry.flows.domain; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST; import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.deleteResource; @@ -57,6 +61,7 @@ import google.registry.model.eppcommon.Trid; import google.registry.model.poll.PendingActionNotificationResponse; import google.registry.model.poll.PollMessage; import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.HistoryEntry; import google.registry.model.transfer.TransferResponse.DomainTransferResponse; import google.registry.model.transfer.TransferStatus; @@ -139,12 +144,12 @@ public class DomainTransferApproveFlowTest runFlowAssertResponse(readFile(expectedXmlFilename)); // Transfer should have succeeded. Verify correct fields were set. domain = reloadResourceByForeignKey(); - assertAboutDomains().that(domain).hasOneHistoryEntryEachOfTypes( - HistoryEntry.Type.DOMAIN_CREATE, - HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST, - HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE); + assertAboutDomains() + .that(domain) + .hasOneHistoryEntryEachOfTypes( + DOMAIN_CREATE, DOMAIN_TRANSFER_REQUEST, DOMAIN_TRANSFER_APPROVE); final HistoryEntry historyEntryTransferApproved = - getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE); + getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_APPROVE); assertAboutHistoryEntries().that(historyEntryTransferApproved) .hasOtherClientId("NewRegistrar"); assertTransferApproved(domain); @@ -445,4 +450,53 @@ public class DomainTransferApproveFlowTest assertIcannReportingActivityFieldLogged("srs-dom-transfer-approve"); assertTldsFieldLogged("tld"); } + + private void setUpGracePeriodDurations() { + persistResource( + Registry.get("tld") + .asBuilder() + .setAutomaticTransferLength(Duration.standardDays(2)) + .setTransferGracePeriodLength(Duration.standardDays(3)) + .build()); + } + + @Test + public void testIcannTransactionRecord_noRecordsToCancel() throws Exception { + setUpGracePeriodDurations(); + clock.advanceOneMilli(); + runFlow(); + HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_APPROVE); + // We should only produce a transfer success record for (now + transfer grace period) + assertThat(persistedEntry.getDomainTransactionRecords()) + .containsExactly( + DomainTransactionRecord.create( + "tld", clock.nowUtc().plusDays(3), TRANSFER_SUCCESSFUL, 1)); + } + + @Test + public void testIcannTransactionRecord_cancelsPreviousRecords() throws Exception { + clock.advanceOneMilli(); + setUpGracePeriodDurations(); + DomainTransactionRecord previousSuccessRecord = + DomainTransactionRecord.create( + "tld", clock.nowUtc().plusDays(1), TRANSFER_SUCCESSFUL, 1); + persistResource( + new HistoryEntry.Builder() + .setType(DOMAIN_TRANSFER_REQUEST) + .setParent(domain) + .setModificationTime(clock.nowUtc().minusDays(4)) + .setDomainTransactionRecords( + ImmutableSet.of(previousSuccessRecord)) + .build()); + runFlow(); + HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_APPROVE); + // We should produce cancellation records for the original reporting date (now + 1 day) and + // success records for the new reporting date (now + transferGracePeriod=3 days) + assertThat(persistedEntry.getDomainTransactionRecords()) + .containsExactly( + previousSuccessRecord.asBuilder().setReportAmount(-1).build(), + DomainTransactionRecord.create( + "tld", clock.nowUtc().plusDays(3), TRANSFER_SUCCESSFUL, 1)); + + } } diff --git a/javatests/google/registry/flows/domain/DomainTransferCancelFlowTest.java b/javatests/google/registry/flows/domain/DomainTransferCancelFlowTest.java index a6ebb4a30..32e94b986 100644 --- a/javatests/google/registry/flows/domain/DomainTransferCancelFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainTransferCancelFlowTest.java @@ -15,6 +15,10 @@ package google.registry.flows.domain; import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST; import static google.registry.testing.DatastoreHelper.assertBillingEvents; import static google.registry.testing.DatastoreHelper.createPollMessageForImplicitTransfer; import static google.registry.testing.DatastoreHelper.deleteResource; @@ -39,10 +43,13 @@ import google.registry.model.domain.DomainResource; import google.registry.model.domain.GracePeriod; import google.registry.model.eppcommon.AuthInfo.PasswordAuth; import google.registry.model.poll.PollMessage; +import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.HistoryEntry; import google.registry.model.transfer.TransferResponse.DomainTransferResponse; import google.registry.model.transfer.TransferStatus; import org.joda.time.DateTime; +import org.joda.time.Duration; import org.junit.Before; import org.junit.Test; @@ -113,12 +120,12 @@ public class DomainTransferCancelFlowTest assertAboutDomains().that(domain) .hasRegistrationExpirationTime(originalExpirationTime).and() .hasLastTransferTimeNotEqualTo(clock.nowUtc()); - assertAboutDomains().that(domain).hasOneHistoryEntryEachOfTypes( - HistoryEntry.Type.DOMAIN_CREATE, - HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST, - HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL); + assertAboutDomains() + .that(domain) + .hasOneHistoryEntryEachOfTypes( + DOMAIN_CREATE, DOMAIN_TRANSFER_REQUEST, DOMAIN_TRANSFER_CANCEL); final HistoryEntry historyEntryTransferCancel = - getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL); + getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_CANCEL); assertAboutHistoryEntries().that(historyEntryTransferCancel).hasClientId("NewRegistrar") .and().hasOtherClientId("TheRegistrar"); // The only billing event left should be the original autorenew event, now reopened. @@ -138,7 +145,7 @@ public class DomainTransferCancelFlowTest .setEventTime(originalExpirationTime) .setAutorenewEndTime(END_OF_TIME) .setMsg("Domain was auto-renewed.") - .setParent(getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_CREATE)) + .setParent(getOnlyHistoryEntryOfType(domain, DOMAIN_CREATE)) .build(), new PollMessage.OneTime.Builder() .setClientId("TheRegistrar") @@ -152,7 +159,7 @@ public class DomainTransferCancelFlowTest .setPendingTransferExpirationTime(clock.nowUtc()) .build())) .setMsg("Transfer cancelled.") - .setParent(getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL)) + .setParent(getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_CANCEL)) .build()); // The original grace periods should remain untouched. @@ -323,4 +330,38 @@ public class DomainTransferCancelFlowTest assertIcannReportingActivityFieldLogged("srs-dom-transfer-cancel"); assertTldsFieldLogged("tld"); } + + @Test + public void testIcannTransactionRecord_noRecordsToCancel() throws Exception { + clock.advanceOneMilli(); + runFlow(); + HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_CANCEL); + // No cancellation records should be produced + assertThat(persistedEntry.getDomainTransactionRecords()).isEmpty(); + } + + @Test + public void testIcannTransactionRecord_cancelsPreviousRecords() throws Exception { + clock.advanceOneMilli(); + persistResource( + Registry.get("tld") + .asBuilder() + .setAutomaticTransferLength(Duration.standardDays(2)) + .setTransferGracePeriodLength(Duration.standardDays(3)) + .build()); + DomainTransactionRecord previousSuccessRecord = + DomainTransactionRecord.create("tld", clock.nowUtc().plusDays(1), TRANSFER_SUCCESSFUL, 1); + persistResource( + new HistoryEntry.Builder() + .setType(DOMAIN_TRANSFER_REQUEST) + .setParent(domain) + .setModificationTime(clock.nowUtc().minusDays(4)) + .setDomainTransactionRecords(ImmutableSet.of(previousSuccessRecord)) + .build()); + runFlow(); + HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_CANCEL); + // We should produce a cancellation record for the original transfer success + assertThat(persistedEntry.getDomainTransactionRecords()) + .containsExactly(previousSuccessRecord.asBuilder().setReportAmount(-1).build()); + } } diff --git a/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java b/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java index 738755d71..a0eea3794 100644 --- a/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java @@ -15,6 +15,11 @@ package google.registry.flows.domain; import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_NACKED; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REJECT; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST; import static google.registry.testing.DatastoreHelper.assertBillingEvents; import static google.registry.testing.DatastoreHelper.deleteResource; import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType; @@ -42,10 +47,13 @@ import google.registry.model.eppcommon.AuthInfo.PasswordAuth; import google.registry.model.eppcommon.Trid; import google.registry.model.poll.PendingActionNotificationResponse; import google.registry.model.poll.PollMessage; +import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.HistoryEntry; import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferStatus; import org.joda.time.DateTime; +import org.joda.time.Duration; import org.junit.Before; import org.junit.Test; @@ -88,11 +96,9 @@ public class DomainTransferRejectFlowTest .hasRegistrationExpirationTime(originalExpirationTime).and() .hasLastTransferTimeNotEqualTo(clock.nowUtc()).and() .hasOneHistoryEntryEachOfTypes( - HistoryEntry.Type.DOMAIN_CREATE, - HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST, - HistoryEntry.Type.DOMAIN_TRANSFER_REJECT); + DOMAIN_CREATE, DOMAIN_TRANSFER_REQUEST, DOMAIN_TRANSFER_REJECT); final HistoryEntry historyEntryTransferRejected = - getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_TRANSFER_REJECT); + getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_REJECT); assertAboutHistoryEntries() .that(historyEntryTransferRejected) .hasOtherClientId("NewRegistrar"); @@ -285,4 +291,46 @@ public class DomainTransferRejectFlowTest assertIcannReportingActivityFieldLogged("srs-dom-transfer-reject"); assertTldsFieldLogged("tld"); } + + private void setUpGracePeriodDurations() { + persistResource( + Registry.get("tld") + .asBuilder() + .setAutomaticTransferLength(Duration.standardDays(2)) + .setTransferGracePeriodLength(Duration.standardDays(3)) + .build()); + } + + @Test + public void testIcannTransactionRecord_noRecordsToCancel() throws Exception { + setUpGracePeriodDurations(); + runFlow(); + HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_REJECT); + // We should only produce transfer nacked records, reported now + assertThat(persistedEntry.getDomainTransactionRecords()) + .containsExactly(DomainTransactionRecord.create("tld", clock.nowUtc(), TRANSFER_NACKED, 1)); + } + + @Test + public void testIcannTransactionRecord_cancelsPreviousRecords() throws Exception { + setUpGracePeriodDurations(); + DomainTransactionRecord previousSuccessRecord = + DomainTransactionRecord.create( + "tld", clock.nowUtc().plusDays(1), TRANSFER_SUCCESSFUL, 1); + persistResource( + new HistoryEntry.Builder() + .setType(DOMAIN_TRANSFER_REQUEST) + .setParent(domain) + .setModificationTime(clock.nowUtc().minusDays(4)) + .setDomainTransactionRecords( + ImmutableSet.of(previousSuccessRecord)) + .build()); + runFlow(); + HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_REJECT); + // We should produce cancellation records for the original success records and nack records + assertThat(persistedEntry.getDomainTransactionRecords()) + .containsExactly( + previousSuccessRecord.asBuilder().setReportAmount(-1).build(), + DomainTransactionRecord.create("tld", clock.nowUtc(), TRANSFER_NACKED, 1)); + } } diff --git a/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java index 46147488f..8b9ee8c50 100644 --- a/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java @@ -16,6 +16,9 @@ package google.registry.flows.domain; import static com.google.common.truth.Truth.assertThat; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE; +import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST; import static google.registry.testing.DatastoreHelper.assertBillingEvents; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType; @@ -68,6 +71,7 @@ import google.registry.model.eppcommon.StatusValue; import google.registry.model.poll.PendingActionNotificationResponse; import google.registry.model.poll.PollMessage; import google.registry.model.registry.Registry; +import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.HistoryEntry; import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferStatus; @@ -163,14 +167,12 @@ public class DomainTransferRequestFlowTest // Transfer should have been requested. Verify correct fields were set. domain = reloadResourceByForeignKey(); final HistoryEntry historyEntryTransferRequest = - getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST); + getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_REQUEST); subordinateHost = reloadResourceAndCloneAtTime(subordinateHost, clock.nowUtc()); assertTransferRequested(domain); assertAboutDomains().that(domain) .hasPendingTransferExpirationTime(implicitTransferTime).and() - .hasOneHistoryEntryEachOfTypes( - HistoryEntry.Type.DOMAIN_CREATE, - HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST); + .hasOneHistoryEntryEachOfTypes(DOMAIN_CREATE, DOMAIN_TRANSFER_REQUEST); assertAboutHistoryEntries() .that(historyEntryTransferRequest) .hasPeriodYears(1) @@ -971,4 +973,23 @@ public class DomainTransferRequestFlowTest assertIcannReportingActivityFieldLogged("srs-dom-transfer-request"); assertTldsFieldLogged("tld"); } + + @Test + public void testIcannTransactionRecord_getsStored() throws Exception { + setupDomain("example", "tld"); + persistResource( + Registry.get("tld") + .asBuilder() + .setAutomaticTransferLength(Duration.standardDays(2)) + .setTransferGracePeriodLength(Duration.standardDays(3)) + .build()); + clock.advanceOneMilli(); + runTest("domain_transfer_request.xml", UserPrivileges.NORMAL); + HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_REQUEST); + // We should produce a transfer success record + assertThat(persistedEntry.getDomainTransactionRecords()) + .containsExactly( + DomainTransactionRecord.create( + "tld", clock.nowUtc().plusDays(5), TRANSFER_SUCCESSFUL, 1)); + } } diff --git a/javatests/google/registry/model/schema.txt b/javatests/google/registry/model/schema.txt index 15b53a213..b699d54b4 100644 --- a/javatests/google/registry/model/schema.txt +++ b/javatests/google/registry/model/schema.txt @@ -811,10 +811,8 @@ enum google.registry.model.reporting.DomainTransactionRecord$TransactionReportFi NET_RENEWS_8_YR; NET_RENEWS_9_YR; RESTORED_DOMAINS; - TRANSFER_GAINING_NACKED; - TRANSFER_GAINING_SUCCESSFUL; - TRANSFER_LOSING_NACKED; - TRANSFER_LOSING_SUCCESSFUL; + TRANSFER_NACKED; + TRANSFER_SUCCESSFUL; } class google.registry.model.reporting.HistoryEntry { @Id long id;