killbill-memoizeit
Changes
invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java 13(+7 -6)
invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java 9(+5 -4)
invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDateNotificationKey.java 68(+63 -5)
invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotificationKey.java 8(+4 -4)
Details
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java b/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
index 16835c6..f5b891c 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/InvoiceApiHelper.java
@@ -28,6 +28,7 @@ import java.util.UUID;
import javax.annotation.Nullable;
import javax.inject.Inject;
+import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.callcontext.InternalCallContext;
@@ -84,7 +85,10 @@ public class InvoiceApiHelper {
final boolean isRescheduled = false;
final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, context);
- invoicePluginDispatcher.priorCall(targetDate, existingInvoices, isDryRun, isRescheduled, context, internalTenantContext);
+ final DateTime rescheduleDate = invoicePluginDispatcher.priorCall(targetDate, existingInvoices, isDryRun, isRescheduled, context, internalTenantContext);
+ if (rescheduleDate != null) {
+ log.warn("Ignoring rescheduleDate='{}', delayed scheduling is unsupported for API calls", rescheduleDate);
+ }
boolean success = false;
GlobalLock lock = null;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 29784f4..29668fb 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -230,7 +230,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
final CallContext context) throws InvoiceApiException {
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(accountId, context);
- final Invoice result = dispatcher.processAccount(true, accountId, targetDate, dryRunArguments, internalContext);
+ final Invoice result = dispatcher.processAccount(true, accountId, targetDate, dryRunArguments, false, internalContext);
if (result == null) {
throw new InvoiceApiException(ErrorCode.INVOICE_NOTHING_TO_DO, accountId, targetDate != null ? targetDate : "null");
} else {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index c51221b..1283805 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -1000,13 +1000,14 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
});
}
- private void notifyOfFutureBillingEvents(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final UUID accountId,
- final FutureAccountNotifications callbackDateTimePerSubscriptions, final InternalCallContext internalCallContext) {
-
+ private void notifyOfFutureBillingEvents(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory,
+ final UUID accountId,
+ final FutureAccountNotifications callbackDateTimePerSubscriptions,
+ final InternalCallContext internalCallContext) {
for (final LocalDate notificationDate : callbackDateTimePerSubscriptions.getNotificationsForTrigger().keySet()) {
final DateTime notificationDateTime = internalCallContext.toUTCDateTime(notificationDate);
final Set<UUID> subscriptionIds = callbackDateTimePerSubscriptions.getNotificationsForTrigger().get(notificationDate);
- nextBillingDatePoster.insertNextBillingNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionIds, notificationDateTime, internalCallContext);
+ nextBillingDatePoster.insertNextBillingNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionIds, notificationDateTime, callbackDateTimePerSubscriptions.isRescheduled(), internalCallContext);
}
final long dryRunNotificationTime = invoiceConfig.getDryRunNotificationSchedule(internalCallContext).getMillis();
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index b936c5a..f26102b 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -116,6 +116,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
@@ -214,27 +215,21 @@ public class InvoiceDispatcher {
} catch (final CatalogApiException e) {
log.warn("Failed to retrieve BillingEvents for accountId='{}'", accountId, e);
}
-
-
-
-
}
-
-
public void processSubscriptionForInvoiceGeneration(final EffectiveSubscriptionInternalEvent transition,
final InternalCallContext context) throws InvoiceApiException {
final UUID subscriptionId = transition.getSubscriptionId();
final LocalDate targetDate = context.toLocalDate(transition.getEffectiveTransitionTime());
- processSubscriptionForInvoiceGeneration(subscriptionId, targetDate, context);
+ processSubscriptionForInvoiceGeneration(subscriptionId, targetDate, false, context);
}
- public void processSubscriptionForInvoiceGeneration(final UUID subscriptionId, final LocalDate targetDate, final InternalCallContext context) throws InvoiceApiException {
- processSubscriptionInternal(subscriptionId, targetDate, false, context);
+ public void processSubscriptionForInvoiceGeneration(final UUID subscriptionId, final LocalDate targetDate, final boolean isRescheduled, final InternalCallContext context) throws InvoiceApiException {
+ processSubscriptionInternal(subscriptionId, targetDate, false, isRescheduled, context);
}
public void processSubscriptionForInvoiceNotification(final UUID subscriptionId, final LocalDate targetDate, final InternalCallContext context) throws InvoiceApiException {
- final Invoice dryRunInvoice = processSubscriptionInternal(subscriptionId, targetDate, true, context);
+ final Invoice dryRunInvoice = processSubscriptionInternal(subscriptionId, targetDate, true, false, context);
if (dryRunInvoice != null && dryRunInvoice.getBalance().compareTo(BigDecimal.ZERO) > 0) {
final InvoiceNotificationInternalEvent event = new DefaultInvoiceNotificationInternalEvent(dryRunInvoice.getAccountId(), dryRunInvoice.getBalance(), dryRunInvoice.getCurrency(),
context.toUTCDateTime(targetDate), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
@@ -246,7 +241,7 @@ public class InvoiceDispatcher {
}
}
- private Invoice processSubscriptionInternal(final UUID subscriptionId, final LocalDate targetDate, final boolean dryRunForNotification, final InternalCallContext context) throws InvoiceApiException {
+ private Invoice processSubscriptionInternal(final UUID subscriptionId, final LocalDate targetDate, final boolean dryRunForNotification, final boolean isRescheduled, final InternalCallContext context) throws InvoiceApiException {
try {
if (subscriptionId == null) {
log.warn("Failed handling SubscriptionBase change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
@@ -255,7 +250,7 @@ public class InvoiceDispatcher {
final UUID accountId = subscriptionApi.getAccountIdFromSubscriptionId(subscriptionId, context);
final DryRunArguments dryRunArguments = dryRunForNotification ? TARGET_DATE_DRY_RUN_ARGUMENTS : null;
- return processAccountFromNotificationOrBusEvent(accountId, targetDate, dryRunArguments, context);
+ return processAccountFromNotificationOrBusEvent(accountId, targetDate, dryRunArguments, isRescheduled, context);
} catch (final SubscriptionBaseApiException e) {
log.warn("Failed handling SubscriptionBase change.",
new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
@@ -266,6 +261,7 @@ public class InvoiceDispatcher {
public Invoice processAccountFromNotificationOrBusEvent(final UUID accountId,
@Nullable final LocalDate targetDate,
@Nullable final DryRunArguments dryRunArguments,
+ final boolean isRescheduled,
final InternalCallContext context) throws InvoiceApiException {
if (!invoiceConfig.isInvoicingSystemEnabled(context)) {
log.warn("Invoicing system is off, parking accountId='{}'", accountId);
@@ -273,13 +269,14 @@ public class InvoiceDispatcher {
return null;
}
- return processAccount(false, accountId, targetDate, dryRunArguments, context);
+ return processAccount(false, accountId, targetDate, dryRunArguments, isRescheduled, context);
}
public Invoice processAccount(final boolean isApiCall,
final UUID accountId,
@Nullable final LocalDate targetDate,
@Nullable final DryRunArguments dryRunArguments,
+ final boolean isRescheduled,
final InternalCallContext context) throws InvoiceApiException {
boolean parkedAccount = false;
try {
@@ -296,7 +293,7 @@ public class InvoiceDispatcher {
try {
lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), accountId.toString(), invoiceConfig.getMaxGlobalLockRetries());
- return processAccountWithLock(parkedAccount, accountId, targetDate, dryRunArguments, context);
+ return processAccountWithLock(parkedAccount, accountId, targetDate, dryRunArguments, isRescheduled, context);
} catch (final LockFailedException e) {
log.warn("Failed to process invoice for accountId='{}', targetDate='{}'", accountId.toString(), targetDate, e);
} finally {
@@ -311,6 +308,7 @@ public class InvoiceDispatcher {
final UUID accountId,
@Nullable final LocalDate inputTargetDateMaybeNull,
@Nullable final DryRunArguments dryRunArguments,
+ final boolean isRescheduled,
final InternalCallContext context) throws InvoiceApiException {
final boolean isDryRun = dryRunArguments != null;
final boolean upcomingInvoiceDryRun = isDryRun && DryRunType.UPCOMING_INVOICE.equals(dryRunArguments.getDryRunType());
@@ -340,9 +338,9 @@ public class InvoiceDispatcher {
return new DefaultInvoice(input);
}
}));
- Invoice invoice;
+ final Invoice invoice;
if (!isDryRun) {
- invoice = processAccountWithLockAndInputTargetDate(accountId, inputTargetDate, billingEvents, existingInvoices, false, context);
+ invoice = processAccountWithLockAndInputTargetDate(accountId, inputTargetDate, billingEvents, existingInvoices, false, isRescheduled, context);
if (parkedAccount) {
try {
log.info("Illegal invoicing state fixed for accountId='{}', unparking account", accountId);
@@ -428,7 +426,7 @@ public class InvoiceDispatcher {
private Invoice processDryRun_UPCOMING_INVOICE_Invoice(final UUID accountId, final List<LocalDate> allCandidateTargetDates, final BillingEventSet billingEvents, final List<Invoice> existingInvoices, final InternalCallContext context) throws InvoiceApiException {
for (final LocalDate curTargetDate : allCandidateTargetDates) {
- final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDate, billingEvents, existingInvoices, true, context);
+ final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDate, billingEvents, existingInvoices, true, false, context);
if (invoice != null) {
return invoice;
}
@@ -459,14 +457,14 @@ public class InvoiceDispatcher {
// Generate a dryRun invoice for such date if required in such a way that dryRun invoice on our targetDate only contains items that we expect to see
final Invoice additionalInvoice = prevLocalDate != null ?
- processAccountWithLockAndInputTargetDate(accountId, prevLocalDate, billingEvents, existingInvoices, true, context) :
+ processAccountWithLockAndInputTargetDate(accountId, prevLocalDate, billingEvents, existingInvoices, true, false, context) :
null;
final List<Invoice> augmentedExistingInvoices = additionalInvoice != null ?
new ImmutableList.Builder().addAll(existingInvoices).add(additionalInvoice).build() :
existingInvoices;
- final Invoice targetInvoice = processAccountWithLockAndInputTargetDate(accountId, targetDate, billingEvents, augmentedExistingInvoices, true, context);
+ final Invoice targetInvoice = processAccountWithLockAndInputTargetDate(accountId, targetDate, billingEvents, augmentedExistingInvoices, true, false, context);
// If our targetDate -- user specified -- did not align with any boundary, we return previous 'additionalInvoice' invoice
return targetInvoice != null ? targetInvoice : additionalInvoice;
}
@@ -508,11 +506,9 @@ public class InvoiceDispatcher {
final BillingEventSet billingEvents,
final List<Invoice> existingInvoices,
final boolean isDryRun,
+ final boolean isRescheduled,
final InternalCallContext internalCallContext) throws InvoiceApiException {
- final boolean isRescheduled = false; // TODO
-
final CallContext callContext = buildCallContext(internalCallContext);
- invoicePluginDispatcher.priorCall(targetDate, existingInvoices, isDryRun, isRescheduled, callContext, internalCallContext);
final ImmutableAccountData account;
try {
@@ -523,6 +519,17 @@ public class InvoiceDispatcher {
return null;
}
+ final DateTime rescheduleDate = invoicePluginDispatcher.priorCall(targetDate, existingInvoices, isDryRun, isRescheduled, callContext, internalCallContext);
+ if (rescheduleDate != null) {
+ if (isDryRun) {
+ log.warn("Ignoring rescheduleDate='{}', delayed scheduling is unsupported in dry-run", rescheduleDate);
+ } else {
+ final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(rescheduleDate, billingEvents, internalCallContext);
+ commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, internalCallContext);
+ }
+ return null;
+ }
+
final InvoiceWithMetadata invoiceWithMetadata = generateKillBillInvoice(account, targetDate, billingEvents, existingInvoices, internalCallContext);
final DefaultInvoice invoice = invoiceWithMetadata.getInvoice();
@@ -669,17 +676,37 @@ public class InvoiceDispatcher {
return generator.generateInvoice(account, billingEvents, existingInvoices, targetInvoiceId, targetDate, account.getCurrency(), context);
}
+ private FutureAccountNotifications createNextFutureNotificationDate(final DateTime rescheduleDate, final BillingEventSet billingEvents, final InternalCallContext context) {
+ final FutureAccountNotificationsBuilder notificationsBuilder = new FutureAccountNotificationsBuilder();
+ notificationsBuilder.setRescheduled(true);
+
+ final Set<UUID> subscriptionIds = ImmutableSet.<UUID>copyOf(Iterables.<BillingEvent, UUID>transform(billingEvents,
+ new Function<BillingEvent, UUID>() {
+ @Override
+ public UUID apply(final BillingEvent billingEvent) {
+ return billingEvent.getSubscription().getId();
+ }
+ }));
+ populateNextFutureNotificationDate(rescheduleDate, subscriptionIds, notificationsBuilder, context);
+
+ // Even though a plugin forced us to reschedule the invoice generation, honor the dry run notifications settings
+ populateNextFutureDryRunNotificationDate(billingEvents, notificationsBuilder, context);
+ return notificationsBuilder.build();
+ }
- private FutureAccountNotifications createNextFutureNotificationDate(final InvoiceWithMetadata invoiceWithMetadata, final BillingEventSet billingEvents, final InternalCallContext context) {
+ private void populateNextFutureNotificationDate(final DateTime notificationDateTime, final Set<UUID> subscriptionIds, final FutureAccountNotificationsBuilder notificationsBuilder, final InternalCallContext context) {
+ final LocalDate notificationDate = context.toLocalDate(notificationDateTime);
+ notificationsBuilder.setNotificationListForTrigger(ImmutableMap.<LocalDate, Set<UUID>>of(notificationDate, subscriptionIds));
+ }
+ private FutureAccountNotifications createNextFutureNotificationDate(final InvoiceWithMetadata invoiceWithMetadata, final BillingEventSet billingEvents, final InternalCallContext context) {
final FutureAccountNotificationsBuilder notificationsBuilder = new FutureAccountNotificationsBuilder();
populateNextFutureNotificationDate(invoiceWithMetadata, notificationsBuilder);
populateNextFutureDryRunNotificationDate(billingEvents, notificationsBuilder, context);
return notificationsBuilder.build();
}
-
private void populateNextFutureNotificationDate(final InvoiceWithMetadata invoiceWithMetadata, final FutureAccountNotificationsBuilder notificationsBuilder) {
final Map<LocalDate, Set<UUID>> notificationListForTrigger = new HashMap<LocalDate, Set<UUID>>();
@@ -869,14 +896,16 @@ public class InvoiceDispatcher {
private final Map<LocalDate, Set<UUID>> notificationListForTrigger;
private final Map<LocalDate, Set<UUID>> notificationListForDryRun;
+ private final boolean isRescheduled;
public FutureAccountNotifications() {
- this(ImmutableMap.<LocalDate, Set<UUID>>of(), ImmutableMap.<LocalDate, Set<UUID>>of());
+ this(ImmutableMap.<LocalDate, Set<UUID>>of(), ImmutableMap.<LocalDate, Set<UUID>>of(), false);
}
- public FutureAccountNotifications(final Map<LocalDate, Set<UUID>> notificationListForTrigger, final Map<LocalDate, Set<UUID>> notificationListForDryRun) {
+ public FutureAccountNotifications(final Map<LocalDate, Set<UUID>> notificationListForTrigger, final Map<LocalDate, Set<UUID>> notificationListForDryRun, final boolean isRescheduled) {
this.notificationListForTrigger = notificationListForTrigger;
this.notificationListForDryRun = notificationListForDryRun;
+ this.isRescheduled = isRescheduled;
}
public Map<LocalDate, Set<UUID>> getNotificationsForTrigger() {
@@ -887,12 +916,15 @@ public class InvoiceDispatcher {
return notificationListForDryRun;
}
-
+ public boolean isRescheduled() {
+ return isRescheduled;
+ }
public static class FutureAccountNotificationsBuilder {
private Map<LocalDate, Set<UUID>> notificationListForTrigger;
private Map<LocalDate, Set<UUID>> notificationListForDryRun;
+ private boolean isRescheduled = false;
public FutureAccountNotificationsBuilder() {
}
@@ -905,6 +937,10 @@ public class InvoiceDispatcher {
this.notificationListForDryRun = notificationListForDryRun;
}
+ public void setRescheduled(final boolean rescheduled) {
+ isRescheduled = rescheduled;
+ }
+
public Map<LocalDate, Set<UUID>> getNotificationListForTrigger() {
return MoreObjects.firstNonNull(notificationListForTrigger, ImmutableMap.<LocalDate, Set<UUID>>of());
}
@@ -913,8 +949,12 @@ public class InvoiceDispatcher {
return MoreObjects.firstNonNull(notificationListForDryRun, ImmutableMap.<LocalDate, Set<UUID>>of());
}
+ public boolean isRescheduled() {
+ return isRescheduled;
+ }
+
public FutureAccountNotifications build() {
- return new FutureAccountNotifications(getNotificationListForTrigger(), getNotificationListForDryRun());
+ return new FutureAccountNotifications(getNotificationListForTrigger(), getNotificationListForDryRun(), isRescheduled());
}
}
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
index eee8749..a57f621 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -109,7 +109,7 @@ public class InvoiceListener extends RetryableService implements InvoiceListener
try {
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "SubscriptionBaseTransition", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
final UUID accountId = accountApi.getByRecordId(event.getSearchKey1(), context);
- dispatcher.processAccountFromNotificationOrBusEvent(accountId, null, null, context);
+ dispatcher.processAccountFromNotificationOrBusEvent(accountId, null, null, false, context);
} catch (final InvoiceApiException e) {
log.warn("Unable to process event {}", event, e);
} catch (final AccountApiException e) {
@@ -206,12 +206,10 @@ public class InvoiceListener extends RetryableService implements InvoiceListener
retryableSubscriber.handleEvent(event);
}
-
-
- public void handleNextBillingDateEvent(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+ public void handleNextBillingDateEvent(final UUID subscriptionId, final DateTime eventDateTime, final boolean isRescheduled, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "Next Billing Date", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
try {
- dispatcher.processSubscriptionForInvoiceGeneration(subscriptionId, context.toLocalDate(eventDateTime), context);
+ dispatcher.processSubscriptionForInvoiceGeneration(subscriptionId, context.toLocalDate(eventDateTime), isRescheduled, context);
} catch (final InvoiceApiException e) {
log.warn("Unable to process subscriptionId='{}', eventDateTime='{}'", subscriptionId, eventDateTime, e);
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java
index 2c3a6b1..0e4a868 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoicePluginDispatcher.java
@@ -19,12 +19,15 @@ package org.killbill.billing.invoice;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
+import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.callcontext.InternalTenantContext;
@@ -36,6 +39,7 @@ import org.killbill.billing.invoice.api.InvoiceItemType;
import org.killbill.billing.invoice.model.DefaultInvoice;
import org.killbill.billing.invoice.plugin.api.InvoiceContext;
import org.killbill.billing.invoice.plugin.api.InvoicePluginApi;
+import org.killbill.billing.invoice.plugin.api.PriorInvoiceResult;
import org.killbill.billing.osgi.api.OSGIServiceRegistration;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.util.callcontext.CallContext;
@@ -65,16 +69,30 @@ public class InvoicePluginDispatcher {
this.invoiceConfig = invoiceConfig;
}
- public void priorCall(final LocalDate targetDate, final List<Invoice> existingInvoices, final boolean isDryRun, final boolean isRescheduled, final CallContext callContext, final InternalTenantContext internalTenantContext) {
- final List<InvoicePluginApi> invoicePlugins = getInvoicePlugins(internalTenantContext);
+ public DateTime priorCall(final LocalDate targetDate, final List<Invoice> existingInvoices, final boolean isDryRun, final boolean isRescheduled, final CallContext callContext, final InternalTenantContext internalTenantContext) {
+ log.debug("Invoking invoice plugins priorCall: targetDate='{}', isDryRun='{}', isRescheduled='{}'", targetDate, isDryRun, isRescheduled);
+ final Map<String, InvoicePluginApi> invoicePlugins = getInvoicePlugins(internalTenantContext);
if (invoicePlugins.isEmpty()) {
- return;
+ return null;
}
+ DateTime earliestRescheduleDate = null;
final InvoiceContext invoiceContext = new DefaultInvoiceContext(targetDate, null, existingInvoices, isDryRun, isRescheduled, callContext);
- for (final InvoicePluginApi invoicePlugin : invoicePlugins) {
- invoicePlugin.priorCall(invoiceContext, ImmutableList.<PluginProperty>of());
+ for (final String invoicePluginName : invoicePlugins.keySet()) {
+ final PriorInvoiceResult priorInvoiceResult = invoicePlugins.get(invoicePluginName).priorCall(invoiceContext, ImmutableList.<PluginProperty>of());
+ if (priorInvoiceResult.getRescheduleDate() != null &&
+ (earliestRescheduleDate == null || earliestRescheduleDate.compareTo(priorInvoiceResult.getRescheduleDate()) > 0)) {
+ earliestRescheduleDate = priorInvoiceResult.getRescheduleDate();
+ log.info("Invoice plugin {} rescheduled invoice generation to {} for targetDate {}", invoicePluginName, earliestRescheduleDate, targetDate);
+ }
+
+ if (priorInvoiceResult.isAborted()) {
+ log.info("Invoice plugin {} aborted invoice generation for targetDate {}", invoicePluginName, targetDate);
+ // TODO
+ }
}
+
+ return earliestRescheduleDate;
}
public void onSuccessCall(final LocalDate targetDate,
@@ -84,6 +102,7 @@ public class InvoicePluginDispatcher {
final boolean isRescheduled,
final CallContext callContext,
final InternalTenantContext internalTenantContext) {
+ log.debug("Invoking invoice plugins onSuccessCall: targetDate='{}', isDryRun='{}', isRescheduled='{}', invoice='{}'", targetDate, isDryRun, isRescheduled, invoice);
onCompletionCall(true, targetDate, invoice, existingInvoices, isDryRun, isRescheduled, callContext, internalTenantContext);
}
@@ -94,6 +113,7 @@ public class InvoicePluginDispatcher {
final boolean isRescheduled,
final CallContext callContext,
final InternalTenantContext internalTenantContext) {
+ log.debug("Invoking invoice plugins onFailureCall: targetDate='{}', isDryRun='{}', isRescheduled='{}', invoice='{}'", targetDate, isDryRun, isRescheduled, invoice);
onCompletionCall(false, targetDate, invoice, existingInvoices, isDryRun, isRescheduled, callContext, internalTenantContext);
}
@@ -105,7 +125,7 @@ public class InvoicePluginDispatcher {
final boolean isRescheduled,
final CallContext callContext,
final InternalTenantContext internalTenantContext) {
- final List<InvoicePluginApi> invoicePlugins = getInvoicePlugins(internalTenantContext);
+ final Collection<InvoicePluginApi> invoicePlugins = getInvoicePlugins(internalTenantContext).values();
if (invoicePlugins.isEmpty()) {
return;
}
@@ -128,9 +148,11 @@ public class InvoicePluginDispatcher {
// subsequent plugins should have access to items added by previous plugins
//
public List<InvoiceItem> getAdditionalInvoiceItems(final Invoice originalInvoice, final boolean isDryRun, final CallContext callContext, final InternalTenantContext tenantContext) throws InvoiceApiException {
+ log.debug("Invoking invoice plugins getAdditionalInvoiceItems: isDryRun='{}', originalInvoice='{}'", isDryRun, originalInvoice);
+
final List<InvoiceItem> additionalInvoiceItems = new LinkedList<InvoiceItem>();
- final List<InvoicePluginApi> invoicePlugins = getInvoicePlugins(tenantContext);
+ final Collection<InvoicePluginApi> invoicePlugins = getInvoicePlugins(tenantContext).values();
if (invoicePlugins.isEmpty()) {
return additionalInvoiceItems;
}
@@ -156,14 +178,13 @@ public class InvoicePluginDispatcher {
}
}
- private List<InvoicePluginApi> getInvoicePlugins(final InternalTenantContext tenantContext) {
-
+ private Map<String, InvoicePluginApi> getInvoicePlugins(final InternalTenantContext tenantContext) {
final Collection<String> resultingPluginList = getResultingPluginNameList(tenantContext);
- final List<InvoicePluginApi> invoicePlugins = new ArrayList<InvoicePluginApi>();
+ final Map<String, InvoicePluginApi> invoicePlugins = new HashMap<String, InvoicePluginApi>();
for (final String name : resultingPluginList) {
final InvoicePluginApi serviceForName = pluginRegistry.getServiceForName(name);
- invoicePlugins.add(serviceForName);
+ invoicePlugins.put(name, serviceForName);
}
return invoicePlugins;
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java
index afb7750..98eb563 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -107,7 +107,7 @@ public class InvoiceTagHandler extends RetryableService implements KillbillServi
private void processUnpaid_AUTO_INVOICING_OFF_invoices(final UUID accountId, final InternalCallContext context) {
try {
- dispatcher.processAccountFromNotificationOrBusEvent(accountId, null, null, context);
+ dispatcher.processAccountFromNotificationOrBusEvent(accountId, null, null, false, context);
} catch (final InvoiceApiException e) {
log.warn("Failed to process tag removal AUTO_INVOICING_OFF for accountId='{}'", accountId, e);
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
index 47dc673..98ee28a 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -94,9 +94,10 @@ public class DefaultNextBillingDateNotifier extends RetryableService implements
key.isDryRunForInvoiceNotification()) {
processEventForInvoiceNotification(firstSubscriptionId, targetDate, userToken, accountRecordId, tenantRecordId);
} else {
- processEventForInvoiceGeneration(firstSubscriptionId, targetDate, userToken, accountRecordId, tenantRecordId);
+ final boolean isRescheduled = key.isRescheduled() == Boolean.TRUE; // Handle null value (old versions < 0.19.7)
+ processEventForInvoiceGeneration(firstSubscriptionId, targetDate, isRescheduled, userToken, accountRecordId, tenantRecordId);
}
- } catch (SubscriptionBaseApiException e) {
+ } catch (final SubscriptionBaseApiException e) {
log.warn("Error retrieving subscriptionId='{}'", firstSubscriptionId, e);
}
}
@@ -127,8 +128,8 @@ public class DefaultNextBillingDateNotifier extends RetryableService implements
super.stop();
}
- private void processEventForInvoiceGeneration(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
- listener.handleNextBillingDateEvent(subscriptionId, eventDateTime, userToken, accountRecordId, tenantRecordId);
+ private void processEventForInvoiceGeneration(final UUID subscriptionId, final DateTime eventDateTime, final boolean isRescheduled, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+ listener.handleNextBillingDateEvent(subscriptionId, eventDateTime, isRescheduled, userToken, accountRecordId, tenantRecordId);
}
private void processEventForInvoiceNotification(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java
index 6cfcb83..92b816a 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDatePoster.java
@@ -35,7 +35,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
public class DefaultNextBillingDatePoster implements NextBillingDatePoster {
@@ -56,8 +55,9 @@ public class DefaultNextBillingDatePoster implements NextBillingDatePoster {
final UUID accountId,
final Iterable<UUID> subscriptionIds,
final DateTime futureNotificationTime,
+ final boolean isRescheduled,
final InternalCallContext internalCallContext) {
- insertNextBillingFromTransactionInternal(entitySqlDaoWrapperFactory, subscriptionIds, Boolean.FALSE, futureNotificationTime, futureNotificationTime, internalCallContext);
+ insertNextBillingFromTransactionInternal(entitySqlDaoWrapperFactory, subscriptionIds, Boolean.FALSE, isRescheduled, futureNotificationTime, futureNotificationTime, internalCallContext);
}
@Override
@@ -67,12 +67,13 @@ public class DefaultNextBillingDatePoster implements NextBillingDatePoster {
final DateTime futureNotificationTime,
final DateTime targetDate,
final InternalCallContext internalCallContext) {
- insertNextBillingFromTransactionInternal(entitySqlDaoWrapperFactory, subscriptionIds, Boolean.TRUE, futureNotificationTime, targetDate, internalCallContext);
+ insertNextBillingFromTransactionInternal(entitySqlDaoWrapperFactory, subscriptionIds, Boolean.TRUE, null, futureNotificationTime, targetDate, internalCallContext);
}
private void insertNextBillingFromTransactionInternal(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory,
final Iterable<UUID> subscriptionIds,
final Boolean isDryRunForInvoiceNotification,
+ final Boolean isRescheduled,
final DateTime futureNotificationTime,
final DateTime targetDate,
final InternalCallContext internalCallContext) {
@@ -111,7 +112,7 @@ public class DefaultNextBillingDatePoster implements NextBillingDatePoster {
if (existingNotificationForEffectiveDate == null) {
log.info("Queuing next billing date notification at {} for subscriptionId {}", futureNotificationTime.toString(), JOINER.join(subscriptionIds));
- final NextBillingDateNotificationKey newNotificationEvent = new NextBillingDateNotificationKey(null, subscriptionIds, targetDate, isDryRunForInvoiceNotification);
+ final NextBillingDateNotificationKey newNotificationEvent = new NextBillingDateNotificationKey(null, subscriptionIds, targetDate, isDryRunForInvoiceNotification, isRescheduled);
nextBillingQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory.getHandle().getConnection(), futureNotificationTime,
newNotificationEvent, internalCallContext.getUserToken(),
internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDateNotificationKey.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDateNotificationKey.java
index 1b64c60..4f23d1d 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDateNotificationKey.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDateNotificationKey.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you 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:
*
@@ -29,27 +31,31 @@ import com.google.common.collect.Iterables;
public class NextBillingDateNotificationKey extends DefaultUUIDNotificationKey {
- private Boolean isDryRunForInvoiceNotification;
- private DateTime targetDate;
+ private final Boolean isDryRunForInvoiceNotification;
+ private final Boolean isRescheduled;
+ private final DateTime targetDate;
private final Iterable<UUID> uuidKeys;
@JsonCreator
public NextBillingDateNotificationKey(@Deprecated @JsonProperty("uuidKey") final UUID uuidKey,
@JsonProperty("uuidKeys") final Iterable<UUID> uuidKeys,
@JsonProperty("targetDate") final DateTime targetDate,
- @JsonProperty("isDryRunForInvoiceNotification") final Boolean isDryRunForInvoiceNotification) {
+ @JsonProperty("isDryRunForInvoiceNotification") final Boolean isDryRunForInvoiceNotification,
+ @JsonProperty("isRescheduled") final Boolean isRescheduled) {
super(uuidKey);
this.uuidKeys = uuidKeys;
this.targetDate = targetDate;
this.isDryRunForInvoiceNotification = isDryRunForInvoiceNotification;
+ this.isRescheduled = isRescheduled;
}
- public NextBillingDateNotificationKey(NextBillingDateNotificationKey existing,
+ public NextBillingDateNotificationKey(final NextBillingDateNotificationKey existing,
final Iterable<UUID> newUUIDKeys) {
super(null);
this.uuidKeys = ImmutableSet.copyOf(Iterables.concat(existing.getUuidKeys(), newUUIDKeys));
this.targetDate = existing.getTargetDate();
this.isDryRunForInvoiceNotification = existing.isDryRunForInvoiceNotification();
+ this.isRescheduled = existing.isRescheduled();
}
@JsonProperty("isDryRunForInvoiceNotification")
@@ -57,6 +63,11 @@ public class NextBillingDateNotificationKey extends DefaultUUIDNotificationKey {
return isDryRunForInvoiceNotification;
}
+ @JsonProperty("isRescheduled")
+ public Boolean isRescheduled() {
+ return isRescheduled;
+ }
+
public DateTime getTargetDate() {
return targetDate;
}
@@ -69,4 +80,51 @@ public class NextBillingDateNotificationKey extends DefaultUUIDNotificationKey {
return uuidKeys;
}
}
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("NextBillingDateNotificationKey{");
+ sb.append("isDryRunForInvoiceNotification=").append(isDryRunForInvoiceNotification);
+ sb.append(", isRescheduled=").append(isRescheduled);
+ sb.append(", targetDate=").append(targetDate);
+ sb.append(", uuidKeys=").append(uuidKeys);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+
+ final NextBillingDateNotificationKey that = (NextBillingDateNotificationKey) o;
+
+ if (isDryRunForInvoiceNotification != null ? !isDryRunForInvoiceNotification.equals(that.isDryRunForInvoiceNotification) : that.isDryRunForInvoiceNotification != null) {
+ return false;
+ }
+ if (isRescheduled != null ? !isRescheduled.equals(that.isRescheduled) : that.isRescheduled != null) {
+ return false;
+ }
+ if (targetDate != null ? targetDate.compareTo(that.targetDate) != 0 : that.targetDate != null) {
+ return false;
+ }
+ return uuidKeys != null ? uuidKeys.equals(that.uuidKeys) : that.uuidKeys == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + (isDryRunForInvoiceNotification != null ? isDryRunForInvoiceNotification.hashCode() : 0);
+ result = 31 * result + (isRescheduled != null ? isRescheduled.hashCode() : 0);
+ result = 31 * result + (targetDate != null ? targetDate.hashCode() : 0);
+ result = 31 * result + (uuidKeys != null ? uuidKeys.hashCode() : 0);
+ return result;
+ }
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java
index d2dce63..f4b4a03 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/NextBillingDatePoster.java
@@ -27,7 +27,7 @@ import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
public interface NextBillingDatePoster {
void insertNextBillingNotificationFromTransaction(EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, UUID accountId,
- Iterable<UUID> subscriptionId, DateTime futureNotificationTime, InternalCallContext internalCallContext);
+ Iterable<UUID> subscriptionId, DateTime futureNotificationTime, final boolean isRescheduled, InternalCallContext internalCallContext);
void insertNextBillingDryRunNotificationFromTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final UUID accountId,
final Iterable<UUID> subscriptionId, final DateTime futureNotificationTime, final DateTime targetDate, final InternalCallContext internalCallContext);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotificationKey.java b/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotificationKey.java
index b837bdf..0e6e941 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotificationKey.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotificationKey.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -38,7 +38,7 @@ public class TestNextBillingDateNotificationKey {
final DateTime targetDate = new DateTime();
final Boolean isDryRunForInvoiceNotification = Boolean.FALSE;
- final NextBillingDateNotificationKey key = new NextBillingDateNotificationKey(uuidKey, null, targetDate, isDryRunForInvoiceNotification);
+ final NextBillingDateNotificationKey key = new NextBillingDateNotificationKey(uuidKey, null, targetDate, isDryRunForInvoiceNotification, false);
final String json = mapper.writeValueAsString(key);
final NextBillingDateNotificationKey result = mapper.readValue(json, NextBillingDateNotificationKey.class);
@@ -56,7 +56,7 @@ public class TestNextBillingDateNotificationKey {
final DateTime targetDate = new DateTime();
final Boolean isDryRunForInvoiceNotification = Boolean.FALSE;
- final NextBillingDateNotificationKey key = new NextBillingDateNotificationKey(null, ImmutableList.of(uuidKey1, uuidKey2), targetDate, isDryRunForInvoiceNotification);
+ final NextBillingDateNotificationKey key = new NextBillingDateNotificationKey(null, ImmutableList.of(uuidKey1, uuidKey2), targetDate, isDryRunForInvoiceNotification, false);
final String json = mapper.writeValueAsString(key);
final NextBillingDateNotificationKey result = mapper.readValue(json, NextBillingDateNotificationKey.class);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotifier.java b/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotifier.java
index b620fab..fe11d11 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotifier.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/notification/TestNextBillingDateNotifier.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -49,7 +49,7 @@ public class TestNextBillingDateNotifier extends InvoiceTestSuiteWithEmbeddedDB
final NotificationQueue nextBillingQueue = notificationQueueService.getNotificationQueue(DefaultInvoiceService.INVOICE_SERVICE_NAME, DefaultNextBillingDateNotifier.NEXT_BILLING_DATE_NOTIFIER_QUEUE);
- nextBillingQueue.recordFutureNotification(now, new NextBillingDateNotificationKey(null, ImmutableList.<UUID>of(subscriptionId), now, Boolean.FALSE), internalCallContext.getUserToken(), accountRecordId, internalCallContext.getTenantRecordId());
+ nextBillingQueue.recordFutureNotification(now, new NextBillingDateNotificationKey(null, ImmutableList.<UUID>of(subscriptionId), now, Boolean.FALSE, Boolean.FALSE), internalCallContext.getUserToken(), accountRecordId, internalCallContext.getTenantRecordId());
// Move time in the future after the notification effectiveDate
clock.setDeltaFromReality(3000);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
index ea9001c..c4db83f 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -104,21 +104,21 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
internalCallContextFactory, invoicePluginDispatcher, locker, busService.getBus(),
notificationQueueService, invoiceConfig, clock, parkedAccountsManager);
- Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
+ Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.assertNotNull(invoice);
List<InvoiceModelDao> invoices = invoiceDao.getInvoicesByAccount(false, context);
Assert.assertEquals(invoices.size(), 0);
// Try it again to double check
- invoice = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
+ invoice = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.assertNotNull(invoice);
invoices = invoiceDao.getInvoicesByAccount(false, context);
Assert.assertEquals(invoices.size(), 0);
// This time no dry run
- invoice = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, context);
+ invoice = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, false, context);
Assert.assertNotNull(invoice);
invoices = invoiceDao.getInvoicesByAccount(false, context);
@@ -194,7 +194,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(invoiceModelDao), context);
try {
- dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
+ dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.fail();
} catch (final InvoiceApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
@@ -205,7 +205,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
Assert.assertTrue(tagUserApi.getTagsForAccount(accountId, true, callContext).isEmpty());
try {
- dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, context);
+ dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, false, context);
Assert.fail();
} catch (final InvoiceApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
@@ -218,12 +218,12 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
Assert.assertEquals(tags.get(0).getTagDefinitionId(), SystemTags.PARK_TAG_DEFINITION_ID);
// isApiCall=false
- final Invoice nullInvoice1 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, context);
+ final Invoice nullInvoice1 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, false, context);
Assert.assertNull(nullInvoice1);
// No dry-run and isApiCall=true
try {
- dispatcher.processAccount(true, accountId, target, null, context);
+ dispatcher.processAccount(true, accountId, target, null, false, context);
Assert.fail();
} catch (final InvoiceApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
@@ -244,18 +244,18 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
});
// Dry-run and isApiCall=false: still parked
- final Invoice nullInvoice2 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
+ final Invoice nullInvoice2 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.assertNull(nullInvoice2);
// Dry-run and isApiCall=true: call goes through
- final Invoice invoice1 = dispatcher.processAccount(true, accountId, target, new DryRunFutureDateArguments(), context);
+ final Invoice invoice1 = dispatcher.processAccount(true, accountId, target, new DryRunFutureDateArguments(), false, context);
Assert.assertNotNull(invoice1);
Assert.assertEquals(invoiceDao.getInvoicesByAccount(false, context).size(), 0);
// Dry-run: still parked
Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, false, callContext).size(), 1);
// No dry-run and isApiCall=true: call goes through
- final Invoice invoice2 = dispatcher.processAccount(true, accountId, target, null, context);
+ final Invoice invoice2 = dispatcher.processAccount(true, accountId, target, null, false, context);
Assert.assertNotNull(invoice2);
Assert.assertEquals(invoiceDao.getInvoicesByAccount(false, context).size(), 1);
// No dry-run: now unparked
@@ -293,7 +293,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
internalCallContextFactory, invoicePluginDispatcher, locker, busService.getBus(),
notificationQueueService, invoiceConfig, clock, parkedAccountsManager);
- final Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(account.getId(), new LocalDate("2012-07-30"), null, context);
+ final Invoice invoice = dispatcher.processAccountFromNotificationOrBusEvent(account.getId(), new LocalDate("2012-07-30"), null, false, context);
Assert.assertNotNull(invoice);
final List<InvoiceItem> invoiceItems = invoice.getInvoiceItems();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index f5e9bd1..30d07e7 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -238,7 +238,7 @@ public class TestInvoiceHelper {
invoiceDao, internalCallContextFactory, invoicePluginDispatcher, locker, busService.getBus(),
notificationQueueService, invoiceConfig, clock, parkedAccountsManager);
- return dispatcher.processAccountFromNotificationOrBusEvent(accountId, targetDate, dryRunArguments, internalCallContext);
+ return dispatcher.processAccountFromNotificationOrBusEvent(accountId, targetDate, dryRunArguments, false, internalCallContext);
}
public SubscriptionBase createSubscription() throws SubscriptionBaseApiException {
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
index ef72b84..3d8a454 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you 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:
*
@@ -21,17 +23,16 @@ import java.util.UUID;
import javax.inject.Inject;
import org.joda.time.DateTime;
-
import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.invoice.api.InvoiceInternalApi;
-import org.killbill.clock.Clock;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.clock.Clock;
import org.killbill.notificationq.api.NotificationQueueService;
public class TestInvoiceNotificationQListener extends InvoiceListener {
- int eventCount = 0;
- UUID latestSubscriptionId = null;
+ private int eventCount = 0;
+ private UUID latestSubscriptionId = null;
@Inject
public TestInvoiceNotificationQListener(final AccountInternalApi accountApi,
@@ -44,7 +45,7 @@ public class TestInvoiceNotificationQListener extends InvoiceListener {
}
@Override
- public void handleNextBillingDateEvent(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+ public void handleNextBillingDateEvent(final UUID subscriptionId, final DateTime eventDateTime, final boolean isRescheduled, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
eventCount++;
latestSubscriptionId = subscriptionId;
}
@@ -56,5 +57,4 @@ public class TestInvoiceNotificationQListener extends InvoiceListener {
public UUID getLatestSubscriptionId() {
return latestSubscriptionId;
}
-
}