diff --git a/java/google/registry/batch/ExpandRecurringBillingEventsAction.java b/java/google/registry/batch/ExpandRecurringBillingEventsAction.java index 625ece5a3..44a0a4ec8 100644 --- a/java/google/registry/batch/ExpandRecurringBillingEventsAction.java +++ b/java/google/registry/batch/ExpandRecurringBillingEventsAction.java @@ -139,7 +139,9 @@ public class ExpandRecurringBillingEventsAction implements Runnable { } getContext().incrementCounter("Recurring billing events encountered"); // Ignore any recurring billing events that have yet to apply. - if (recurring.getEventTime().isAfter(executeTime)) { + if (recurring.getEventTime().isAfter(executeTime) + // This second case occurs when a domain is transferred or deleted before first renewal. + || recurring.getRecurrenceEndTime().isBefore(recurring.getEventTime())) { getContext().incrementCounter("Recurring billing events ignored"); return; } diff --git a/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java b/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java index 50427e762..92ac3995f 100644 --- a/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java +++ b/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java @@ -392,6 +392,18 @@ public class ExpandRecurringBillingEventsActionTest assertCursorAt(beginningOfTest); } + @Test + public void testSuccess_expandSingleEvent_recurrenceEndBeforeEvent() throws Exception { + // This can occur when a domain is transferred or deleted before a domain comes up for renewal. + recurring = persistResource(recurring.asBuilder() + .setRecurrenceEndTime(recurring.getEventTime().minusDays(5)) + .build()); + action.cursorTimeParam = Optional.of(START_OF_TIME); + runMapreduce(); + assertBillingEventsForResource(domain, recurring); + assertCursorAt(beginningOfTest); + } + @Test public void testSuccess_expandSingleEvent_dryRun() throws Exception { persistResource(recurring);