killbill-aplcache
Changes
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java 1(+1 -0)
entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java 27(+6 -21)
invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java 5(+2 -3)
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java 3(+2 -1)
payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java 2(+0 -2)
Details
diff --git a/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java b/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
index ca0cd0c..bc78b08 100644
--- a/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
+++ b/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
@@ -63,8 +63,8 @@ public class InternalCallContext extends InternalTenantContext {
this.contextUserType = userType;
this.reasonCode = reasonCode;
this.comments = comment;
- this.createdDate = toUTCDateTime(createdDate);
- this.updatedDate = toUTCDateTime(updatedDate);
+ this.createdDate = createdDate;
+ this.updatedDate = updatedDate;
}
public InternalCallContext(final Long tenantRecordId, final CallContext callContext, final DateTime utcNow) {
diff --git a/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java b/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
index c5c88e9..89f710c 100644
--- a/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
+++ b/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
@@ -23,6 +23,7 @@ import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
+import org.killbill.clock.ClockUtil;
public class TimeAwareContext {
@@ -34,41 +35,16 @@ public class TimeAwareContext {
this.referenceTime = computeReferenceTime(referenceDateTime);
}
- /// Generic functions
- /// TODO Move to ClockUtil
-
- // Create a DateTime object forcing the time zone to be UTC
- protected DateTime toUTCDateTime(final DateTime dateTime) {
- return toDateTime(dateTime, DateTimeZone.UTC);
- }
-
- // Create a DateTime object using the specified timezone (usually, the one on the account)
- public DateTime toDateTime(final DateTime dateTime, final DateTimeZone accountTimeZone) {
- return dateTime.toDateTime(accountTimeZone);
- }
-
- /// DateTime <-> LocalDate transformations
-
- // Create a DateTime object using the specified reference time and timezone (usually, the one on the account)
public DateTime toUTCDateTime(final LocalDate localDate) {
validateContext();
- final DateTime targetDateTime = new DateTime(localDate.getYear(),
- localDate.getMonthOfYear(),
- localDate.getDayOfMonth(),
- getReferenceTime().getHourOfDay(),
- getReferenceTime().getMinuteOfHour(),
- getReferenceTime().getSecondOfMinute(),
- getFixedOffsetTimeZone());
-
- return toUTCDateTime(targetDateTime);
+ return ClockUtil.toUTCDateTime(localDate, getReferenceTime(), getFixedOffsetTimeZone());
}
- // Create a LocalDate object using the specified timezone (usually, the one on the account), respecting the offset at the time of the referenceDateTime
public LocalDate toLocalDate(final DateTime dateTime) {
validateContext();
- return new LocalDate(dateTime, getFixedOffsetTimeZone());
+ return ClockUtil.toLocalDate(dateTime, getFixedOffsetTimeZone());
}
private void validateContext() {
@@ -77,16 +53,19 @@ public class TimeAwareContext {
}
}
+ // For convenience (used in tests)
+
+ //@VisibleForTesting
protected LocalTime computeReferenceTime(@Nullable final DateTime referenceTime) {
- return referenceTime == null ? null : toDateTime(referenceTime, getFixedOffsetTimeZone()).toLocalTime();
+ return referenceTime == null ? null : ClockUtil.toDateTime(referenceTime, getFixedOffsetTimeZone()).toLocalTime();
}
- // For convenience, to be overridden in tests
-
+ //@VisibleForTesting
public DateTimeZone getFixedOffsetTimeZone() {
return fixedOffsetTimeZone;
}
+ //@VisibleForTesting
public LocalTime getReferenceTime() {
return referenceTime;
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
index d8fca92..5f0149c 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
@@ -78,7 +78,7 @@ public class TestIntegration extends TestIntegrationBase {
//
TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
- SubscriptionEventType.START_BILLING, null, null, clock.getUTCNow(), null);
+ SubscriptionEventType.START_BILLING, null, null, null, null);
Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
@@ -93,7 +93,7 @@ public class TestIntegration extends TestIntegrationBase {
// ADD ADD_ON ON THE SAME DAY
//
dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, null, null,
- SubscriptionEventType.START_BILLING, null, bpSubscription.getBundleId(), clock.getUTCNow(), null);
+ SubscriptionEventType.START_BILLING, null, bpSubscription.getBundleId(), null, null);
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("399.95")));
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
@@ -109,7 +109,7 @@ public class TestIntegration extends TestIntegrationBase {
// There is no invoice created as we only adjust the previous invoice.
//
dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, null, null, null, null, null, SubscriptionEventType.STOP_BILLING, bpSubscription.getId(),
- bpSubscription.getBundleId(), clock.getUTCNow(), null);
+ bpSubscription.getBundleId(), null, null);
dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-399.95")));
// The second invoice should be adjusted for the AO (we paid for the full period) and since we paid we should also see a CBA
@@ -153,7 +153,7 @@ public class TestIntegration extends TestIntegrationBase {
// CHANGE PLAN IMMEDIATELY AND EXPECT BOTH EVENTS: NextEvent.CHANGE NextEvent.INVOICE
//
TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
- subscription.getId(), subscription.getBundleId(), clock.getUTCNow(), null);
+ subscription.getId(), subscription.getBundleId(), null, null);
Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(initialCreationDate.toLocalDate(), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index caff3d5..3a7e621 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -99,10 +99,7 @@ import org.killbill.billing.util.api.RecordIdApi;
import org.killbill.billing.util.api.TagApiException;
import org.killbill.billing.util.api.TagDefinitionApiException;
import org.killbill.billing.util.api.TagUserApi;
-import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
-import org.killbill.billing.util.callcontext.CallContext;
-import org.killbill.billing.util.callcontext.TestCallContext;
import org.killbill.billing.util.dao.NonEntityDao;
import org.killbill.billing.util.nodes.KillbillNodesApi;
import org.killbill.billing.util.tag.ControlTagType;
@@ -434,7 +431,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
final PluginProperty prop1 = new PluginProperty(InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID, invoice.getId().toString(), false);
properties.add(prop1);
return paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, amount, currency, UUID.randomUUID().toString(),
- UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, refreshedCallContext());
+ UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, callContext);
} catch (final PaymentApiException e) {
fail(e.toString());
return null;
@@ -453,7 +450,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
properties.add(prop1);
return paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, invoice.getBalance(), invoice.getCurrency(), UUID.randomUUID().toString(),
- UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, refreshedCallContext());
+ UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, callContext);
} catch (final PaymentApiException e) {
fail(e.toString());
return null;
@@ -473,7 +470,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
properties.add(prop1);
return paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, invoice.getBalance(), invoice.getCurrency(), UUID.randomUUID().toString(),
- UUID.randomUUID().toString(), properties, EXTERNAL_PAYMENT_OPTIONS, refreshedCallContext());
+ UUID.randomUUID().toString(), properties, EXTERNAL_PAYMENT_OPTIONS, callContext);
} catch (final PaymentApiException e) {
fail(e.toString());
return null;
@@ -492,7 +489,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
public Payment apply(@Nullable final Void input) {
try {
return paymentApi.createRefundWithPaymentControl(account, payment.getId(), amount, currency, UUID.randomUUID().toString(),
- PLUGIN_PROPERTIES, PAYMENT_OPTIONS, refreshedCallContext());
+ PLUGIN_PROPERTIES, PAYMENT_OPTIONS, callContext);
} catch (final PaymentApiException e) {
fail(e.toString());
return null;
@@ -511,7 +508,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
properties.add(prop1);
try {
return paymentApi.createRefundWithPaymentControl(account, payment.getId(), payment.getPurchasedAmount(), payment.getCurrency(), UUID.randomUUID().toString(),
- properties, PAYMENT_OPTIONS, refreshedCallContext());
+ properties, PAYMENT_OPTIONS, callContext);
} catch (final PaymentApiException e) {
fail(e.toString());
return null;
@@ -536,7 +533,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
try {
return paymentApi.createRefundWithPaymentControl(account, payment.getId(), amount, currency, UUID.randomUUID().toString(),
- properties, PAYMENT_OPTIONS, refreshedCallContext());
+ properties, PAYMENT_OPTIONS, callContext);
} catch (final PaymentApiException e) {
fail(e.toString());
return null;
@@ -555,7 +552,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
public Payment apply(@Nullable final Void input) {
try {
return paymentApi.createChargebackWithPaymentControl(account, payment.getId(), amount, currency, UUID.randomUUID().toString(),
- PAYMENT_OPTIONS, refreshedCallContext());
+ PAYMENT_OPTIONS, callContext);
} catch (final PaymentApiException e) {
fail(e.toString());
return null;
@@ -729,11 +726,6 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
assertListenerStatus();
}
- // Update the context dates (matters for payments ordering for instance)
- protected CallContext refreshedCallContext() {
- return new TestCallContext(callContext, clock.getUTCNow());
- }
-
private <T> T doCallAndCheckForCompletion(final Function<Void, T> f, final NextEvent... events) {
final Joiner joiner = Joiner.on(", ");
log.debug(" ************ STARTING BUS HANDLER CHECK : {} ********************", joiner.join(events));
@@ -754,7 +746,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
private final SubscriptionEventType action;
private final UUID subscriptionId;
private final UUID bundleId;
- private final DateTime effectiveDate;
+ private final LocalDate effectiveDate;
private final BillingActionPolicy billingPolicy;
public TestDryRunArguments(final DryRunType dryRunType) {
@@ -776,7 +768,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
final SubscriptionEventType action,
final UUID subscriptionId,
final UUID bundleId,
- final DateTime effectiveDate,
+ final LocalDate effectiveDate,
final BillingActionPolicy billingPolicy) {
this.dryRunType = dryRunType;
this.spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceList, phaseType);
@@ -808,7 +800,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
}
@Override
- public DateTime getEffectiveDate() {
+ public LocalDate getEffectiveDate() {
return effectiveDate;
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
index e3bb373..5894656 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
@@ -24,6 +24,7 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
+import org.joda.time.IllegalInstantException;
import org.joda.time.LocalDate;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountData;
@@ -75,7 +76,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
final TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
- SubscriptionEventType.START_BILLING, null, null, clock.getUTCNow(), null);
+ SubscriptionEventType.START_BILLING, null, null, null, null);
final Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 9, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
@@ -197,4 +198,60 @@ public class TestWithTimeZones extends TestIntegrationBase {
final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
Assert.assertEquals(invoices.size(), 1);
}
+
+ @Test(groups = "slow")
+ public void testReferenceTimeInDSTGap() throws Exception {
+ final DateTimeZone tz = DateTimeZone.forID("America/Los_Angeles");
+ clock.setTime(new DateTime(2015, 3, 7, 2, 0, 0, tz));
+
+ final AccountData accountData = new MockAccountBuilder().currency(Currency.USD)
+ .timeZone(tz)
+ .build();
+ final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+ accountChecker.checkAccount(account.getId(), accountData, callContext);
+ Assert.assertEquals(account.getTimeZone(), tz);
+ Assert.assertEquals(account.getFixedOffsetTimeZone(), DateTimeZone.forOffsetHours(-8));
+
+ // Note the gap: 2015-03-07T02:00:00.000-08:00 to 2015-03-08T03:00:00.000-07:00
+ clock.addDays(1);
+
+ try {
+ // See TimeAwareContext#toUTCDateTime (which uses account.getFixedOffsetTimeZone() instead)
+ new DateTime(clock.getUTCToday().getYear(),
+ clock.getUTCToday().getMonthOfYear(),
+ clock.getUTCToday().getDayOfMonth(),
+ account.getReferenceTime().toDateTime(tz).getHourOfDay(),
+ account.getReferenceTime().toDateTime(tz).getMinuteOfHour(),
+ account.getReferenceTime().toDateTime(tz).getSecondOfMinute(),
+ account.getTimeZone());
+ Assert.fail();
+ } catch (final IllegalInstantException e) {
+ // Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-08T10:00:00.000 (America/Los_Angeles)
+ }
+
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", ProductCategory.BASE, BillingPeriod.MONTHLY, "notrial", null);
+ // Pass a date of today, to trigger TimeAwareContext#toUTCDateTime
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), clock.getUTCToday(), ImmutableList.<PluginProperty>of(), callContext);
+ assertListenerStatus();
+
+ Assert.assertEquals(entitlement.getEffectiveStartDate().compareTo(new LocalDate("2015-03-08")), 0);
+ Assert.assertEquals(((DefaultEntitlement) entitlement).getBasePlanSubscriptionBase().getStartDate().compareTo(new DateTime("2015-03-08T02:00:00.000-08:00")), 0);
+
+ invoiceChecker.checkChargedThroughDate(entitlement.getId(), new LocalDate("2015-04-08"), callContext);
+
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ clock.addDays(31);
+ assertListenerStatus();
+
+ invoiceChecker.checkChargedThroughDate(entitlement.getId(), new LocalDate("2015-05-08"), callContext);
+
+ for (int i = 0; i < 25 ; i++) {
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ clock.addMonths(1);
+ assertListenerStatus();
+
+ invoiceChecker.checkChargedThroughDate(entitlement.getId(), new LocalDate("2015-03-08").plusMonths(3 + i), callContext);
+ }
+ }
}
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
index 71fa477..07ddabf 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
@@ -138,6 +138,7 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
accountInternalApi,
immutableAccountInternalApi,
nonEntityDao,
+ clock,
internalCallContextFactory,
callContext,
internalCallContext);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
index 5e43715..8b41884 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -26,22 +26,14 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
-import org.killbill.billing.ObjectType;
-import org.killbill.billing.entitlement.AccountEventsStreams;
-import org.killbill.billing.payment.api.PluginProperty;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
import org.killbill.billing.account.api.Account;
import org.killbill.billing.api.TestApiListener.NextEvent;
-import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.AccountEventsStreams;
import org.killbill.billing.entitlement.EntitlementService;
import org.killbill.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
import org.killbill.billing.entitlement.EventsStream;
@@ -52,7 +44,10 @@ import org.killbill.billing.entitlement.api.DefaultEntitlementApi;
import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
import org.killbill.billing.entitlement.api.EntitlementApiException;
-import org.killbill.billing.entitlement.dao.BlockingStateSqlDao;
+import org.killbill.billing.payment.api.PluginProperty;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
@@ -61,8 +56,6 @@ import com.google.common.collect.Iterables;
public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
- private BlockingStateSqlDao sqlDao;
- private Account account;
private DefaultEntitlement baseEntitlement;
private DefaultEntitlement addOnEntitlement;
// Dates for the base plan only
@@ -73,10 +66,8 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
@BeforeMethod(groups = "slow")
public void setUp() throws Exception {
- sqlDao = dbi.onDemand(BlockingStateSqlDao.class);
-
clock.setDay(initialDate);
- account = createAccount(getAccountData(7));
+ final Account account = createAccount(getAccountData(7));
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE);
@@ -452,7 +443,6 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
}
private Collection<BlockingState> computeFutureBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement) throws EntitlementApiException {
- setContextAccountRecordId();
final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(internalCallContext);
final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(accountEventsStreams.getEventsStreams().values()),
@@ -471,7 +461,6 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
}
private Collection<BlockingState> computeBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement, final DateTime effectiveDate) throws EntitlementApiException {
- setContextAccountRecordId();
final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(internalCallContext);
final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(accountEventsStreams.getEventsStreams().values()),
@@ -493,8 +482,4 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
}
}));
}
-
- private void setContextAccountRecordId() {
- internalCallContext.setAccountRecordId(nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID)));
- }
}
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 9f0e176..f4fac61 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
@@ -28,14 +28,12 @@ import java.util.UUID;
import javax.annotation.Nullable;
-import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.account.api.ImmutableAccountData;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.Currency;
@@ -208,15 +206,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
final CallContext context) throws InvoiceApiException {
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(accountId, context);
- final ImmutableAccountData account;
- try {
- account = accountUserApi.getImmutableAccountDataById(accountId, internalContext);
- } catch (final AccountApiException e) {
- throw new InvoiceApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, e.toString());
- }
-
- final DateTime processingDateTime = targetDate != null ? targetDate.toDateTimeAtCurrentTime(account.getTimeZone()) : null;
- final Invoice result = dispatcher.processAccount(accountId, processingDateTime, dryRunArguments, internalContext);
+ final Invoice result = dispatcher.processAccount(accountId, targetDate, dryRunArguments, 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/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index a9e4d02..b3db9fd 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -108,6 +108,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.inject.Inject;
@@ -165,19 +166,19 @@ public class InvoiceDispatcher {
public void processSubscriptionForInvoiceGeneration(final EffectiveSubscriptionInternalEvent transition,
final InternalCallContext context) throws InvoiceApiException {
final UUID subscriptionId = transition.getSubscriptionId();
- final DateTime targetDate = transition.getEffectiveTransitionTime();
+ final LocalDate targetDate = context.toLocalDate(transition.getEffectiveTransitionTime());
processSubscriptionForInvoiceGeneration(subscriptionId, targetDate, context);
}
- public void processSubscriptionForInvoiceGeneration(final UUID subscriptionId, final DateTime targetDate, final InternalCallContext context) throws InvoiceApiException {
+ public void processSubscriptionForInvoiceGeneration(final UUID subscriptionId, final LocalDate targetDate, final InternalCallContext context) throws InvoiceApiException {
processSubscriptionInternal(subscriptionId, targetDate, false, context);
}
- public void processSubscriptionForInvoiceNotification(final UUID subscriptionId, final DateTime targetDate, final InternalCallContext context) throws InvoiceApiException {
+ public void processSubscriptionForInvoiceNotification(final UUID subscriptionId, final LocalDate targetDate, final InternalCallContext context) throws InvoiceApiException {
final Invoice dryRunInvoice = processSubscriptionInternal(subscriptionId, targetDate, true, context);
if (dryRunInvoice != null && dryRunInvoice.getBalance().compareTo(BigDecimal.ZERO) > 0) {
final InvoiceNotificationInternalEvent event = new DefaultInvoiceNotificationInternalEvent(dryRunInvoice.getAccountId(), dryRunInvoice.getBalance(), dryRunInvoice.getCurrency(),
- targetDate, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
+ context.toUTCDateTime(targetDate), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
try {
eventBus.post(event);
} catch (final EventBusException e) {
@@ -186,7 +187,7 @@ public class InvoiceDispatcher {
}
}
- private Invoice processSubscriptionInternal(final UUID subscriptionId, final DateTime targetDate, final boolean dryRunForNotification, final InternalCallContext context) throws InvoiceApiException {
+ private Invoice processSubscriptionInternal(final UUID subscriptionId, final LocalDate targetDate, final boolean dryRunForNotification, final InternalCallContext context) throws InvoiceApiException {
try {
if (subscriptionId == null) {
log.error("Failed handling SubscriptionBase change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
@@ -203,7 +204,7 @@ public class InvoiceDispatcher {
}
}
- public Invoice processAccount(final UUID accountId, @Nullable final DateTime targetDate,
+ public Invoice processAccount(final UUID accountId, @Nullable final LocalDate targetDate,
@Nullable final DryRunArguments dryRunArguments, final InternalCallContext context) throws InvoiceApiException {
GlobalLock lock = null;
try {
@@ -222,13 +223,18 @@ public class InvoiceDispatcher {
return null;
}
- private Invoice processAccountWithLock(final UUID accountId, @Nullable final DateTime inputTargetDateTime,
+ private Invoice processAccountWithLock(final UUID accountId, @Nullable final LocalDate inputTargetDateMaybeNull,
@Nullable final DryRunArguments dryRunArguments, final InternalCallContext context) throws InvoiceApiException {
-
final boolean isDryRun = dryRunArguments != null;
- // A null inputTargetDateTime is only allowed in dryRun mode to have the system compute it
- Preconditions.checkArgument(inputTargetDateTime != null ||
- (dryRunArguments != null && DryRunType.UPCOMING_INVOICE.equals(dryRunArguments.getDryRunType())), "inputTargetDateTime is required in non dryRun mode");
+ final boolean upcomingInvoiceDryRun = isDryRun && DryRunType.UPCOMING_INVOICE.equals(dryRunArguments.getDryRunType());
+
+ LocalDate inputTargetDate = inputTargetDateMaybeNull;
+ // A null inputTargetDate is only allowed in dryRun mode to have the system compute it
+ if (inputTargetDate == null && !upcomingInvoiceDryRun) {
+ inputTargetDate = clock.getUTCToday();
+ }
+ Preconditions.checkArgument(inputTargetDate != null || upcomingInvoiceDryRun, "inputTargetDate is required in non dryRun mode");
+
try {
// Make sure to first set the BCD if needed then get the account object (to have the BCD set)
final BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId, dryRunArguments, context);
@@ -236,11 +242,11 @@ public class InvoiceDispatcher {
return null;
}
final Iterable<UUID> filteredSubscriptionIdsForDryRun = getFilteredSubscriptionIdsForDryRun(dryRunArguments, billingEvents);
- final List<DateTime> candidateDateTimes = (inputTargetDateTime != null) ?
- ImmutableList.of(inputTargetDateTime) :
- getUpcomingInvoiceCandidateDates(filteredSubscriptionIdsForDryRun, context);
- for (final DateTime curTargetDateTime : candidateDateTimes) {
- final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDateTime, billingEvents, isDryRun, context);
+ final List<LocalDate> candidateTargetDates = (inputTargetDate != null) ?
+ ImmutableList.<LocalDate>of(inputTargetDate) :
+ getUpcomingInvoiceCandidateDates(filteredSubscriptionIdsForDryRun, context);
+ for (final LocalDate curTargetDate : candidateTargetDates) {
+ final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDate, billingEvents, isDryRun, context);
if (invoice != null) {
filterInvoiceItemsForDryRun(filteredSubscriptionIdsForDryRun, invoice);
return invoice;
@@ -294,7 +300,7 @@ public class InvoiceDispatcher {
});
}
- private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final DateTime targetDateTime,
+ private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final LocalDate targetDate,
final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext context) throws InvoiceApiException {
try {
final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
@@ -310,7 +316,6 @@ public class InvoiceDispatcher {
}));
final Currency targetCurrency = account.getCurrency();
- final LocalDate targetDate = context.toLocalDate(targetDateTime);
final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, billingEvents, invoices, targetDate, targetCurrency, context);
final Invoice invoice = invoiceWithMetadata.getInvoice();
@@ -323,9 +328,9 @@ public class InvoiceDispatcher {
//
if (invoice == null) {
if (isDryRun) {
- log.info("Generated null dryRun invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
+ log.info("Generated null dryRun invoice for accountId {} and targetDate {}", accountId, targetDate);
} else {
- log.info("Generated null invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
+ log.info("Generated null invoice for accountId {} and targetDate {}", accountId, targetDate);
final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(),
context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
@@ -610,11 +615,16 @@ public class InvoiceDispatcher {
}
}
- private List<DateTime> getUpcomingInvoiceCandidateDates(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
+ private List<LocalDate> getUpcomingInvoiceCandidateDates(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
final Iterable<DateTime> nextScheduledInvoiceDates = getNextScheduledInvoiceEffectiveDate(filteredSubscriptionIds, internalCallContext);
final Iterable<DateTime> nextScheduledSubscriptionsEventDates = subscriptionApi.getFutureNotificationsForAccount(internalCallContext);
- Iterables.concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates);
- return UPCOMING_NOTIFICATION_DATE_ORDERING.sortedCopy(Iterables.concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates));
+ return Lists.<DateTime, LocalDate>transform(UPCOMING_NOTIFICATION_DATE_ORDERING.sortedCopy(Iterables.<DateTime>concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates)),
+ new Function<DateTime, LocalDate>() {
+ @Override
+ public LocalDate apply(final DateTime input) {
+ return internalCallContext.toLocalDate(input);
+ }
+ });
}
private Iterable<DateTime> getNextScheduledInvoiceEffectiveDate(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
@@ -669,7 +679,7 @@ public class InvoiceDispatcher {
}
@Override
- public DateTime getEffectiveDate() {
+ public LocalDate getEffectiveDate() {
return null;
}
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 165f849..a9a128f 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,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 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:
*
@@ -30,8 +32,6 @@ import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
import org.killbill.billing.util.callcontext.CallOrigin;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.billing.util.config.InvoiceConfig;
-import org.killbill.clock.Clock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,27 +46,21 @@ public class InvoiceListener {
private final InvoiceDispatcher dispatcher;
private final InternalCallContextFactory internalCallContextFactory;
private final AccountInternalApi accountApi;
- private final InvoiceConfig invoiceConfig;
- private final Clock clock;
@Inject
- public InvoiceListener(final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory,
- final InvoiceConfig invoiceConfig, final InvoiceDispatcher dispatcher) {
+ public InvoiceListener(final AccountInternalApi accountApi, final InternalCallContextFactory internalCallContextFactory, final InvoiceDispatcher dispatcher) {
this.accountApi = accountApi;
this.dispatcher = dispatcher;
- this.invoiceConfig = invoiceConfig;
this.internalCallContextFactory = internalCallContextFactory;
- this.clock = clock;
}
@AllowConcurrentEvents
@Subscribe
public void handleRepairSubscriptionEvent(final RepairSubscriptionInternalEvent event) {
-
try {
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "RepairBundle", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
- dispatcher.processAccount(event.getAccountId(), event.getEffectiveDate(), null, context);
- } catch (InvoiceApiException e) {
+ dispatcher.processAccount(event.getAccountId(), context.toLocalDate(event.getEffectiveDate()), null, context);
+ } catch (final InvoiceApiException e) {
log.error(e.getMessage());
}
}
@@ -74,7 +68,6 @@ public class InvoiceListener {
@AllowConcurrentEvents
@Subscribe
public void handleSubscriptionTransition(final EffectiveSubscriptionInternalEvent event) {
-
try {
// Skip future uncancel event
// Skip events which are marked as not being the last one
@@ -85,15 +78,12 @@ public class InvoiceListener {
}
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "SubscriptionBaseTransition", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
dispatcher.processSubscriptionForInvoiceGeneration(event, context);
- } catch (InvoiceApiException e) {
+ } catch (final InvoiceApiException e) {
log.error(e.getMessage());
}
}
- @AllowConcurrentEvents
- @Subscribe
public void handleBlockingStateTransition(final BlockingTransitionInternalEvent event) {
-
// We are only interested in blockBilling or unblockBilling transitions.
if (!event.isTransitionedToUnblockedBilling() && !event.isTransitionedToBlockedBilling()) {
return;
@@ -102,10 +92,10 @@ public class 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.processAccount(accountId, clock.getUTCNow(), null, context);
- } catch (InvoiceApiException e) {
+ dispatcher.processAccount(accountId, null, null, context);
+ } catch (final InvoiceApiException e) {
log.error(e.getMessage());
- } catch (AccountApiException e) {
+ } catch (final AccountApiException e) {
log.error(e.getMessage());
}
}
@@ -113,8 +103,8 @@ public class InvoiceListener {
public void handleNextBillingDateEvent(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
try {
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "Next Billing Date", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
- dispatcher.processSubscriptionForInvoiceGeneration(subscriptionId, eventDateTime, context);
- } catch (InvoiceApiException e) {
+ dispatcher.processSubscriptionForInvoiceGeneration(subscriptionId, context.toLocalDate(eventDateTime), context);
+ } catch (final InvoiceApiException e) {
log.error(e.getMessage());
}
}
@@ -122,8 +112,8 @@ public class InvoiceListener {
public void handleEventForInvoiceNotification(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
try {
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "Next Billing Date", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
- dispatcher.processSubscriptionForInvoiceNotification(subscriptionId, eventDateTime, context);
- } catch (InvoiceApiException e) {
+ dispatcher.processSubscriptionForInvoiceNotification(subscriptionId, context.toLocalDate(eventDateTime), context);
+ } catch (final InvoiceApiException e) {
log.error(e.getMessage());
}
}
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 cb6ed8c..c8bc558 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,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 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:
*
@@ -18,18 +20,16 @@ package org.killbill.billing.invoice;
import java.util.UUID;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import org.killbill.billing.ObjectType;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.events.ControlTagDeletionInternalEvent;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.clock.Clock;
-import org.killbill.billing.events.ControlTagDeletionInternalEvent;
import org.killbill.billing.util.tag.ControlTagType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
@@ -39,15 +39,12 @@ public class InvoiceTagHandler {
private static final Logger log = LoggerFactory.getLogger(InvoiceTagHandler.class);
- private final Clock clock;
private final InvoiceDispatcher dispatcher;
private final InternalCallContextFactory internalCallContextFactory;
@Inject
- public InvoiceTagHandler(final Clock clock,
- final InvoiceDispatcher dispatcher,
+ public InvoiceTagHandler(final InvoiceDispatcher dispatcher,
final InternalCallContextFactory internalCallContextFactory) {
- this.clock = clock;
this.dispatcher = dispatcher;
this.internalCallContextFactory = internalCallContextFactory;
}
@@ -55,7 +52,6 @@ public class InvoiceTagHandler {
@AllowConcurrentEvents
@Subscribe
public void process_AUTO_INVOICING_OFF_removal(final ControlTagDeletionInternalEvent event) {
-
if (event.getTagDefinition().getName().equals(ControlTagType.AUTO_INVOICING_OFF.toString()) && event.getObjectType() == ObjectType.ACCOUNT) {
final UUID accountId = event.getObjectId();
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "InvoiceTagHandler", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
@@ -65,8 +61,8 @@ public class InvoiceTagHandler {
private void processUnpaid_AUTO_INVOICING_OFF_invoices(final UUID accountId, final InternalCallContext context) {
try {
- dispatcher.processAccount(accountId, clock.getUTCNow(), null, context);
- } catch (InvoiceApiException e) {
+ dispatcher.processAccount(accountId, null, null, context);
+ } catch (final InvoiceApiException e) {
log.warn(String.format("Failed to process process removal AUTO_INVOICING_OFF for account %s", accountId), e);
}
}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index fd4b071..c455844 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -23,7 +23,6 @@ import java.util.Collection;
import java.util.List;
import java.util.UUID;
-import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.catalog.api.Currency;
@@ -43,7 +42,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
private final Logger log = LoggerFactory.getLogger(TestDefaultInvoiceMigrationApi.class);
private LocalDate date_migrated;
- private DateTime date_regular;
+ private LocalDate date_regular;
private UUID accountId;
private UUID migrationInvoiceId;
@@ -57,7 +56,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
public void beforeMethod() throws Exception {
super.beforeMethod();
date_migrated = clock.getUTCToday().minusYears(1);
- date_regular = clock.getUTCNow();
+ date_regular = clock.getUTCToday();
final Account account = invoiceUtil.createAccount(callContext);
accountId = account.getId();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
index 2ff479d..57ebef6 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 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:
*
@@ -58,11 +60,9 @@ public class TestDefaultInvoiceUserApi extends InvoiceTestSuiteWithEmbeddedDB {
super.beforeMethod();
final Account account = invoiceUtil.createAccount(callContext);
accountId = account.getId();
- invoiceId = invoiceUtil.generateRegularInvoice(account, clock.getUTCNow(), callContext);
+ invoiceId = invoiceUtil.generateRegularInvoice(account, null, callContext);
}
-
-
@Test(groups = "slow")
public void testPostExternalChargeOnNewInvoice() throws Exception {
// Initial account balance
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 2bdde60..079900b 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-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 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
@@ -84,7 +84,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
- final DateTime target = effectiveDate;
+ final LocalDate target = internalCallContext.toLocalDate(effectiveDate);
final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
@@ -144,7 +144,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
null, invoiceConfig, clock);
- final Invoice invoice = dispatcher.processAccount(account.getId(), new DateTime("2012-07-30T00:00:00.000Z"), null, context);
+ final Invoice invoice = dispatcher.processAccount(account.getId(), new LocalDate("2012-07-30"), null, 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 973d658..6b4020f 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -193,7 +193,7 @@ public class TestInvoiceHelper {
this.invoiceConfig = invoiceConfig;
}
- public UUID generateRegularInvoice(final Account account, final DateTime targetDate, final CallContext callContext) throws Exception {
+ public UUID generateRegularInvoice(final Account account, final LocalDate targetDate, final CallContext callContext) throws Exception {
final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
Mockito.when(subscription.getId()).thenReturn(UUID.randomUUID());
Mockito.when(subscription.getBundleId()).thenReturn(new UUID(0L, 0L));
@@ -258,12 +258,12 @@ public class TestInvoiceHelper {
final Account account;
if (isFastTest()) {
- account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountUserApi, accountApi, immutableAccountApi, nonEntityDao, internalCallContextFactory, callContext, internalCallContext);
+ account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountUserApi, accountApi, immutableAccountApi, nonEntityDao, clock, internalCallContextFactory, callContext, internalCallContext);
} else {
account = accountUserApi.createAccount(accountData, callContext);
}
- GuicyKillbillTestSuite.refreshCallContext(account.getId(), internalCallContextFactory, callContext, internalCallContext);
+ GuicyKillbillTestSuite.refreshCallContext(account.getId(), clock, internalCallContextFactory, callContext, internalCallContext);
return account;
}
@@ -462,7 +462,7 @@ public class TestInvoiceHelper {
}
@Override
- public DateTime getEffectiveDate() {
+ public LocalDate getEffectiveDate() {
return null;
}
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 9cda9fa..5e9e90f 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
@@ -33,7 +33,7 @@ public class TestInvoiceNotificationQListener extends InvoiceListener {
@Inject
public TestInvoiceNotificationQListener(final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory, final InvoiceDispatcher dispatcher) {
- super(accountApi, clock, internalCallContextFactory, null, dispatcher);
+ super(accountApi, internalCallContextFactory, dispatcher);
}
@Override
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index fed8945..85f268a 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -51,8 +51,6 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.ObjectType;
@@ -105,7 +103,6 @@ import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.clock.Clock;
-import org.killbill.clock.ClockUtil;
import org.killbill.commons.metrics.TimedResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -366,7 +363,7 @@ public class InvoiceResource extends JaxRsResourceBase {
final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);
- final DryRunArguments dryRunArguments = new DefaultDryRunArguments(dryRunSubscriptionSpec, account.getTimeZone(), account.getCurrency(), clock);
+ final DryRunArguments dryRunArguments = new DefaultDryRunArguments(dryRunSubscriptionSpec, account);
try {
final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRunArguments,
callContext);
@@ -952,13 +949,13 @@ public class InvoiceResource extends JaxRsResourceBase {
private final DryRunType dryRunType;
private final SubscriptionEventType action;
private final UUID subscriptionId;
- private final DateTime effectiveDate;
+ private final LocalDate effectiveDate;
private final PlanPhaseSpecifier specifier;
private final UUID bundleId;
private final BillingActionPolicy billingPolicy;
private final List<PlanPhasePriceOverride> overrides;
- public DefaultDryRunArguments(final InvoiceDryRunJson input, final DateTimeZone accountTimeZone, final Currency currency, final Clock clock) {
+ public DefaultDryRunArguments(final InvoiceDryRunJson input, final Account account) {
if (input == null) {
this.dryRunType = DryRunType.TARGET_DATE;
this.action = null;
@@ -973,7 +970,7 @@ public class InvoiceResource extends JaxRsResourceBase {
this.action = input.getDryRunAction() != null ? SubscriptionEventType.valueOf(input.getDryRunAction()) : null;
this.subscriptionId = input.getSubscriptionId() != null ? UUID.fromString(input.getSubscriptionId()) : null;
this.bundleId = input.getBundleId() != null ? UUID.fromString(input.getBundleId()) : null;
- this.effectiveDate = input.getEffectiveDate() != null ? ClockUtil.computeDateTimeWithUTCReferenceTime(input.getEffectiveDate(), clock.getUTCNow().toLocalTime(), accountTimeZone, clock) : null;
+ this.effectiveDate = input.getEffectiveDate();
this.billingPolicy = input.getBillingPolicy() != null ? BillingActionPolicy.valueOf(input.getBillingPolicy()) : null;
final PlanPhaseSpecifier planPhaseSpecifier = (input.getProductName() != null &&
input.getProductCategory() != null &&
@@ -991,9 +988,9 @@ public class InvoiceResource extends JaxRsResourceBase {
@Override
public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
if (input.getPhaseName() != null) {
- return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
+ return new DefaultPlanPhasePriceOverride(input.getPhaseName(), account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice());
} else {
- return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+ return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice());
}
}
})) : ImmutableList.<PlanPhasePriceOverride>of();
@@ -1021,7 +1018,7 @@ public class InvoiceResource extends JaxRsResourceBase {
}
@Override
- public DateTime getEffectiveDate() {
+ public LocalDate getEffectiveDate() {
return effectiveDate;
}
@@ -1040,5 +1037,4 @@ public class InvoiceResource extends JaxRsResourceBase {
return overrides;
}
}
-
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index e286e85..57dd579 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -124,7 +124,7 @@ public class PaymentResource extends ComboPaymentResource {
@TimedResource(name = "getPayment")
@GET
@Produces(APPLICATION_JSON)
- @ApiOperation(value = "Retrieve a payment by id", response = PaymentJson.class)
+ @ApiOperation(value = "Retrieve a payment by external key", response = PaymentJson.class)
@ApiResponses(value = {@ApiResponse(code = 404, message = "Payment not found")})
public Response getPaymentByExternalKey(@QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
@QueryParam(QUERY_EXTERNAL_KEY) final String paymentExternalKey,
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index 84b3bc1..4cee36a 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -42,6 +42,7 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.clock.ClockUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -143,7 +144,7 @@ public class BillCycleDayCalculator {
}
final DateTime date = plan.dateOfFirstRecurringNonZeroCharge(subscription.getStartDate(), initialPhaseType);
- final int bcdLocal = context.toDateTime(date, account.getTimeZone()).getDayOfMonth();
+ final int bcdLocal = ClockUtil.toDateTime(date, account.getTimeZone()).getDayOfMonth();
log.info("Calculated BCD: subscription id {}, subscription start {}, timezone {}, bcd {}",
subscription.getId(), date.toDateTimeISO(), account.getTimeZone(), bcdLocal);
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
index 106c179..1ef93cc 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
@@ -121,8 +121,6 @@ public class TestPaymentLeavingStateCallback extends PaymentTestSuiteWithEmbedde
transactions.get(0).getId(), TransactionStatus.SUCCESS, BigDecimal.ONE, Currency.BRL,
"foo", "bar", internalCallContext);
- internalCallContext.setAccountRecordId(123L);
-
paymentStateContext = new PaymentStateContext(true,
paymentId,
null,
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
index ac1860e..5b56ec4 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
@@ -21,7 +21,7 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
-import org.joda.time.DateTimeZone;
+import org.killbill.billing.account.api.Account;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
@@ -37,13 +37,13 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testPaymentCRUD() throws Exception {
for (int i = 0; i < 3; i++) {
- testPaymentCRUDForAccount(UUID.randomUUID(), i + 1);
+ testPaymentCRUDForAccount();
}
}
- public void testPaymentCRUDForAccount(final UUID accountId, final int accountNb) {
- // We need to create specific call contexts to make the account_record_id magic work
- internalCallContext.setAccountRecordId((long) accountNb);
+ public void testPaymentCRUDForAccount() throws Exception {
+ final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+ final UUID accountId = account.getId();
final PaymentModelDao specifiedFirstPaymentModelDao = generatePaymentModelDao(accountId);
final PaymentTransactionModelDao specifiedFirstPaymentTransactionModelDao = generatePaymentTransactionModelDao(specifiedFirstPaymentModelDao.getId());
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
index d75b656..8bc6634 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
@@ -25,18 +25,16 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.account.api.Account;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
-import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.callcontext.UserType;
import org.killbill.billing.util.entity.Pagination;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -60,8 +58,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final TransactionType transactionType = TransactionType.AUTHORIZE;
final String pluginName = "superPlugin";
- final UUID accountId = UUID.randomUUID();
-
final List<PluginProperty> properties = new ArrayList<PluginProperty>();
properties.add(new PluginProperty("key1", "value1", false));
properties.add(new PluginProperty("key2", "value2", false));
@@ -315,9 +311,8 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
// Just to guarantee that next clock.getUTCNow() > newTime
try {
Thread.sleep(1000);
- } catch (InterruptedException e) {
+ } catch (final InterruptedException e) {
}
- ;
final Iterable<PaymentTransactionModelDao> transactions2 = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.PENDING), clock.getUTCNow(), initialTime, 0L, 1L);
for (PaymentTransactionModelDao paymentTransaction : transactions2) {
@@ -333,10 +328,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
}
@Test(groups = "slow")
- public void testPaymentByStatesAcrossTenants() {
-
- final UUID paymentMethodId = UUID.randomUUID();
- final UUID accountId = UUID.randomUUID();
+ public void testPaymentByStatesAcrossTenants() throws Exception {
final String externalKey1 = "XXhhhhooo1";
final String transactionExternalKey1 = "transactionXX1";
@@ -357,72 +349,72 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
// Right before createdAfterDate, so should not be returned
final DateTime createdDate1 = createdAfterDate.minusHours(1);
- final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, accountId, paymentMethodId, externalKey1);
+ clock.setTime(createdDate1);
+ Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+ final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, account.getId(), account.getPaymentMethodId(), externalKey1);
paymentModelDao1.setStateName("AUTH_ERRORED");
final PaymentTransactionModelDao transaction1 = new PaymentTransactionModelDao(createdDate1, createdDate1, null, transactionExternalKey1,
paymentModelDao1.getId(), TransactionType.AUTHORIZE, createdDate1,
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- internalCallContext.setAccountRecordId(1L);
- internalCallContext.setCreatedDate(createdDate1);
- internalCallContext.setUpdatedDate(createdDate1);
paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, internalCallContext);
// Right after createdAfterDate, so it should be returned
final DateTime createdDate2 = createdAfterDate.plusHours(1);
- final PaymentModelDao paymentModelDao2 = new PaymentModelDao(createdDate2, createdDate2, accountId, paymentMethodId, externalKey2);
+ clock.setTime(createdDate2);
+ account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+ final PaymentModelDao paymentModelDao2 = new PaymentModelDao(createdDate2, createdDate2, account.getId(), account.getPaymentMethodId(), externalKey2);
paymentModelDao2.setStateName("CAPTURE_ERRORED");
final PaymentTransactionModelDao transaction2 = new PaymentTransactionModelDao(createdDate2, createdDate2, null, transactionExternalKey2,
paymentModelDao2.getId(), TransactionType.AUTHORIZE, createdDate2,
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- internalCallContext.setAccountRecordId(2L);
- internalCallContext.setCreatedDate(createdDate2);
- internalCallContext.setUpdatedDate(createdDate2);
paymentDao.insertPaymentWithFirstTransaction(paymentModelDao2, transaction2, internalCallContext);
// Right before createdBeforeDate, so it should be returned
final DateTime createdDate3 = createdBeforeDate.minusDays(1);
- final PaymentModelDao paymentModelDao3 = new PaymentModelDao(createdDate3, createdDate3, accountId, paymentMethodId, externalKey3);
+ clock.setTime(createdDate3);
+ account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+ final PaymentModelDao paymentModelDao3 = new PaymentModelDao(createdDate3, createdDate3, account.getId(), account.getPaymentMethodId(), externalKey3);
paymentModelDao3.setStateName("CAPTURE_ERRORED");
final PaymentTransactionModelDao transaction3 = new PaymentTransactionModelDao(createdDate3, createdDate3, null, transactionExternalKey3,
paymentModelDao3.getId(), TransactionType.AUTHORIZE, createdDate3,
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- internalCallContext.setAccountRecordId(3L);
- internalCallContext.setCreatedDate(createdDate3);
- internalCallContext.setUpdatedDate(createdDate3);
paymentDao.insertPaymentWithFirstTransaction(paymentModelDao3, transaction3, internalCallContext);
// Right before createdBeforeDate but with a SUCCESS state so it should NOT be returned
final DateTime createdDate4 = createdBeforeDate.minusDays(1);
- final PaymentModelDao paymentModelDao4 = new PaymentModelDao(createdDate4, createdDate4, accountId, paymentMethodId, externalKey4);
+ clock.setTime(createdDate4);
+ account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+ final PaymentModelDao paymentModelDao4 = new PaymentModelDao(createdDate4, createdDate4, account.getId(), account.getPaymentMethodId(), externalKey4);
paymentModelDao4.setStateName("CAPTURE_SUCCESS");
final PaymentTransactionModelDao transaction4 = new PaymentTransactionModelDao(createdDate4, createdDate4, null, transactionExternalKey4,
paymentModelDao4.getId(), TransactionType.AUTHORIZE, createdDate4,
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- internalCallContext.setAccountRecordId(4L);
- internalCallContext.setCreatedDate(createdDate4);
- internalCallContext.setUpdatedDate(createdDate4);
paymentDao.insertPaymentWithFirstTransaction(paymentModelDao4, transaction4, internalCallContext);
// Right after createdBeforeDate, so it should NOT be returned
final DateTime createdDate5 = createdBeforeDate.plusDays(1);
- final PaymentModelDao paymentModelDao5 = new PaymentModelDao(createdDate5, createdDate5, accountId, paymentMethodId, externalKey5);
+ clock.setTime(createdDate5);
+ account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+ final PaymentModelDao paymentModelDao5 = new PaymentModelDao(createdDate5, createdDate5, account.getId(), account.getPaymentMethodId(), externalKey5);
paymentModelDao5.setStateName("CAPTURE_ERRORED");
final PaymentTransactionModelDao transaction5 = new PaymentTransactionModelDao(createdDate5, createdDate5, null, transactionExternalKey5,
paymentModelDao5.getId(), TransactionType.AUTHORIZE, createdDate5,
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- internalCallContext.setAccountRecordId(5L);
- internalCallContext.setCreatedDate(createdDate5);
- internalCallContext.setUpdatedDate(createdDate5);
paymentDao.insertPaymentWithFirstTransaction(paymentModelDao5, transaction5, internalCallContext);
final String[] errorStates = {"AUTH_ERRORED", "CAPTURE_ERRORED", "REFUND_ERRORED", "CREDIT_ERRORED"};
@@ -431,25 +423,26 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
}
@Test(groups = "slow")
- public void testPaginationForPaymentByStatesAcrossTenants() {
- // Right before createdAfterDate, so should not be returned
+ public void testPaginationForPaymentByStatesAcrossTenants() throws Exception {
final DateTime createdDate1 = clock.getUTCNow().minusHours(1);
+ clock.setTime(createdDate1);
+
+ final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
final int NB_ENTRIES = 30;
for (int i = 0; i < NB_ENTRIES; i++) {
- final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID().toString());
+ final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, account.getId(), account.getPaymentMethodId(), UUID.randomUUID().toString());
final PaymentTransactionModelDao transaction1 = new PaymentTransactionModelDao(createdDate1, createdDate1, null, UUID.randomUUID().toString(),
paymentModelDao1.getId(), TransactionType.AUTHORIZE, createdDate1,
TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
"unknown", "");
- internalCallContext.setAccountRecordId(1L);
- internalCallContext.setCreatedDate(createdDate1);
- internalCallContext.setUpdatedDate(createdDate1);
paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, internalCallContext);
}
- final Pagination<PaymentTransactionModelDao> result = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.UNKNOWN), clock.getUTCNow(), createdDate1, 0L, new Long(NB_ENTRIES));
+ clock.setTime(createdDate1.plusHours(1));
+
+ final Pagination<PaymentTransactionModelDao> result = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.UNKNOWN), clock.getUTCNow(), createdDate1, 0L, (long) NB_ENTRIES);
Assert.assertEquals(result.getTotalNbRecords(), new Long(NB_ENTRIES));
final Iterator<PaymentTransactionModelDao> iterator = result.iterator();
@@ -461,10 +454,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
}
@Test(groups = "slow")
- public void testPaymentAttemptsByStateAcrossTenants() {
-
- final UUID paymentMethodId = UUID.randomUUID();
- final UUID accountId = UUID.randomUUID();
+ public void testPaymentAttemptsByStateAcrossTenants() throws Exception {
final String externalKey1 = "gfhfg";
final String transactionExternalKey1 = "sadas";
@@ -477,42 +467,41 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final String stateName = "FOO";
final String pluginName = "miraculous";
- final PaymentAttemptModelDao attempt1 = new PaymentAttemptModelDao(accountId, paymentMethodId, createdAfterDate, createdAfterDate, externalKey1,
+ clock.setTime(createdAfterDate);
+ Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+ final PaymentAttemptModelDao attempt1 = new PaymentAttemptModelDao(account.getId(), account.getPaymentMethodId(), createdAfterDate, createdAfterDate, externalKey1,
UUID.randomUUID(), transactionExternalKey1, TransactionType.AUTHORIZE, stateName, BigDecimal.ONE, Currency.USD,
ImmutableList.<String>of(pluginName), null);
- final PaymentAttemptModelDao attempt2 = new PaymentAttemptModelDao(accountId, paymentMethodId, createdAfterDate, createdAfterDate, externalKey2,
+ paymentDao.insertPaymentAttemptWithProperties(attempt1, internalCallContext);
+
+ account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+ final PaymentAttemptModelDao attempt2 = new PaymentAttemptModelDao(account.getId(), account.getPaymentMethodId(), createdAfterDate, createdAfterDate, externalKey2,
UUID.randomUUID(), transactionExternalKey2, TransactionType.AUTHORIZE, stateName, BigDecimal.ONE, Currency.USD,
ImmutableList.<String>of(pluginName), null);
- internalCallContext.setAccountRecordId(1L);
- internalCallContext.setCreatedDate(createdAfterDate);
- internalCallContext.setUpdatedDate(createdAfterDate);
- paymentDao.insertPaymentAttemptWithProperties(attempt1, internalCallContext);
-
- internalCallContext.setAccountRecordId(2L);
- internalCallContext.setCreatedDate(createdAfterDate);
- internalCallContext.setUpdatedDate(createdAfterDate);
- paymentDao.insertPaymentAttemptWithProperties(attempt2, internalCallContext);
+ paymentDao.insertPaymentAttemptWithProperties(attempt2, internalCallContext);
final Pagination<PaymentAttemptModelDao> result = paymentDao.getPaymentAttemptsByStateAcrossTenants(stateName, createdBeforeDate, 0L, 2L);
Assert.assertEquals(result.getTotalNbRecords().longValue(), 2L);
}
@Test(groups = "slow")
- public void testUpdatePaymentAttempt() throws PluginPropertySerializerException {
+ public void testUpdatePaymentAttempt() throws Exception {
+ final DateTime createdAfterDate = clock.getUTCNow().minusDays(10);
+ clock.setTime(createdAfterDate);
+
+ final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
- final UUID paymentMethodId = UUID.randomUUID();
- final UUID accountId = UUID.randomUUID();
final String externalKey1 = "2354";
final String transactionExternalKey1 = "jkjkjk";
- final DateTime createdAfterDate = clock.getUTCNow().minusDays(10);
-
final String stateName = "RRRRR";
final String pluginName = "elated";
- final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, paymentMethodId, createdAfterDate, createdAfterDate, externalKey1,
+ final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), account.getPaymentMethodId(), createdAfterDate, createdAfterDate, externalKey1,
UUID.randomUUID(), transactionExternalKey1, TransactionType.AUTHORIZE, stateName, BigDecimal.ONE, Currency.USD,
ImmutableList.<String>of(pluginName), null);
@@ -530,7 +519,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
properties.add(new PluginProperty("prop1", "value1", false));
properties.add(new PluginProperty("prop2", "value2", false));
-
final byte [] serializedProperties = PluginPropertySerializer.serialize(properties);
paymentDao.updatePaymentAttemptWithProperties(rehydratedAttempt.getId(), transactionId, newStateName, serializedProperties, internalCallContext);
final PaymentAttemptModelDao attempt2 = paymentDao.getPaymentAttempt(rehydratedAttempt.getId(), internalCallContext);
@@ -540,7 +528,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final Iterable<PluginProperty> properties2 = PluginPropertySerializer.deserialize(attempt2.getPluginProperties());
checkProperty(properties2, new PluginProperty("prop1", "value1", false));
checkProperty(properties2, new PluginProperty("prop2", "value2", false));
-
}
private void checkProperty(final Iterable<PluginProperty> properties, final PluginProperty expected) {
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
index e52d7a3..0c47d84 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
@@ -148,12 +148,12 @@ public class TestPaymentHelper {
Account account;
if (isFastTest()) {
- account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountApi, accountInternalApi, immutableAccountInternalApi, nonEntityDao, internalCallContextFactory, context, internalCallContext);
+ account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountApi, accountInternalApi, immutableAccountInternalApi, nonEntityDao, clock, internalCallContextFactory, context, internalCallContext);
} else {
account = accountApi.createAccount(accountData, context);
}
- GuicyKillbillTestSuite.refreshCallContext(account.getId(), internalCallContextFactory, context, internalCallContext);
+ GuicyKillbillTestSuite.refreshCallContext(account.getId(), clock, internalCallContextFactory, context, internalCallContext);
if (addPaymentMethod) {
final PaymentMethodPlugin pm = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index a7354f3..9d0c003 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -512,7 +512,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
case START_BILLING:
final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
- final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? dryRunArguments.getEffectiveDate() : utcNow;
+ final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : utcNow;
final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, context);
final UUID subscriptionId = UUIDs.randomUUID();
dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, 1L, plan, inputSpec.getPhaseType(), realPriceList,
@@ -530,7 +530,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
case CHANGE:
final DefaultSubscriptionBase subscriptionForChange = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), context);
- DateTime changeEffectiveDate = dryRunArguments.getEffectiveDate();
+ DateTime changeEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : null;
if (changeEffectiveDate == null) {
BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
if (policy == null) {
@@ -547,7 +547,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
case STOP_BILLING:
final DefaultSubscriptionBase subscriptionForCancellation = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), context);
- DateTime cancelEffectiveDate = dryRunArguments.getEffectiveDate();
+ DateTime cancelEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : null;
if (dryRunArguments.getEffectiveDate() == null) {
BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
if (policy == null) {
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
index 2e9b743..badf00a 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
@@ -30,6 +30,7 @@ import org.killbill.billing.platform.test.config.TestKillbillConfigSource;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.clock.Clock;
import org.killbill.clock.ClockMock;
import org.skife.config.ConfigSource;
import org.slf4j.Logger;
@@ -103,6 +104,7 @@ public class GuicyKillbillTestSuite {
}
public static void refreshCallContext(final UUID accountId,
+ final Clock clock,
final InternalCallContextFactory internalCallContextFactory,
final TenantContext callContext,
final MutableInternalCallContext internalCallContext) {
@@ -110,10 +112,12 @@ public class GuicyKillbillTestSuite {
internalCallContext.setAccountRecordId(tmp.getAccountRecordId());
internalCallContext.setFixedOffsetTimeZone(tmp.getFixedOffsetTimeZone());
internalCallContext.setReferenceTime(tmp.getReferenceTime());
+ internalCallContext.setCreatedDate(clock.getUTCNow());
+ internalCallContext.setUpdatedDate(clock.getUTCNow());
}
protected void refreshCallContext(final UUID accountId) {
- refreshCallContext(accountId, internalCallContextFactory, callContext, internalCallContext);
+ refreshCallContext(accountId, clock, internalCallContextFactory, callContext, internalCallContext);
}
@BeforeMethod(alwaysRun = true)
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java
index 0abf3c0..cc2e479 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java
@@ -29,6 +29,7 @@ import org.killbill.billing.dao.MockNonEntityDao;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.clock.Clock;
import org.mockito.Mockito;
public class GuicyKillbillTestSuiteNoDB extends GuicyKillbillTestSuite {
@@ -38,6 +39,7 @@ public class GuicyKillbillTestSuiteNoDB extends GuicyKillbillTestSuite {
final AccountInternalApi accountInternalApi,
final ImmutableAccountInternalApi immutableAccountInternalApi,
final NonEntityDao nonEntityDao,
+ final Clock clock,
final InternalCallContextFactory internalCallContextFactory,
final CallContext callContext,
final MutableInternalCallContext internalCallContext) throws AccountApiException {
@@ -51,7 +53,7 @@ public class GuicyKillbillTestSuiteNoDB extends GuicyKillbillTestSuite {
((MockNonEntityDao) nonEntityDao).addTenantRecordIdMapping(account.getId(), internalCallContext);
((MockNonEntityDao) nonEntityDao).addAccountRecordIdMapping(account.getId(), internalCallContext);
- refreshCallContext(account.getId(), internalCallContextFactory, callContext, internalCallContext);
+ refreshCallContext(account.getId(), clock, internalCallContextFactory, callContext, internalCallContext);
return account;
}
diff --git a/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java b/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java
index 14d116d..49ecb00 100644
--- a/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java
+++ b/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java
@@ -23,11 +23,15 @@ import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.killbill.billing.account.api.Account;
+import org.killbill.billing.callcontext.TimeAwareContext;
import org.killbill.billing.mock.MockAccountBuilder;
import org.killbill.billing.util.UtilTestSuiteNoDB;
import org.killbill.billing.util.account.AccountDateTimeUtils;
+import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
+
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@@ -139,6 +143,50 @@ public class TestTimeAwareContext extends UtilTestSuiteNoDB {
assertEquals(internalCallContext.toLocalDate(dateTime3), new LocalDate("2015-11-30"));
}
+ @Test(groups = "fast")
+ public void testIdempotencyOfDatesManipulation() throws Exception {
+ final ImmutableList.Builder<DateTimeZone> dateTimeZoneBuilder = ImmutableList.<DateTimeZone>builder();
+ dateTimeZoneBuilder.add(DateTimeZone.forID("HST"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("PST8PDT"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("MST"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("CST6CDT"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("EST"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("Brazil/DeNoronha"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("UTC"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("CET"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("Europe/Istanbul"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("Singapore"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("Japan"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("Australia/Sydney"));
+ dateTimeZoneBuilder.add(DateTimeZone.forID("Pacific/Tongatapu"));
+ final Iterable<DateTimeZone> dateTimeZones = dateTimeZoneBuilder.build();
+
+ final ImmutableList.Builder<DateTime> referenceDateTimeBuilder = ImmutableList.<DateTime>builder();
+ referenceDateTimeBuilder.add(new DateTime(2012, 1, 1, 1, 1, 1, DateTimeZone.UTC));
+ referenceDateTimeBuilder.add(new DateTime(2012, 3, 15, 12, 42, 0, DateTimeZone.forID("PST8PDT")));
+ referenceDateTimeBuilder.add(new DateTime(2012, 11, 15, 12, 42, 0, DateTimeZone.forID("PST8PDT")));
+ final Iterable<DateTime> referenceDateTimes = referenceDateTimeBuilder.build();
+
+ DateTime currentDateTime = new DateTime(2015, 1, 1, 1, 1, DateTimeZone.UTC);
+ final DateTime endDateTime = new DateTime(2020, 1, 1, 1, 1, DateTimeZone.UTC);
+ while (currentDateTime.compareTo(endDateTime) <= 0) {
+ for (final DateTimeZone dateTimeZone : dateTimeZones) {
+ for (final DateTime referenceDateTime : referenceDateTimes) {
+ final TimeAwareContext timeAwareContext = new TimeAwareContext(dateTimeZone, referenceDateTime);
+
+ final LocalDate computedLocalDate = timeAwareContext.toLocalDate(currentDateTime);
+ final DateTime computedDateTime = timeAwareContext.toUTCDateTime(computedLocalDate);
+ final LocalDate computedLocalDate2 = timeAwareContext.toLocalDate(computedDateTime);
+
+ final String msg = String.format("currentDateTime=%s, localDate=%s, dateTime=%s, dateTimeZone=%s, referenceDateTime=%s", currentDateTime, computedLocalDate, computedDateTime, dateTimeZone, referenceDateTime);
+ Assert.assertEquals(computedLocalDate2, computedLocalDate, msg);
+ }
+ }
+
+ currentDateTime = currentDateTime.plusHours(1);
+ }
+ }
+
private void refreshCallContext(final DateTime effectiveDateTime, final DateTimeZone timeZone) {
final Account account = new MockAccountBuilder().timeZone(timeZone)
.createdDate(effectiveDateTime)