killbill-uncached
Changes
invoice/pom.xml 5(+5 -0)
invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java 99(+85 -14)
invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousInArrearUsageInterval.java 211(+211 -0)
invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java 166(+166 -0)
invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java 70(+35 -35)
Details
diff --git a/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java b/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java
index ed46527..e782366 100644
--- a/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java
+++ b/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java
@@ -18,11 +18,11 @@ package org.killbill.billing.glue;
public interface InvoiceModule {
- public abstract void installInvoiceUserApi();
+ public void installInvoiceUserApi();
- public abstract void installInvoicePaymentApi();
+ public void installInvoicePaymentApi();
- public abstract void installInvoiceMigrationApi();
+ public void installInvoiceMigrationApi();
- public abstract void installInvoiceInternalApi();
+ public void installInvoiceInternalApi();
}
diff --git a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
index e75e6ce..cfc0ea4 100644
--- a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
+++ b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
@@ -17,6 +17,7 @@
package org.killbill.billing.junction;
import java.math.BigDecimal;
+import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@@ -27,6 +28,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.Usage;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
import org.killbill.billing.subscription.api.SubscriptionBase;
@@ -105,7 +107,13 @@ public interface BillingEvent extends Comparable<BillingEvent> {
public Long getTotalOrdering();
/**
- * @return The TimeZone of the account
+ * @return the TimeZone of the account
*/
public DateTimeZone getTimeZone();
+
+ /**
+ *
+ * @return the list of {@code Usage} section
+ */
+ public List<Usage> getUsages();
}
invoice/pom.xml 5(+5 -0)
diff --git a/invoice/pom.xml b/invoice/pom.xml
index 8f29a64..dd3b8a2 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -94,6 +94,11 @@
</dependency>
<dependency>
<groupId>org.kill-bill.billing</groupId>
+ <artifactId>killbill-usage</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.kill-bill.billing</groupId>
<artifactId>killbill-util</artifactId>
</dependency>
<dependency>
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
index 14ffe3f..472b796 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
@@ -60,6 +60,7 @@ public abstract class InvoiceCalculatorUtils {
public static boolean isCharge(final InvoiceItem invoiceItem) {
return InvoiceItemType.EXTERNAL_CHARGE.equals(invoiceItem.getInvoiceItemType()) ||
InvoiceItemType.FIXED.equals(invoiceItem.getInvoiceItemType()) ||
+ InvoiceItemType.USAGE.equals(invoiceItem.getInvoiceItemType()) ||
InvoiceItemType.RECURRING.equals(invoiceItem.getInvoiceItemType());
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
index 5818562..3a57387 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -18,6 +18,7 @@ package org.killbill.billing.invoice.generator;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
@@ -26,18 +27,17 @@ import javax.annotation.Nullable;
import org.joda.time.LocalDate;
import org.joda.time.Months;
-import org.killbill.billing.catalog.api.BillingMode;
-import org.killbill.billing.invoice.model.BillingModeGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.BillingMode;
import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Currency;
-import org.killbill.clock.Clock;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.model.BillingModeGenerator;
import org.killbill.billing.invoice.model.DefaultInvoice;
import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
import org.killbill.billing.invoice.model.InAdvanceBillingMode;
@@ -45,11 +45,21 @@ import org.killbill.billing.invoice.model.InvalidDateSequenceException;
import org.killbill.billing.invoice.model.RecurringInvoiceItem;
import org.killbill.billing.invoice.model.RecurringInvoiceItemData;
import org.killbill.billing.invoice.tree.AccountItemTree;
+import org.killbill.billing.invoice.usage.SubscriptionConsumableInArrear;
import org.killbill.billing.junction.BillingEvent;
import org.killbill.billing.junction.BillingEventSet;
+import org.killbill.billing.usage.api.UsageUserApi;
import org.killbill.billing.util.config.InvoiceConfig;
import org.killbill.billing.util.currency.KillBillMoney;
+import org.killbill.clock.Clock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.inject.Inject;
public class DefaultInvoiceGenerator implements InvoiceGenerator {
@@ -58,11 +68,13 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
private final Clock clock;
private final InvoiceConfig config;
+ private final UsageUserApi usageApi;
@Inject
- public DefaultInvoiceGenerator(final Clock clock, final InvoiceConfig config) {
+ public DefaultInvoiceGenerator(final Clock clock, final UsageUserApi usageApi, final InvoiceConfig config) {
this.clock = clock;
this.config = config;
+ this.usageApi = usageApi;
}
/*
@@ -72,7 +84,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
public Invoice generateInvoice(final UUID accountId, @Nullable final BillingEventSet events,
@Nullable final List<Invoice> existingInvoices,
final LocalDate targetDate,
- final Currency targetCurrency) throws InvoiceApiException {
+ final Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException {
if ((events == null) || (events.size() == 0) || events.isAccountAutoInvoiceOff()) {
return null;
}
@@ -86,19 +98,78 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
final List<InvoiceItem> inAdvanceItems = generateInAdvanceInvoiceItems(accountId, invoiceId, events, existingInvoices, adjustedTargetDate, targetCurrency);
invoice.addInvoiceItems(inAdvanceItems);
+ final List<InvoiceItem> usageItems = generateUsageInvoiceItems(invoiceId, events, existingInvoices, targetDate, context);
+ invoice.addInvoiceItems(usageItems);
+
return inAdvanceItems.size() != 0 ? invoice : null;
}
- private List<InvoiceItem> generateInAdvanceInvoiceItems(final UUID accountId, final UUID invoiceId, @Nullable final BillingEventSet events,
- @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
- final Currency targetCurrency) throws InvoiceApiException {
+ // STEPH_USAGE Only deals with consumable in arrear usage billing.
+ private List<InvoiceItem> generateUsageInvoiceItems(final UUID invoiceId, final BillingEventSet eventSet,
+ @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
+ final InternalCallContext context) throws InvoiceApiException {
+
+ try {
+
+ final List<InvoiceItem> items = Lists.newArrayList();
+ final Iterator<BillingEvent> events = eventSet.iterator();
+
+ final List<BillingEvent> curEvents = Lists.newArrayList();
+ UUID curSubscriptionId = null;
+ while (events.hasNext()) {
+ final BillingEvent event = events.next();
+ final UUID subscriptionId = event.getSubscription().getId();
+ if (curSubscriptionId != null && !curSubscriptionId.equals(subscriptionId)) {
+ //
+ // STEPH_USAGE unitType issue
+ // STEPH_USAGE context needs tenantId , hum...
+ final UUID tenantId = UUID.randomUUID();
+ SubscriptionConsumableInArrear foo = new SubscriptionConsumableInArrear(invoiceId, "foo", curEvents, usageApi, targetDate, context.toTenantContext(tenantId));
+ items.addAll(foo.computeMissingUsageInvoiceItems(extractUsageItemsForSubscription(subscriptionId, existingInvoices)));
+ curEvents.clear();
+ }
+ curSubscriptionId = subscriptionId;
+ curEvents.add(event);
+ }
+
+ return items;
+
+ } catch (CatalogApiException e) {
+ throw new InvoiceApiException(e);
+ }
+ }
+
+ private List<InvoiceItem> extractUsageItemsForSubscription(final UUID subscriptionId, @Nullable final List<Invoice> existingInvoices) {
+
+ if (existingInvoices == null) {
+ return Collections.emptyList();
+ }
+
+ final Iterable usageItems = Iterables.concat(Iterables.transform(existingInvoices, new Function<Invoice, Iterable<InvoiceItem>>() {
+ @Override
+ public Iterable<InvoiceItem> apply(final Invoice input) {
+
+ return Iterables.filter(input.getInvoiceItems(), new Predicate<InvoiceItem>() {
+ @Override
+ public boolean apply(final InvoiceItem input) {
+ return input.getInvoiceItemType() == InvoiceItemType.USAGE && input.getSubscriptionId().equals(subscriptionId);
+ }
+ });
+ }
+ }));
+ return ImmutableList.<InvoiceItem>copyOf(usageItems);
+ }
+
+ private List<InvoiceItem> generateInAdvanceInvoiceItems(final UUID accountId, final UUID invoiceId, final BillingEventSet eventSet,
+ @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
+ final Currency targetCurrency) throws InvoiceApiException {
final AccountItemTree accountItemTree = new AccountItemTree(accountId);
if (existingInvoices != null) {
for (final Invoice invoice : existingInvoices) {
for (final InvoiceItem item : invoice.getInvoiceItems()) {
if (item.getSubscriptionId() == null || // Always include migration invoices, credits, external charges etc.
- !events.getSubscriptionIdsWithAutoInvoiceOff()
- .contains(item.getSubscriptionId())) { //don't add items with auto_invoice_off tag
+ !eventSet.getSubscriptionIdsWithAutoInvoiceOff()
+ .contains(item.getSubscriptionId())) { //don't add items with auto_invoice_off tag
accountItemTree.addExistingItem(item);
}
}
@@ -106,7 +177,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
}
// Generate list of proposed invoice items based on billing events from junction-- proposed items are ALL items since beginning of time
- final List<InvoiceItem> proposedItems = generateInAdvanceInvoiceItems(invoiceId, accountId, events, targetDate, targetCurrency);
+ final List<InvoiceItem> proposedItems = generateInAdvanceInvoiceItems(invoiceId, accountId, eventSet, targetDate, targetCurrency);
accountItemTree.mergeWithProposedItems(proposedItems);
return accountItemTree.getResultingItemList();
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
index 014dbcd..e0d6b21 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
@@ -23,6 +23,7 @@ import javax.annotation.Nullable;
import org.joda.time.LocalDate;
+import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
@@ -31,5 +32,5 @@ import org.killbill.billing.junction.BillingEventSet;
public interface InvoiceGenerator {
public Invoice generateInvoice(UUID accountId, @Nullable BillingEventSet events, @Nullable List<Invoice> existingInvoices,
- LocalDate targetDate, Currency targetCurrency) throws InvoiceApiException;
+ LocalDate targetDate, Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException;
}
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 66c6efb..1dba77c 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -190,7 +190,7 @@ public class InvoiceDispatcher {
final Currency targetCurrency = account.getCurrency();
final LocalDate targetDate = dateAndTimeZoneContext != null ? dateAndTimeZoneContext.computeTargetDate(targetDateTime) : null;
- final Invoice invoice = targetDate != null ? generator.generateInvoice(accountId, billingEvents, invoices, targetDate, targetCurrency) : null;
+ final Invoice invoice = targetDate != null ? generator.generateInvoice(accountId, billingEvents, invoices, targetDate, targetCurrency, context) : null;
boolean isRealInvoiceWithItems = false;
if (invoice == null) {
log.info("Generated null invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
index 46538b3..de3bf99 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
@@ -78,6 +78,10 @@ public class InvoiceItemFactory {
case ITEM_ADJ:
item = new ItemAdjInvoiceItem(id, createdDate, invoiceId, accountId, startDate, amount, currency, linkedItemId);
break;
+ case USAGE:
+ // STEPH USAGE should we add unitType in schema pr override fields (planName,..) Same for unitAmount
+ item = new UsageInvoiceItem(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency,"unitType");
+ break;
default:
throw new RuntimeException("Unexpected type of event item " + type);
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/UsageInvoiceItem.java b/invoice/src/main/java/org/killbill/billing/invoice/model/UsageInvoiceItem.java
new file mode 100644
index 0000000..9b6489e
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/UsageInvoiceItem.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 The Billing Project, Inc.
+ *
+ * Ning 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:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.model;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+
+public class UsageInvoiceItem extends InvoiceItemBase {
+
+ private final String unitType;
+
+ public UsageInvoiceItem(final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId, @Nullable final UUID subscriptionId,
+ final String planName, final String phaseName,
+ final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final Currency currency, final String unitType) {
+ this(UUID.randomUUID(), null, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, unitType);
+ }
+
+ public UsageInvoiceItem(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, final UUID bundleId,
+ final UUID subscriptionId, final String planName, final String phaseName,
+ final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final Currency currency, final String unitType) {
+ super(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+ this.unitType = unitType;
+ }
+
+ @Override
+ public InvoiceItemType getInvoiceItemType() {
+ return InvoiceItemType.USAGE;
+ }
+
+ @Override
+ public String getDescription() {
+ return String.format("%s (usage item)", unitType);
+ }
+
+ public String getUnitType() {
+ return unitType;
+ }
+}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java b/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
index 57c6bb1..be44a10 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
@@ -97,6 +97,7 @@ public class AccountItemTree {
case CBA_ADJ:
case CREDIT_ADJ:
case REFUND_ADJ:
+ case USAGE:
return;
case RECURRING:
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousInArrearUsageInterval.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousInArrearUsageInterval.java
new file mode 100644
index 0000000..405306e
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousInArrearUsageInterval.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2014 The Billing Project, Inc.
+ *
+ * Ning 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:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.usage;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.TieredBlock;
+import org.killbill.billing.catalog.api.Usage;
+import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.generator.BillingIntervalDetail;
+import org.killbill.billing.invoice.model.UsageInvoiceItem;
+import org.killbill.billing.junction.BillingEvent;
+import org.killbill.billing.usage.api.RolledUpUsage;
+import org.killbill.billing.usage.api.UsageUserApi;
+import org.killbill.billing.util.callcontext.TenantContext;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import static org.killbill.billing.invoice.usage.SubscriptionConsumableInArrear.getTieredBlocks;
+import static org.killbill.billing.invoice.usage.SubscriptionConsumableInArrear.localDateToEndOfDayInAccountTimezone;
+
+public class ContiguousInArrearUsageInterval {
+
+ private final List<LocalDate> transitionTimes;
+ private final List<BillingEvent> billingEvents;
+
+ private final Usage usage;
+ private final String unitType;
+ private final UsageUserApi usageApi;
+ private final LocalDate targetDate;
+ private final UUID invoiceId;
+ private final TenantContext context;
+
+ public ContiguousInArrearUsageInterval(final Usage usage, final UUID invoiceId, final String unitType, final UsageUserApi usageApi, final LocalDate targetDate, final TenantContext context) {
+ this.usage = usage;
+ this.invoiceId = invoiceId;
+ this.unitType = unitType;
+ this.usageApi = usageApi;
+ this.targetDate = targetDate;
+ this.context = context;
+ this.billingEvents = Lists.newLinkedList();
+ this.transitionTimes = Lists.newLinkedList();
+ }
+
+ public void addBillingEvent(final BillingEvent event) {
+ billingEvents.add(event);
+ }
+
+ public Usage getUsage() {
+ return usage;
+ }
+
+ public int getBCD() {
+ return billingEvents.get(0).getBillCycleDayLocal();
+ }
+
+ public UUID getAccountId() {
+ return billingEvents.get(0).getAccount().getId();
+ }
+
+ public UUID getBundleId() {
+ return billingEvents.get(0).getSubscription().getBundleId();
+ }
+
+ public UUID getSubscriptionId() {
+ return billingEvents.get(0).getSubscription().getId();
+ }
+
+ // STEPH_USAGE planName/phaseName,BCD,... might not be correct if we changed plan but Usage section was exactly similar
+ public String getPlanName() {
+ return billingEvents.get(0).getPlan().getName();
+ }
+
+ public String getPhaseName() {
+ return billingEvents.get(0).getPlanPhase().getName();
+ }
+
+ public Currency getCurrency() {
+ return billingEvents.get(0).getCurrency();
+ }
+
+ public DateTimeZone getAccountTimeZone() {
+ return billingEvents.get(0).getTimeZone();
+ }
+
+
+
+ public ContiguousInArrearUsageInterval build(final boolean closedInterval) {
+
+ Preconditions.checkState((!closedInterval && billingEvents.size() >= 1) ||
+ (closedInterval && billingEvents.size() >= 2));
+
+ final LocalDate startDate = new LocalDate(billingEvents.get(0).getEffectiveDate(), getAccountTimeZone());
+ if (targetDate.isBefore(startDate)) {
+ return this;
+ }
+
+ final LocalDate endDate = closedInterval ? new LocalDate(billingEvents.get(billingEvents.size() - 1), getAccountTimeZone()) : targetDate;
+
+ final BillingIntervalDetail bid = new BillingIntervalDetail(startDate, endDate, targetDate, getBCD(), usage.getBillingPeriod());
+
+ int numberOfPeriod = 0;
+ // First billingCycleDate prior startDate
+ LocalDate nextBillCycleDate = bid.getFutureBillingDateFor(numberOfPeriod);
+ transitionTimes.add(startDate);
+ while (!nextBillCycleDate.isAfter(endDate)) {
+ if (nextBillCycleDate.isAfter(startDate)) {
+ transitionTimes.add(nextBillCycleDate);
+ }
+ numberOfPeriod++;
+ nextBillCycleDate = bid.getFutureBillingDateFor(numberOfPeriod);
+ }
+ return this;
+ }
+
+ public List<InvoiceItem> computeMissingItems(final List<InvoiceItem> existingUsage) throws CatalogApiException {
+
+ final List<InvoiceItem> result = Lists.newLinkedList();
+
+ final List<RolledUpUsage> rolledUpUsages = getRolledUpUsage();
+ for (RolledUpUsage ru : rolledUpUsages) {
+ final LocalDate startRolledUpDate = new LocalDate(ru.getStartTime(), getAccountTimeZone());
+ final LocalDate endRolledUpDate = new LocalDate(ru.getEndTime(), getAccountTimeZone());
+ final BigDecimal billedUsage = computeBilledUsage(startRolledUpDate, endRolledUpDate, existingUsage);
+ final BigDecimal toBeBilledUsage = computeToBeBilledUsage(ru.getAmount());
+ if (billedUsage.compareTo(toBeBilledUsage) < 0) {
+ InvoiceItem item = new UsageInvoiceItem(invoiceId, getAccountId(), getBundleId(), getSubscriptionId(), getPlanName(),
+ getPhaseName(), startRolledUpDate, endRolledUpDate, toBeBilledUsage.subtract(billedUsage), getCurrency(), unitType);
+ result.add(item);
+ }
+ }
+ return result;
+ }
+
+ private List<RolledUpUsage> getRolledUpUsage() {
+
+ final Iterable<DateTime> transitions = Iterables.transform(transitionTimes, new Function<LocalDate, DateTime>() {
+ @Override
+ public DateTime apply(final LocalDate input) {
+ return localDateToEndOfDayInAccountTimezone(input, getAccountTimeZone());
+ }
+ });
+ final List<RolledUpUsage> usagesForInterval = usageApi.getAllUsageForSubscription(getSubscriptionId(), unitType, ImmutableList.copyOf(transitions), context);
+ return usagesForInterval;
+ }
+
+ private final BigDecimal computeToBeBilledUsage(final BigDecimal units) throws CatalogApiException {
+
+ // STEPH_USAGE need to review catalog xml which defines block tiers, ...
+ final int blockSize = 0x1000;
+ final int nbBlocks = units.intValue() / blockSize + ((units.intValue() % blockSize == 0) ? 0 : 1);
+
+ // STEPH_USAGE this is wrong should use from each tier.
+ final List<TieredBlock> tieredBlocks = getTieredBlocks(usage, unitType);
+ for (TieredBlock tier : tieredBlocks) {
+ if (tier.getMax() >= units.doubleValue()) {
+ return tier.getPrice().getPrice(getCurrency());
+ }
+ }
+ // Return from last tier
+ return tieredBlocks.get(tieredBlocks.size() - 1).getPrice().getPrice(getCurrency());
+ }
+
+ private final BigDecimal computeBilledUsage(final LocalDate startDate, final LocalDate endDate, final List<InvoiceItem> existingUsage) {
+ final Iterable<InvoiceItem> filteredUsageForInterval = Iterables.filter(existingUsage, new Predicate<InvoiceItem>() {
+ @Override
+ public boolean apply(final InvoiceItem input) {
+ // STEPH_USAGE what happens if we discover usage period that overlap (one side or both side) the [startDate, endDate] interval
+ // STEPH_USAGE how to distinguish different usage charges (maybe different sections.) (needs to at least of the unitType in usage element
+ return input.getInvoiceItemType() == InvoiceItemType.USAGE &&
+ input.getStartDate().compareTo(startDate) >= 0 &&
+ input.getEndDate().compareTo(endDate) <= 0;
+ }
+ });
+
+ final BigDecimal billedAmount = BigDecimal.ZERO;
+ for (InvoiceItem ii : filteredUsageForInterval) {
+ billedAmount.add(ii.getAmount());
+ }
+ // Return the billed $ amount (not the # of units)
+ return billedAmount;
+ }
+
+}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
new file mode 100644
index 0000000..14f932a
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2014 The Billing Project, Inc.
+ *
+ * Ning 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:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.usage;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Tier;
+import org.killbill.billing.catalog.api.TieredBlock;
+import org.killbill.billing.catalog.api.Usage;
+import org.killbill.billing.catalog.api.UsageType;
+import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.model.UsageInvoiceItem;
+import org.killbill.billing.junction.BillingEvent;
+import org.killbill.billing.usage.api.UsageUserApi;
+import org.killbill.billing.util.callcontext.TenantContext;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class SubscriptionConsumableInArrear {
+
+ private UUID invoiceId;
+ private final String unitType;
+ private final List<BillingEvent> subscriptionBillingEvents;
+ private final UsageUserApi usageApi;
+ private final LocalDate targetDate;
+ private final TenantContext context;
+
+ public SubscriptionConsumableInArrear(final UUID invoiceId, final String unitType, final List<BillingEvent> subscriptionBillingEvents, final UsageUserApi usageApi, final LocalDate targetDate, final TenantContext context) {
+ this.invoiceId = invoiceId;
+ this.unitType = unitType;
+ this.subscriptionBillingEvents = subscriptionBillingEvents;
+ this.usageApi = usageApi;
+ this.targetDate = targetDate;
+ this.context = context;
+ }
+
+ public List<InvoiceItem> computeMissingUsageInvoiceItems(final List<InvoiceItem> existingUsage) throws CatalogApiException {
+
+ final List<InvoiceItem> result = Lists.newLinkedList();
+ final List<ContiguousInArrearUsageInterval> billingEventTransitionTimePeriods = computeBillingEventTransitionTimePeriods();
+ for (ContiguousInArrearUsageInterval usageInterval : billingEventTransitionTimePeriods) {
+ result.addAll(usageInterval.computeMissingItems(existingUsage));
+ }
+ return result;
+ }
+
+
+ static List<TieredBlock> getTieredBlocks(final Usage usage, final String unitType) {
+
+ Preconditions.checkArgument(usage.getTiers().length > 0);
+
+ final List<TieredBlock> result = Lists.newLinkedList();
+ for (Tier tier : usage.getTiers()) {
+
+ for (TieredBlock tierBlock : tier.getTieredBlocks()) {
+ if (tierBlock.getUnit().getName().equals(unitType)) {
+ result.add(tierBlock);
+ }
+ }
+ }
+ return result;
+ }
+
+ static DateTime localDateToEndOfDayInAccountTimezone(final LocalDate input, final DateTimeZone accountTimeZone) {
+ final DateTime dateTimeInAccountTimeZone = new DateTime(input.getYear(), input.getMonthOfYear(), input.getDayOfMonth(), 23, 59, 59, accountTimeZone);
+ return new DateTime(dateTimeInAccountTimeZone, DateTimeZone.UTC);
+ }
+
+
+ private List<ContiguousInArrearUsageInterval> computeBillingEventTransitionTimePeriods() {
+
+ final List<ContiguousInArrearUsageInterval> usageInterval = Lists.newLinkedList();
+
+ ContiguousInArrearUsageInterval existingInterval = null;
+ for (BillingEvent event : subscriptionBillingEvents) {
+ final Usage usage = findUsage(event);
+ if (usage == null || !usage.equals(existingInterval.getUsage())) {
+ if (existingInterval != null) {
+ usageInterval.add(existingInterval.build(true));
+ existingInterval = null;
+ }
+ }
+
+ if (usage != null) {
+ if (existingInterval == null) {
+ existingInterval = new ContiguousInArrearUsageInterval(usage, invoiceId, unitType, usageApi, targetDate, context);
+ }
+ existingInterval.addBillingEvent(event);
+ }
+ }
+ if (existingInterval != null) {
+ usageInterval.add(existingInterval.build(false));
+ }
+ return usageInterval;
+ }
+
+ private Usage findUsage(final BillingEvent event) {
+ if (event.getUsages().size() == 0) {
+ return null;
+ }
+ for (Usage usage : event.getUsages()) {
+ if (usage.getUsageType() != UsageType.CONSUMABLE ||
+ usage.getBillingMode() != BillingMode.IN_ARREAR) {
+ continue;
+ }
+
+ List<TieredBlock> tieredBlock = getTieredBlocks(usage, unitType);
+ if (tieredBlock.size() > 0) {
+ return usage;
+ }
+ }
+ return null;
+ }
+
+ private void addMissingTransitionTimes(final List<LocalDate> transitionTimes, final List<UsageInvoiceItem> existingUsage) {
+
+ Preconditions.checkArgument(transitionTimes.size() > 0);
+
+ final LocalDate startDate = transitionTimes.get(0);
+ final LocalDate endDate = transitionTimes.get(transitionTimes.size() - 1);
+
+ for (UsageInvoiceItem ii : existingUsage) {
+ if (ii.getEndDate().compareTo(startDate) <= 0 || ii.getStartDate().compareTo(endDate) >= 0) {
+ continue;
+ }
+ if (ii.getStartDate().compareTo(startDate) < 0 && ii.getEndDate().compareTo(endDate) <= 0) {
+ transitionTimes.add(ii.getEndDate());
+ } else if (ii.getStartDate().compareTo(startDate) >= 0 && ii.getEndDate().compareTo(endDate) > 0) {
+ transitionTimes.add(ii.getStartDate());
+ } else {
+ transitionTimes.add(ii.getStartDate());
+ transitionTimes.add(ii.getEndDate());
+ }
+ }
+
+ final Set<LocalDate> uniqueTransitions = new HashSet<LocalDate>(transitionTimes);
+ transitionTimes.clear();
+ transitionTimes.addAll(uniqueTransitions);
+ Collections.sort(transitionTimes);
+ }
+
+}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
index ac44bc7..051ec3d 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
@@ -1099,7 +1099,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
final BillingEventSet events = new MockBillingEventSet();
events.add(event1);
- final Invoice invoice1 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, context);
assertEquals(invoice1.getBalance(), KillBillMoney.of(TEN, invoice1.getCurrency()));
invoiceList.add(invoice1);
@@ -1117,7 +1117,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
// second invoice should be for one half (14/28 days) the difference between the rate plans
// this is a temporary state, since it actually contains an adjusting item that properly belong to invoice 1
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, context);
assertEquals(invoice2.getBalance(), KillBillMoney.of(FIVE, invoice2.getCurrency()));
invoiceList.add(invoice2);
@@ -1149,7 +1149,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
events.add(event);
final LocalDate targetDate = invoiceUtil.buildDate(2011, 1, 15);
- final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, context);
// expect one pro-ration item and one full-period item
assertEquals(invoice.getNumberOfItems(), 2);
@@ -1192,7 +1192,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
events.add(event1);
final UUID accountId = account.getId();
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate(effectiveDate1), Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate(effectiveDate1), Currency.USD, context);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
@@ -1208,7 +1208,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
"testEvent2", 2L, SubscriptionBaseTransitionType.PHASE);
events.add(event2);
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate2), Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate2), Currency.USD, context);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
assertEquals(invoice2.getBalance().compareTo(cheapAmount), 0);
@@ -1218,7 +1218,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
//invoiceUtil.createInvoice(invoice2, invoice2.getTargetDate().getDayOfMonth(), callcontext);
final DateTime effectiveDate3 = effectiveDate2.plusMonths(1);
- final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate3), Currency.USD);
+ final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate3), Currency.USD, context);
assertNotNull(invoice3);
assertEquals(invoice3.getNumberOfItems(), 1);
assertEquals(invoice3.getBalance().compareTo(cheapAmount), 0);
@@ -1229,7 +1229,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testInvoiceForEmptyEventSet() throws InvoiceApiException {
final BillingEventSet events = new MockBillingEventSet();
- final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(), Currency.USD);
+ final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(), Currency.USD, context);
assertNull(invoice);
}
@@ -1263,7 +1263,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
"testEvent2", 2L, SubscriptionBaseTransitionType.CHANGE);
events.add(event2);
- final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(effectiveDate2), Currency.USD);
+ final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(effectiveDate2), Currency.USD, context);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
assertEquals(invoice.getBalance().compareTo(cheapAmount), 0);
@@ -1334,7 +1334,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
BillingPeriod.MONTHLY, 31, BillingMode.IN_ADVANCE,
"new-event", 1L, SubscriptionBaseTransitionType.CREATE);
events.add(event1);
- final Invoice newInvoice = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate, Currency.USD);
+ final Invoice newInvoice = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate, Currency.USD, context);
invoiceUtil.createInvoice(newInvoice, true, context);
// VERIFY THAT WE STILL HAVE ONLY 2 ITEMS, MEANING THERE WERE NO REPAIR AND NO CBA GENERATED
@@ -1369,7 +1369,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
"testEvent1", 1L, SubscriptionBaseTransitionType.CHANGE);
events.add(event1);
- Invoice invoice1 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate1), Currency.USD);
+ Invoice invoice1 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate1), Currency.USD, context);
invoices.add(invoice1);
invoiceUtil.createInvoice(invoice1, true, context);
invoice1 = new DefaultInvoice(invoiceDao.getById(invoice1.getId(), context));
@@ -1380,7 +1380,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
BillingPeriod.MONTHLY, 31, BillingMode.IN_ADVANCE,
"testEvent2", 2L, SubscriptionBaseTransitionType.CHANGE);
events.add(event2);
- Invoice invoice2 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate2), Currency.USD);
+ Invoice invoice2 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate2), Currency.USD, context);
invoiceUtil.createInvoice(invoice2, true, context);
invoice2 = new DefaultInvoice(invoiceDao.getById(invoice2.getId(), context));
assertNotNull(invoice2.getInvoiceNumber());
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
index d030c81..20879e6 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
@@ -102,13 +102,13 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
return false;
}
};
- this.generator = new DefaultInvoiceGenerator(clock, invoiceConfig);
+ this.generator = new DefaultInvoiceGenerator(clock, null, invoiceConfig);
}
@Test(groups = "fast")
public void testWithNullEventSetAndNullInvoiceSet() throws InvoiceApiException {
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, null, null, clock.getUTCToday(), Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, null, null, clock.getUTCToday(), Currency.USD, internalCallContext);
assertNull(invoice);
}
@@ -116,7 +116,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
public void testWithEmptyEventSet() throws InvoiceApiException {
final BillingEventSet events = new MockBillingEventSet();
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, events, null, clock.getUTCToday(), Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, clock.getUTCToday(), Currency.USD, internalCallContext);
assertNull(invoice);
}
@@ -136,7 +136,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
@@ -174,7 +174,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
// Target date is the next BCD, in local time
final LocalDate targetDate = invoiceUtil.buildDate(2012, 8, bcdLocal);
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
@@ -198,7 +198,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
// Set a target date of today (start date)
final LocalDate targetDate = startDate;
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 1);
@@ -221,7 +221,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
@@ -254,7 +254,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
@@ -280,7 +280,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate = invoiceUtil.buildDate(2011, 12, 3);
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 4);
@@ -322,7 +322,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate = invoiceUtil.buildDate(2011, 12, 3);
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 4);
@@ -345,12 +345,12 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
LocalDate targetDate = invoiceUtil.buildDate(2011, 12, 1);
final UUID accountId = UUID.randomUUID();
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
final List<Invoice> existingInvoices = new ArrayList<Invoice>();
existingInvoices.add(invoice1);
targetDate = invoiceUtil.buildDate(2011, 12, 3);
- final Invoice invoice2 = generator.generateInvoice(accountId, events, existingInvoices, targetDate, Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, existingInvoices, targetDate, Currency.USD, internalCallContext);
assertNull(invoice2);
}
@@ -523,7 +523,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate = invoiceUtil.buildDate(2011, 1, 1);
events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), targetDate, plan, planPhase, 1));
- final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, internalCallContext);
assertEquals(invoice.getNumberOfItems(), 1);
}
@@ -538,7 +538,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), startDate, plan, planPhase, startDate.getDayOfMonth()));
- final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, internalCallContext);
final RecurringInvoiceItem item = (RecurringInvoiceItem) invoice.getInvoiceItems().get(0);
// end date of the invoice item should be equal to exactly one month later (rounded)
@@ -575,13 +575,13 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(event2);
events.add(event1);
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate("2012-02-01"), Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate("2012-02-01"), Currency.USD, internalCallContext);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
final List<Invoice> invoiceList = new ArrayList<Invoice>();
invoiceList.add(invoice1);
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate("2012-04-05"), Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate("2012-04-05"), Currency.USD, internalCallContext);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
final FixedPriceInvoiceItem item = (FixedPriceInvoiceItem) invoice2.getInvoiceItems().get(0);
@@ -606,7 +606,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(event1);
// ensure both components are invoiced
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD, internalCallContext);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 2);
assertEquals(invoice1.getBalance(), KillBillMoney.of(FIFTEEN, invoice1.getCurrency()));
@@ -618,7 +618,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate currentDate = startDate.plusMonths(1);
// ensure that only the recurring price is invoiced
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, currentDate, Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, currentDate, Currency.USD, internalCallContext);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
assertEquals(invoice2.getBalance(), KillBillMoney.of(FIVE, invoice2.getCurrency()));
@@ -643,7 +643,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(event1);
// ensure that a single invoice item is generated for the fixed cost
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD, internalCallContext);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
assertEquals(invoice1.getBalance(), KillBillMoney.of(fixedCost1, invoice1.getCurrency()));
@@ -657,7 +657,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(event2);
// ensure that a single invoice item is generated for the fixed cost
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, phaseChangeDate, Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, phaseChangeDate, Currency.USD, internalCallContext);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
assertEquals(invoice2.getBalance(), KillBillMoney.of(fixedCost2, invoice2.getCurrency()));
@@ -690,7 +690,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate discountPhaseEndDate = trialPhaseEndDate.plusMonths(6);
events.add(createBillingEvent(subscriptionId, bundleId, discountPhaseEndDate, plan1, phase3, BILL_CYCLE_DAY));
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, creationDate, Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, creationDate, Currency.USD, internalCallContext);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
@@ -698,7 +698,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final List<Invoice> invoiceList = new ArrayList<Invoice>();
invoiceList.add(invoice1);
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, trialPhaseEndDate, Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, trialPhaseEndDate, Currency.USD, internalCallContext);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
assertEquals(invoice2.getInvoiceItems().get(0).getStartDate(), trialPhaseEndDate);
@@ -706,7 +706,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
invoiceList.add(invoice2);
LocalDate targetDate = new LocalDate(trialPhaseEndDate.getYear(), trialPhaseEndDate.getMonthOfYear(), BILL_CYCLE_DAY);
- final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+ final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice3);
assertEquals(invoice3.getNumberOfItems(), 1);
assertEquals(invoice3.getInvoiceItems().get(0).getStartDate(), targetDate);
@@ -714,7 +714,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
invoiceList.add(invoice3);
targetDate = targetDate.plusMonths(6);
- final Invoice invoice4 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+ final Invoice invoice4 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, internalCallContext);
assertNotNull(invoice4);
assertEquals(invoice4.getNumberOfItems(), 7);
}
@@ -726,7 +726,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final Plan plan1 = new MockPlan();
final PlanPhase phase1 = createMockMonthlyPlanPhase(null, ZERO, PhaseType.TRIAL);
events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), clock.getUTCToday(), plan1, phase1, 1));
- generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+ generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, internalCallContext);
}
private MockPlanPhase createMockMonthlyPlanPhase() {
@@ -773,7 +773,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate, final int expectedNumberOfItems,
final BigDecimal expectedAmount) throws InvoiceApiException {
final Currency currency = Currency.USD;
- final Invoice invoice = generator.generateInvoice(accountId, events, existingInvoices, targetDate, currency);
+ final Invoice invoice = generator.generateInvoice(accountId, events, existingInvoices, targetDate, currency, internalCallContext);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), expectedNumberOfItems);
existingInvoices.add(invoice);
@@ -800,7 +800,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(createBillingEvent(baseSubscription.getId(), baseSubscription.getBundleId(), april25, basePlan, basePlanEvergreen, 25));
// generate invoice
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD, internalCallContext);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
assertEquals(invoice1.getBalance().compareTo(TEN), 0);
@@ -821,7 +821,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(createBillingEvent(addOnSubscription2.getId(), baseSubscription.getBundleId(), april28, addOn2Plan, addOn2PlanPhaseEvergreen, 25));
// generate invoice
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april28, Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april28, Currency.USD, internalCallContext);
invoices.add(invoice2);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 2);
@@ -838,7 +838,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
// generate invoice
final LocalDate may1 = new LocalDate(2012, 5, 1);
- final Invoice invoice3 = generator.generateInvoice(accountId, newEvents, invoices, may1, Currency.USD);
+ final Invoice invoice3 = generator.generateInvoice(accountId, newEvents, invoices, may1, Currency.USD, internalCallContext);
assertNotNull(invoice3);
assertEquals(invoice3.getNumberOfItems(), 3);
// -4.50 -18 - 10 (to correct the previous 2 invoices) + 4.50 + 13
@@ -861,7 +861,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final BillingEventSet events = new MockBillingEventSet();
events.add(createBillingEvent(originalSubscription.getId(), originalSubscription.getBundleId(), april25, originalPlan, originalPlanEvergreen, 25));
- final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD);
+ final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD, internalCallContext);
printDetailInvoice(invoice1);
@@ -883,7 +883,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
events.add(createBillingEvent(newSubscription.getId(), originalSubscription.getBundleId(), april25, newPlan, newPlanEvergreen, 25));
// generate a new invoice
- final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april25, Currency.USD);
+ final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april25, Currency.USD, internalCallContext);
printDetailInvoice(invoice2);
assertEquals(invoice2.getNumberOfItems(), 2);
@@ -942,7 +942,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
final UUID accountId = UUID.randomUUID();
- final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+ final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
assertNull(invoice);
}
@@ -970,7 +970,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
eventSet.add(createBillingEvent(subscriptionId2, bundleId, startDate, plan2, plan2phase1, 1));
// generate the first invoice
- final Invoice invoice1 = generator.generateInvoice(accountId, eventSet, invoices, startDate, currency);
+ final Invoice invoice1 = generator.generateInvoice(accountId, eventSet, invoices, startDate, currency, internalCallContext);
assertNotNull(invoice1);
assertTrue(invoice1.getBalance().compareTo(FIFTEEN.add(TWELVE)) == 0);
invoices.add(invoice1);
@@ -981,7 +981,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
eventSet.addSubscriptionWithAutoInvoiceOff(subscriptionId1);
final LocalDate targetDate2 = startDate.plusMonths(1);
- final Invoice invoice2 = generator.generateInvoice(accountId, eventSet, invoices, targetDate2, currency);
+ final Invoice invoice2 = generator.generateInvoice(accountId, eventSet, invoices, targetDate2, currency, internalCallContext);
assertNotNull(invoice2);
assertTrue(invoice2.getBalance().compareTo(TWELVE) == 0);
invoices.add(invoice2);
@@ -989,7 +989,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
final LocalDate targetDate3 = targetDate2.plusMonths(1);
eventSet.clearSubscriptionsWithAutoInvoiceOff();
eventSet.add(subscription1creation);
- final Invoice invoice3 = generator.generateInvoice(accountId, eventSet, invoices, targetDate3, currency);
+ final Invoice invoice3 = generator.generateInvoice(accountId, eventSet, invoices, targetDate3, currency, internalCallContext);
assertNotNull(invoice3);
assertTrue(invoice3.getBalance().compareTo(FIFTEEN.multiply(TWO).add(TWELVE)) == 0);
}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
index e601ca8..e3a2942 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
@@ -16,22 +16,21 @@
package org.killbill.billing.invoice.glue;
-import org.killbill.billing.util.glue.MemoryGlobalLockerModule;
-import org.mockito.Mockito;
-import org.skife.config.ConfigSource;
-
import org.killbill.billing.catalog.glue.CatalogModule;
import org.killbill.billing.invoice.TestInvoiceHelper;
+import org.killbill.billing.junction.BillingInternalApi;
+import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.killbill.billing.usage.glue.UsageModule;
import org.killbill.billing.util.email.EmailModule;
import org.killbill.billing.util.email.templates.TemplateModule;
import org.killbill.billing.util.glue.CacheModule;
import org.killbill.billing.util.glue.CallContextModule;
import org.killbill.billing.util.glue.CustomFieldModule;
+import org.killbill.billing.util.glue.MemoryGlobalLockerModule;
import org.killbill.billing.util.glue.NotificationQueueModule;
import org.killbill.billing.util.glue.TagStoreModule;
-import org.killbill.billing.junction.BillingInternalApi;
-import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
-
+import org.mockito.Mockito;
+import org.skife.config.ConfigSource;
public class TestInvoiceModule extends DefaultInvoiceModule {
@@ -58,7 +57,7 @@ public class TestInvoiceModule extends DefaultInvoiceModule {
install(new NotificationQueueModule(configSource));
install(new TagStoreModule());
install(new CustomFieldModule());
-
+ install(new UsageModule(configSource));
installExternalApis();
bind(TestInvoiceHelper.class).asEagerSingleton();
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 5194fb8..3f51e54 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -17,6 +17,7 @@
package org.killbill.billing.invoice;
import java.math.BigDecimal;
+import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -27,6 +28,7 @@ import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.Usage;
import org.mockito.Mockito;
import org.skife.jdbi.v2.IDBI;
import org.testng.Assert;
@@ -388,6 +390,11 @@ public class TestInvoiceHelper {
}
@Override
+ public List<Usage> getUsages() {
+ return Collections.emptyList();
+ }
+
+ @Override
public int compareTo(final BillingEvent e1) {
if (!getSubscription().getId().equals(e1.getSubscription().getId())) { // First order by subscription
return getSubscription().getId().compareTo(e1.getSubscription().getId());
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
index 2394b96..54cffc5 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -17,6 +17,9 @@
package org.killbill.billing.junction.plumbing.billing;
import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import javax.annotation.Nullable;
@@ -31,11 +34,14 @@ import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.Usage;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
import org.killbill.billing.junction.BillingEvent;
+import com.google.common.collect.Lists;
+
public class DefaultBillingEvent implements BillingEvent {
private final Account account;
private final int billCycleDayLocal;
@@ -53,19 +59,21 @@ public class DefaultBillingEvent implements BillingEvent {
private final Long totalOrdering;
private final DateTimeZone timeZone;
+ private final List<Usage> usages;
+
public DefaultBillingEvent(final Account account, final EffectiveSubscriptionInternalEvent transition, final SubscriptionBase subscription, final int billCycleDayLocal, final Currency currency, final Catalog catalog) throws CatalogApiException {
this.account = account;
this.billCycleDayLocal = billCycleDayLocal;
this.subscription = subscription;
- effectiveDate = transition.getEffectiveTransitionTime();
+ this.effectiveDate = transition.getEffectiveTransitionTime();
final String planPhaseName = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ?
transition.getNextPhase() : transition.getPreviousPhase();
- planPhase = (planPhaseName != null) ? catalog.findPhase(planPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+ this.planPhase = (planPhaseName != null) ? catalog.findPhase(planPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
final String planName = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ?
transition.getNextPlan() : transition.getPreviousPlan();
- plan = (planName != null) ? catalog.findPlan(planName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+ this.plan = (planName != null) ? catalog.findPlan(planName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
final String nextPhaseName = transition.getNextPhase();
final PlanPhase nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
@@ -74,16 +82,17 @@ public class DefaultBillingEvent implements BillingEvent {
final PlanPhase prevPhase = (prevPhaseName != null) ? catalog.findPhase(prevPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
- fixedPrice = getFixedPrice(nextPhase, currency);
- recurringPrice = getRecurringPrice(nextPhase, currency);
+ this.fixedPrice = getFixedPrice(nextPhase, currency);
+ this.recurringPrice = getRecurringPrice(nextPhase, currency);
this.currency = currency;
- description = transition.getTransitionType().toString();
- billingMode = BillingMode.IN_ADVANCE;
- billingPeriod = getRecurringBillingPeriod((transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase);
- type = transition.getTransitionType();
- totalOrdering = transition.getTotalOrdering();
- timeZone = account.getTimeZone();
+ this.description = transition.getTransitionType().toString();
+ this.billingMode = BillingMode.IN_ADVANCE;
+ this.billingPeriod = getRecurringBillingPeriod((transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase);
+ this.type = transition.getTransitionType();
+ this.totalOrdering = transition.getTotalOrdering();
+ this.timeZone = account.getTimeZone();
+ this.usages = initializeUsage();
}
@@ -106,6 +115,8 @@ public class DefaultBillingEvent implements BillingEvent {
this.type = type;
this.totalOrdering = totalOrdering;
this.timeZone = timeZone;
+ this.usages = initializeUsage();
+
}
@Override
@@ -225,6 +236,17 @@ public class DefaultBillingEvent implements BillingEvent {
}
@Override
+ public DateTimeZone getTimeZone() {
+ return timeZone;
+ }
+
+ @Override
+ public List<Usage> getUsages() {
+ return usages;
+ }
+
+
+ @Override
public String toString() {
// Note: we don't use all fields here, as the output would be overwhelming
// (these events are printed in the logs in junction and invoice).
@@ -320,10 +342,6 @@ public class DefaultBillingEvent implements BillingEvent {
return result;
}
- @Override
- public DateTimeZone getTimeZone() {
- return timeZone;
- }
private BigDecimal getFixedPrice(@Nullable final PlanPhase nextPhase, final Currency currency) throws CatalogApiException {
return (nextPhase != null && nextPhase.getFixed() != null && nextPhase.getFixed().getPrice() != null) ? nextPhase.getFixed().getPrice().getPrice(currency) : null;
@@ -339,4 +357,15 @@ public class DefaultBillingEvent implements BillingEvent {
}
return nextPhase.getRecurring() != null ? nextPhase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
}
+
+ private List<Usage> initializeUsage() {
+ List<Usage> result = Collections.<Usage>emptyList();
+ if (planPhase != null) {
+ result = Lists.newArrayList();
+ for (Usage usage : planPhase.getUsages()) {
+ result.add(usage);
+ }
+ }
+ return result;
+ }
}
diff --git a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
index 2ae8f34..c917a59 100644
--- a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
+++ b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
@@ -17,6 +17,7 @@
package org.killbill.billing.usage.api.user;
import java.math.BigDecimal;
+import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
@@ -53,8 +54,14 @@ public class DefaultUsageUserApi implements UsageUserApi {
}
@Override
- public RolledUpUsage getUsageForSubscription(final UUID subscriptionId, final TenantContext context) {
+ public RolledUpUsage getUsageForSubscription(final UUID subscriptionId, final String unitType, final DateTime startTime, final DateTime endTime, final TenantContext context) {
final RolledUpUsageModelDao usageForSubscription = rolledUpUsageDao.getUsageForSubscription(subscriptionId, internalCallContextFactory.createInternalTenantContext(context));
return new DefaultRolledUpUsage(usageForSubscription);
}
+
+ @Override
+ public List<RolledUpUsage> getAllUsageForSubscription(final UUID subscriptionId, final String unitType, final List<DateTime> transitionTimes, final TenantContext tenantContext) {
+ // STEPH USAGE
+ return null;
+ }
}