killbill-memoizeit
Changes
entitlement/src/main/java/com/ning/billing/entitlement/engine/core/DefaultEventsStream.java 5(+5 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java 39(+35 -4)
pom.xml 2(+1 -1)
Details
diff --git a/api/src/main/java/com/ning/billing/entitlement/EventsStream.java b/api/src/main/java/com/ning/billing/entitlement/EventsStream.java
index b570fd3..8cb930f 100644
--- a/api/src/main/java/com/ning/billing/entitlement/EventsStream.java
+++ b/api/src/main/java/com/ning/billing/entitlement/EventsStream.java
@@ -60,6 +60,8 @@ public interface EventsStream {
Collection<BlockingState> getPendingEntitlementCancellationEvents();
+ BlockingState getEntitlementCancellationEvent();
+
// All blocking states for the account, associated bundle or subscription
Collection<BlockingState> getBlockingStates();
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
index ac479f7..5576a98 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
@@ -289,15 +289,28 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// Get the latest state from disk
refresh(callContext);
- if (eventsStream.isEntitlementCancelled() || eventsStream.isSubscriptionCancelled()) {
+ if (eventsStream.isSubscriptionCancelled()) {
throw new EntitlementApiException(ErrorCode.SUB_CANCEL_BAD_STATE, getId(), EntitlementState.CANCELLED);
}
- // Reactivate entitlements
- // See also https://github.com/killbill/killbill/issues/111
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(getAccountId(), callContext);
- for (final BlockingState futureCancellation : eventsStream.getPendingEntitlementCancellationEvents()) {
- blockingStateDao.unactiveBlockingState(futureCancellation.getId(), contextWithValidAccountRecordId);
+ final Collection<BlockingState> pendingEntitlementCancellationEvents = eventsStream.getPendingEntitlementCancellationEvents();
+ if (eventsStream.isEntitlementCancelled()) {
+ final BlockingState cancellationEvent = eventsStream.getEntitlementCancellationEvent();
+ blockingStateDao.unactiveBlockingState(cancellationEvent.getId(), contextWithValidAccountRecordId);
+ } else if (pendingEntitlementCancellationEvents.size() > 0) {
+ // Reactivate entitlements
+ // See also https://github.com/killbill/killbill/issues/111
+ //
+ // Today we only support cancellation at SUBSCRIPTION level (Not ACCOUNT or BUNDLE), so we should really have only
+ // one future event in the list
+ //
+ for (final BlockingState futureCancellation : pendingEntitlementCancellationEvents) {
+ blockingStateDao.unactiveBlockingState(futureCancellation.getId(), contextWithValidAccountRecordId);
+ }
+ } else {
+ // Entitlement is NOT cancelled (or future cancelled), there is nothing to do
+ throw new EntitlementApiException(ErrorCode.SUB_CANCEL_BAD_STATE, getId(), EntitlementState.CANCELLED);
}
// If billing was previously cancelled, reactivate
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/DefaultEventsStream.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/DefaultEventsStream.java
index 7a735cb..1b28830 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/DefaultEventsStream.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/DefaultEventsStream.java
@@ -190,6 +190,11 @@ public class DefaultEventsStream implements EventsStream {
return getPendingEntitlementEvents(DefaultEntitlementApi.ENT_STATE_CANCELLED);
}
+ @Override
+ public BlockingState getEntitlementCancellationEvent() {
+ return entitlementCancelEvent;
+ }
+
public Collection<BlockingState> getPendingEntitlementEvents(final String... types) {
final List<String> typeList = ImmutableList.<String>copyOf(types);
return Collections2.<BlockingState>filter(subscriptionEntitlementStates,
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
index e2ff2d8..caa7178 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -62,15 +62,12 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
testListener.pushExpectedEvent(NextEvent.CREATE);
final Entitlement addOnEntitlement = entitlementApi.addEntitlement(entitlement.getBundleId(), addOnSpec, initialDate, callContext);
assertListenerStatus();
-
- /*
- // TODO It looks like we don't check if there is a future cancellation. Maybe we should?
try {
entitlement.uncancelEntitlement(callContext);
Assert.fail("Entitlement hasn't been cancelled yet");
} catch (final EntitlementApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.SUB_CANCEL_BAD_STATE.getCode());
- }*/
+ }
clock.addDays(3);
@@ -108,6 +105,40 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
}
}
+
+ @Test(groups = "slow")
+ public void testUncancelEffectiveCancelledEntitlement() throws AccountApiException, EntitlementApiException {
+ final LocalDate initialDate = new LocalDate(2013, 8, 7);
+ clock.setDay(initialDate);
+
+ final Account account = accountApi.createAccount(getAccountData(7), callContext);
+
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+ // Keep the same object for the whole test, to make sure we refresh its state before r/w calls
+ testListener.pushExpectedEvent(NextEvent.CREATE);
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), initialDate, callContext);
+ assertListenerStatus();
+
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ clock.addDays(30);
+ assertListenerStatus();
+ subscriptionInternalApi.setChargedThroughDate(entitlement.getId(), clock.getUTCNow().plusMonths(1), internalCallContext);
+
+ final LocalDate entitlementCancelledDate = clock.getToday(account.getTimeZone());
+ testListener.pushExpectedEvent(NextEvent.BLOCK);
+ final Entitlement cancelledEntitlement = entitlement.cancelEntitlementWithDateOverrideBillingPolicy(clock.getToday(account.getTimeZone()), BillingActionPolicy.END_OF_TERM, callContext);
+ assertListenerStatus();
+ Assert.assertEquals(cancelledEntitlement.getEffectiveEndDate(), entitlementCancelledDate);
+
+ testListener.pushExpectedEvent(NextEvent.UNCANCEL);
+ cancelledEntitlement.uncancelEntitlement(callContext);
+ assertListenerStatus();
+
+ final Entitlement reactivatedEntitlement = entitlementApi.getEntitlementForId(cancelledEntitlement.getId(), callContext);
+ Assert.assertNull(reactivatedEntitlement.getEffectiveEndDate());
+ }
+
@Test(groups = "slow")
public void testCreateEntitlementWithCheck() throws AccountApiException, EntitlementApiException {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java
index 2117962..6f27ece 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -46,9 +46,10 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final Account account = accountApi.createAccount(getAccountData(7), callContext);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.BLOCK);
- // Hardcode the UUIDs to have a predictable ordering
- final Entitlement entitlement1 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.fromString("a87c78b4-c6de-4387-8a3b-4a5850dc29fc").toString(), initialDate, callContext);
- final Entitlement entitlement2 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.fromString("b56245e7-11a5-4a41-8854-3d31e24bcdcc").toString(), initialDate, callContext);
+ final Entitlement entitlement1 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), initialDate, callContext);
+ // Sleep 1 sec so created date are apparts from each other and ordering in the bundle does not default on the UUID which is random.
+ try {Thread.sleep(1000); } catch (InterruptedException ignore) {};
+ final Entitlement entitlement2 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), initialDate, callContext);
entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, "stateName", "service", false, false, false, clock.getUTCNow()),
internalCallContextFactory.createInternalCallContext(account.getId(), callContext));
assertListenerStatus();
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index 506278a..2c94cb9 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -169,11 +169,11 @@ public class InvoiceDispatcher {
// 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, context);
- final Account account = accountApi.getAccountById(accountId, context);
+ final Account account = accountApi.getAccountById(accountId, context);
final DateAndTimeZoneContext dateAndTimeZoneContext = billingEvents.iterator().hasNext() ?
new DateAndTimeZoneContext(billingEvents.iterator().next().getEffectiveDate(), account.getTimeZone(), clock) :
- new DateAndTimeZoneContext(null, account.getTimeZone(), clock);
+ null;
List<Invoice> invoices = new ArrayList<Invoice>();
@@ -189,8 +189,8 @@ public class InvoiceDispatcher {
final Currency targetCurrency = account.getCurrency();
- final LocalDate targetDate = dateAndTimeZoneContext.computeTargetDate(targetDateTime);
- final Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoices, targetDate, targetCurrency);
+ final LocalDate targetDate = dateAndTimeZoneContext != null ? dateAndTimeZoneContext.computeTargetDate(targetDateTime) : null;
+ final Invoice invoice = targetDate != null ? generator.generateInvoice(accountId, billingEvents, invoices, targetDate, targetCurrency) : null;
if (invoice == null) {
log.info("Generated null invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
if (!dryRun) {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index 03d7450..728bcce 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -194,7 +194,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
final LocalDate endDate = new LocalDate("2012-11-26");
- ((ClockMock) clock).setTime(new DateTime(2012, 10, 26, 1, 12, 23, DateTimeZone.UTC));
+ ((ClockMock) clock).setTime(new DateTime(2012, 10, 13, 1, 12, 23, DateTimeZone.UTC));
final DateAndTimeZoneContext dateAndTimeZoneContext = new DateAndTimeZoneContext(clock.getUTCNow(), DateTimeZone.forID("Pacific/Pitcairn"), clock);
@@ -217,10 +217,6 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
final LocalDate receivedTargetDate = new LocalDate(receivedDate, DateTimeZone.forID("Pacific/Pitcairn"));
Assert.assertEquals(receivedTargetDate, endDate);
- Assert.assertTrue(receivedDate.compareTo(new DateTime(2012, 11, 26, 9 /* 1 + 8 for Pitcairn */, 12, 23, DateTimeZone.UTC)) >= 0);
- Assert.assertTrue(receivedDate.compareTo(new DateTime(2012, 11, 26, 9, 13, 0, DateTimeZone.UTC)) <= 0);
-
+ Assert.assertTrue(receivedDate.compareTo(new DateTime(2012, 11, 27, 1, 12, 23, DateTimeZone.UTC)) <= 0);
}
-
- //MDW add a test to cover when the account auto-invoice-off tag is present
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/RefundJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/RefundJson.java
index 73a83dd..1c17625 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/RefundJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/RefundJson.java
@@ -42,6 +42,7 @@ public class RefundJson extends JsonBase {
private final Boolean isAdjusted;
private final DateTime requestedDate;
private final DateTime effectiveDate;
+ private final String status;
private final List<InvoiceItemJson> adjustments;
@JsonCreator
@@ -49,6 +50,7 @@ public class RefundJson extends JsonBase {
@JsonProperty("paymentId") final String paymentId,
@JsonProperty("amount") final BigDecimal amount,
@JsonProperty("currency") final String currency,
+ @JsonProperty("status") final String status,
@JsonProperty("adjusted") final Boolean isAdjusted,
@JsonProperty("requestedDate") final DateTime requestedDate,
@JsonProperty("effectiveDate") final DateTime effectiveDate,
@@ -59,6 +61,7 @@ public class RefundJson extends JsonBase {
this.paymentId = paymentId;
this.amount = amount;
this.currency = currency;
+ this.status = status;
this.isAdjusted = isAdjusted;
this.requestedDate = requestedDate;
this.effectiveDate = effectiveDate;
@@ -71,7 +74,7 @@ public class RefundJson extends JsonBase {
public RefundJson(final Refund refund, @Nullable final List<InvoiceItem> adjustments, @Nullable final List<AuditLog> auditLogs) {
this(refund.getId().toString(), refund.getPaymentId().toString(), refund.getRefundAmount(), refund.getCurrency().toString(),
- refund.isAdjusted(), refund.getEffectiveDate(), refund.getEffectiveDate(),
+ refund.getRefundStatus().toString(), refund.isAdjusted(), refund.getEffectiveDate(), refund.getEffectiveDate(),
adjustments == null ? null : ImmutableList.<InvoiceItemJson>copyOf(Collections2.transform(adjustments, new Function<InvoiceItem, InvoiceItemJson>() {
@Override
public InvoiceItemJson apply(@Nullable final InvoiceItem input) {
@@ -113,6 +116,8 @@ public class RefundJson extends JsonBase {
return adjustments;
}
+ public String getStatus() { return status; }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
@@ -121,6 +126,7 @@ public class RefundJson extends JsonBase {
sb.append(", paymentId='").append(paymentId).append('\'');
sb.append(", amount=").append(amount);
sb.append(", currency=").append(currency);
+ sb.append(", status=").append(status);
sb.append(", isAdjusted=").append(isAdjusted);
sb.append(", requestedDate=").append(requestedDate);
sb.append(", effectiveDate=").append(effectiveDate);
@@ -135,6 +141,7 @@ public class RefundJson extends JsonBase {
result = 31 * result + (paymentId != null ? paymentId.hashCode() : 0);
result = 31 * result + (amount != null ? amount.hashCode() : 0);
result = 31 * result + (currency != null ? currency.hashCode() : 0);
+ result = 31 * result + (status != null ? status.hashCode() : 0);
result = 31 * result + (isAdjusted != null ? isAdjusted.hashCode() : 0);
result = 31 * result + (requestedDate != null ? requestedDate.hashCode() : 0);
result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
@@ -222,6 +229,14 @@ public class RefundJson extends JsonBase {
return false;
}
+ if (status == null) {
+ if (other.status != null) {
+ return false;
+ }
+ } else if (!status.equals(other.status)) {
+ return false;
+ }
+
if (adjustments == null) {
if (other.adjustments != null) {
return false;
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestRefundJson.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestRefundJson.java
index 544c23d..6e4e71a 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestRefundJson.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestRefundJson.java
@@ -27,6 +27,7 @@ import org.testng.annotations.Test;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.jaxrs.JaxrsTestSuiteNoDB;
+import com.ning.billing.payment.api.RefundStatus;
import com.google.common.collect.ImmutableList;
@@ -43,9 +44,10 @@ public class TestRefundJson extends JaxrsTestSuiteNoDB {
final boolean isAdjusted = true;
final DateTime requestedDate = clock.getUTCNow();
final DateTime effectiveDate = clock.getUTCNow();
+ final RefundStatus status = RefundStatus.COMPLETED;
final List<InvoiceItemJson> adjustments = ImmutableList.<InvoiceItemJson>of(createInvoiceItemJson());
final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
- final RefundJson refundJson = new RefundJson(refundId, paymentId, amount, currency, isAdjusted, requestedDate,
+ final RefundJson refundJson = new RefundJson(refundId, paymentId, amount, currency, status.toString(), isAdjusted, requestedDate,
effectiveDate, adjustments, auditLogs);
Assert.assertEquals(refundJson.getRefundId(), refundId);
Assert.assertEquals(refundJson.getPaymentId(), paymentId);
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
index 37bde5f..23a067b 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
@@ -27,12 +27,11 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.entity.EntityBase;
import com.ning.billing.payment.dao.PaymentAttemptModelDao;
import com.ning.billing.payment.dao.PaymentModelDao;
import com.ning.billing.payment.dao.RefundModelDao;
-import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
-import com.ning.billing.entity.EntityBase;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
index 54f99e0..9349504 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
@@ -24,8 +24,8 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
import com.ning.billing.entity.EntityBase;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
public class DefaultRefund extends EntityBase implements Refund {
@@ -34,16 +34,18 @@ public class DefaultRefund extends EntityBase implements Refund {
private final Currency currency;
private final boolean isAdjusted;
private final DateTime effectiveDate;
+ private final RefundStatus refundStatus;
public DefaultRefund(final UUID id, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
final UUID paymentId, final BigDecimal amount,
- final Currency currency, final boolean isAdjusted, final DateTime effectiveDate) {
+ final Currency currency, final boolean isAdjusted, final DateTime effectiveDate, final RefundStatus refundStatus) {
super(id, createdDate, updatedDate);
this.paymentId = paymentId;
this.amount = amount;
this.currency = currency;
this.isAdjusted = isAdjusted;
this.effectiveDate = effectiveDate;
+ this.refundStatus = refundStatus;
}
@Override
@@ -72,6 +74,11 @@ public class DefaultRefund extends EntityBase implements Refund {
}
@Override
+ public RefundStatus getRefundStatus() {
+ return refundStatus;
+ }
+
+ @Override
public RefundInfoPlugin getPluginDetail() {
// TODO not implemented
return null;
@@ -85,6 +92,7 @@ public class DefaultRefund extends EntityBase implements Refund {
sb.append(", amount=").append(amount);
sb.append(", currency=").append(currency);
sb.append(", isAdjusted=").append(isAdjusted);
+ sb.append(", status=").append(refundStatus);
sb.append(", effectiveDate=").append(effectiveDate);
sb.append('}');
return sb.toString();
@@ -113,6 +121,9 @@ public class DefaultRefund extends EntityBase implements Refund {
if (currency != that.currency) {
return false;
}
+ if (refundStatus != that.refundStatus) {
+ return false;
+ }
if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) {
return false;
}
@@ -125,6 +136,7 @@ public class DefaultRefund extends EntityBase implements Refund {
int result = paymentId != null ? paymentId.hashCode() : 0;
result = 31 * result + (amount != null ? amount.hashCode() : 0);
result = 31 * result + (currency != null ? currency.hashCode() : 0);
+ result = 31 * result + (refundStatus != null ? refundStatus.hashCode() : 0);
result = 31 * result + (isAdjusted ? 1 : 0);
result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
return result;
diff --git a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
index 7eab0e9..a3fe237 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
@@ -43,10 +43,10 @@ import com.ning.billing.osgi.api.OSGIServiceRegistration;
import com.ning.billing.payment.api.DefaultRefund;
import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.Refund;
+import com.ning.billing.payment.api.RefundStatus;
import com.ning.billing.payment.dao.PaymentDao;
import com.ning.billing.payment.dao.PaymentModelDao;
import com.ning.billing.payment.dao.RefundModelDao;
-import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
import com.ning.billing.payment.plugin.api.PaymentPluginApi;
import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
@@ -136,7 +136,7 @@ public class RefundProcessor extends ProcessorBase {
return new DefaultRefund(refundInfo.getId(), refundInfo.getCreatedDate(), refundInfo.getUpdatedDate(),
paymentId, refundInfo.getAmount(), account.getCurrency(),
- isAdjusted, refundInfo.getCreatedDate());
+ isAdjusted, refundInfo.getCreatedDate(), RefundStatus.COMPLETED);
} else {
paymentDao.updateRefundStatus(refundInfo.getId(), RefundStatus.PLUGIN_ERRORED, refundAmount, account.getCurrency(), context);
throw new PaymentPluginApiException("Refund error for RefundInfo: " + refundInfo.toString(),
@@ -208,7 +208,7 @@ public class RefundProcessor extends ProcessorBase {
}
return new DefaultRefund(result.getId(), result.getCreatedDate(), result.getUpdatedDate(),
result.getPaymentId(), result.getAmount(), result.getCurrency(),
- result.isAdjusted(), result.getCreatedDate());
+ result.isAdjusted(), result.getCreatedDate(), result.getRefundStatus());
}
public List<Refund> getAccountRefunds(final Account account, final InternalTenantContext context)
@@ -237,7 +237,7 @@ public class RefundProcessor extends ProcessorBase {
public Refund apply(final RefundModelDao cur) {
return new DefaultRefund(cur.getId(), cur.getCreatedDate(), cur.getUpdatedDate(),
cur.getPaymentId(), cur.getAmount(), cur.getCurrency(),
- cur.isAdjusted(), cur.getCreatedDate());
+ cur.isAdjusted(), cur.getCreatedDate(), cur.getRefundStatus());
}
}));
}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
index ca5509a..ccc0e17 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
@@ -32,7 +32,7 @@ import com.ning.billing.catalog.api.Currency;
import com.ning.billing.clock.Clock;
import com.ning.billing.entity.EntityPersistenceException;
import com.ning.billing.payment.api.PaymentStatus;
-import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.payment.api.RefundStatus;
import com.ning.billing.util.cache.CacheControllerDispatcher;
import com.ning.billing.util.dao.NonEntityDao;
import com.ning.billing.util.entity.DefaultPagination;
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
index 575e6ca..2c2e76e 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
@@ -20,13 +20,11 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
-import org.joda.time.DateTime;
-
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.payment.api.PaymentStatus;
-import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
import com.ning.billing.callcontext.InternalCallContext;
import com.ning.billing.callcontext.InternalTenantContext;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.api.PaymentStatus;
+import com.ning.billing.payment.api.RefundStatus;
import com.ning.billing.util.entity.Pagination;
public interface PaymentDao {
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
index eb4d052..b66fd95 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
@@ -24,9 +24,10 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.entity.EntityBase;
import com.ning.billing.payment.api.Refund;
+import com.ning.billing.payment.api.RefundStatus;
import com.ning.billing.util.dao.TableName;
-import com.ning.billing.entity.EntityBase;
import com.ning.billing.util.entity.dao.EntityModelDao;
public class RefundModelDao extends EntityBase implements EntityModelDao<Refund> {
@@ -100,13 +101,6 @@ public class RefundModelDao extends EntityBase implements EntityModelDao<Refund>
return isAdjusted;
}
- public enum RefundStatus {
- CREATED,
- PLUGIN_COMPLETED,
- COMPLETED,
- PLUGIN_ERRORED
- }
-
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
index fc75d31..2a245c6 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
@@ -30,7 +30,7 @@ import com.ning.billing.callcontext.InternalCallContext;
import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.payment.api.PaymentStatus;
-import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.payment.api.RefundStatus;
import com.ning.billing.util.entity.Pagination;
import com.google.common.collect.ImmutableList;
@@ -186,6 +186,7 @@ public class MockPaymentDao implements PaymentDao {
return null;
}
+
@Override
public void updateRefundStatus(final UUID refundId, final RefundStatus status, final BigDecimal processedAmount, final Currency processedCurrency, final InternalCallContext context) {
return;
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index 70033b8..49717e9 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -27,13 +27,12 @@ import org.testng.annotations.Test;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.payment.PaymentTestSuiteWithEmbeddedDB;
import com.ning.billing.payment.api.PaymentStatus;
-import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.payment.api.RefundStatus;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
@@ -205,7 +204,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(lastPayment.getEffectiveDate().compareTo(effectiveDate), 0);
assertEquals(lastPayment.getPaymentStatus(), PaymentStatus.UNKNOWN);
-
clock.addDays(3);
final DateTime newEffectiveDate = clock.getUTCNow();
final UUID newPaymentMethodId = UUID.randomUUID();
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index 3453a84..220af20 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.5.6</version>
+ <version>0.5.7</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.8.5-SNAPSHOT</version>
diff --git a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
index baecbc6..5126a79 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
@@ -59,6 +59,7 @@ import com.ning.billing.jaxrs.json.RefundJson;
import com.ning.billing.jaxrs.json.SubscriptionJson;
import com.ning.billing.jaxrs.json.TenantJson;
import com.ning.billing.jaxrs.resources.JaxrsResource;
+import com.ning.billing.payment.api.RefundStatus;
import com.ning.billing.util.api.AuditLevel;
import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient;
@@ -370,13 +371,11 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
assertEquals(fifthResponse.getStatusCode(), javax.ws.rs.core.Response.Status.OK.getStatusCode());
}
-
-
protected SubscriptionJson createEntitlement(final String accountId, final String bundleExternalKey, final String productName, final String productCategory, final String billingPeriod, final boolean waitCompletion) throws Exception {
- final SubscriptionJson input = new SubscriptionJson(accountId, null, null, bundleExternalKey, null ,productName, productCategory,
- billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null, null, null, null, null,
- null, null, null);
+ final SubscriptionJson input = new SubscriptionJson(accountId, null, null, bundleExternalKey, null, productName, productCategory,
+ billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null, null, null, null, null,
+ null, null, null);
String baseJson = mapper.writeValueAsString(input);
final Map<String, String> queryParams = waitCompletion ? getQueryParamsForCallCompletion("5") : DEFAULT_EMPTY_QUERY;
@@ -542,25 +541,25 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
}
final InvoiceItemJson adjustment = new InvoiceItemJson(invoiceItemId, null, null, accountId, null, null, null, null,
- null, null, null, null, amount, currency, null);
+ null, null, null, null, amount, currency, null);
final String adjustmentJson = mapper.writeValueAsString(adjustment);
final Response response = doPost(uri, adjustmentJson, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
}
protected InvoiceJson createExternalCharge(final String accountId, final BigDecimal amount, @Nullable final String bundleId,
- @Nullable final Currency currency, @Nullable final DateTime requestedDate, final Boolean autoPay) throws Exception {
+ @Nullable final Currency currency, @Nullable final DateTime requestedDate, final Boolean autoPay) throws Exception {
return doCreateExternalCharge(accountId, null, bundleId, amount, currency, requestedDate, autoPay, JaxrsResource.CHARGES_PATH);
}
protected InvoiceJson createExternalChargeForInvoice(final String accountId, final String invoiceId, @Nullable final String bundleId, final BigDecimal amount,
- @Nullable final Currency currency, @Nullable final DateTime requestedDate, final Boolean autoPay) throws Exception {
+ @Nullable final Currency currency, @Nullable final DateTime requestedDate, final Boolean autoPay) throws Exception {
final String uri = JaxrsResource.INVOICES_PATH + "/" + invoiceId + "/" + JaxrsResource.CHARGES;
return doCreateExternalCharge(accountId, invoiceId, bundleId, amount, currency, requestedDate, autoPay, uri);
}
private InvoiceJson doCreateExternalCharge(final String accountId, @Nullable final String invoiceId, @Nullable final String bundleId, @Nullable final BigDecimal amount,
- @Nullable final Currency currency, final DateTime requestedDate, final Boolean autoPay, final String uri) throws IOException {
+ @Nullable final Currency currency, final DateTime requestedDate, final Boolean autoPay, final String uri) throws IOException {
final Map<String, String> queryParams = new HashMap<String, String>();
if (requestedDate != null) {
queryParams.put(JaxrsResource.QUERY_REQUESTED_DT, requestedDate.toDateTimeISO().toString());
@@ -570,7 +569,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
}
final InvoiceItemJson externalCharge = new InvoiceItemJson(null, invoiceId, null, accountId, bundleId, null, null, null,
- null, null, null, null, amount, currency, null);
+ null, null, null, null, amount, currency, null);
final String externalChargeJson = mapper.writeValueAsString(externalCharge);
final Response response = doPost(uri, externalChargeJson, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
@@ -691,7 +690,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
protected void payAllInvoices(final AccountJson accountJson, final Boolean externalPayment) throws IOException {
final PaymentJson payment = new PaymentJson(null, null, accountJson.getAccountId(), null, null, null, null,
- null, null, 0, null, null, null, null, null, null, null, null);
+ null, null, 0, null, null, null, null, null, null, null, null);
final String postJson = mapper.writeValueAsString(payment);
final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.PAYMENTS;
@@ -700,7 +699,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
protected List<PaymentJson> createInstaPayment(final AccountJson accountJson, final InvoiceJson invoice) throws IOException {
final PaymentJson payment = new PaymentJson(invoice.getAmount(), BigDecimal.ZERO, accountJson.getAccountId(),
- invoice.getInvoiceId(), null, null, null, null, null, 0, null, null, null, null, null, null, null, null);
+ invoice.getInvoiceId(), null, null, null, null, null, 0, null, null, null, null, null, null, null, null);
final String postJson = mapper.writeValueAsString(payment);
final String uri = JaxrsResource.INVOICES_PATH + "/" + invoice.getInvoiceId() + "/" + JaxrsResource.PAYMENTS;
@@ -711,8 +710,8 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
protected List<PaymentJson> createExternalPayment(final AccountJson accountJson, final String invoiceId, final BigDecimal paidAmount) throws IOException {
final PaymentJson payment = new PaymentJson(paidAmount, BigDecimal.ZERO, accountJson.getAccountId(),
- invoiceId, null, null, null, null, null, 0,
- null, null, null, null, null, null, null, null);
+ invoiceId, null, null, null, null, null, 0,
+ null, null, null, null, null, null, null, null);
final String postJson = mapper.writeValueAsString(payment);
final String paymentURI = JaxrsResource.INVOICES_PATH + "/" + invoiceId + "/" + JaxrsResource.PAYMENTS;
@@ -791,9 +790,9 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
final List<InvoiceItemJson> adjustments = new ArrayList<InvoiceItemJson>();
for (final String itemId : itemAdjustments.keySet()) {
adjustments.add(new InvoiceItemJson(itemId, null, null, null, null, null, null, null, null, null, null, null,
- itemAdjustments.get(itemId), null, null));
+ itemAdjustments.get(itemId), null, null));
}
- final RefundJson refundJson = new RefundJson(null, paymentId, amount, DEFAULT_CURRENCY, adjusted, null, null, adjustments, null);
+ final RefundJson refundJson = new RefundJson(null, paymentId, amount, DEFAULT_CURRENCY, RefundStatus.COMPLETED.toString(), adjusted, null, null, adjustments, null);
final String baseJson = mapper.writeValueAsString(refundJson);
final Response response = doPost(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
@@ -867,7 +866,6 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
// OVERDUE
//
-
protected OverdueStateJson getOverdueStateForAccount(final String accountId) throws Exception {
final String overdueURI = JaxrsResource.ACCOUNTS_PATH + "/" + accountId + "/" + OVERDUE;
final Response overdueResponse = doGet(overdueURI, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java b/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java
index 01200d6..321903c 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java
@@ -30,6 +30,7 @@ import com.ning.billing.jaxrs.json.InvoiceJson;
import com.ning.billing.jaxrs.json.PaymentJson;
import com.ning.billing.jaxrs.json.PaymentMethodJson;
import com.ning.billing.jaxrs.json.RefundJson;
+import com.ning.billing.payment.api.RefundStatus;
public class TestPayment extends TestJaxrsBase {
@@ -177,6 +178,7 @@ public class TestPayment extends TestJaxrsBase {
Assert.assertEquals(refundJsonCheck.getPaymentId(), paymentJson.getPaymentId());
Assert.assertEquals(refundJsonCheck.getAmount().setScale(2, RoundingMode.HALF_UP), refundAmount.setScale(2, RoundingMode.HALF_UP));
Assert.assertEquals(refundJsonCheck.getCurrency(), DEFAULT_CURRENCY);
+ Assert.assertEquals(refundJsonCheck.getStatus(), RefundStatus.COMPLETED.toString());
Assert.assertEquals(refundJsonCheck.getEffectiveDate().getYear(), clock.getUTCNow().getYear());
Assert.assertEquals(refundJsonCheck.getEffectiveDate().getMonthOfYear(), clock.getUTCNow().getMonthOfYear());
Assert.assertEquals(refundJsonCheck.getEffectiveDate().getDayOfMonth(), clock.getUTCNow().getDayOfMonth());
diff --git a/util/src/main/java/com/ning/billing/util/timezone/DateAndTimeZoneContext.java b/util/src/main/java/com/ning/billing/util/timezone/DateAndTimeZoneContext.java
index b9e60b1..c96a9f1 100644
--- a/util/src/main/java/com/ning/billing/util/timezone/DateAndTimeZoneContext.java
+++ b/util/src/main/java/com/ning/billing/util/timezone/DateAndTimeZoneContext.java
@@ -18,6 +18,7 @@ package com.ning.billing.util.timezone;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
+import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
@@ -31,6 +32,7 @@ import com.ning.billing.clock.Clock;
public final class DateAndTimeZoneContext {
private final LocalTime referenceTime;
+ private final int offsetFromUtc;
private final DateTimeZone accountTimeZone;
private final Clock clock;
@@ -38,6 +40,13 @@ public final class DateAndTimeZoneContext {
this.clock = clock;
this.referenceTime = effectiveDateTime != null ? effectiveDateTime.toLocalTime() : null;
this.accountTimeZone = accountTimeZone;
+ this.offsetFromUtc = computeOffsetFromUtc(effectiveDateTime, accountTimeZone);
+ }
+
+ static int computeOffsetFromUtc(final DateTime effectiveDateTime, final DateTimeZone accountTimeZone) {
+ final LocalDate localDateInAccountTimeZone = new LocalDate(effectiveDateTime, accountTimeZone);
+ final LocalDate localDateInUTC = new LocalDate(effectiveDateTime, DateTimeZone.UTC);
+ return Days.daysBetween(localDateInUTC, localDateInAccountTimeZone).getDays();
}
public LocalDate computeTargetDate(final DateTime targetDateTime) {
@@ -50,9 +59,9 @@ public final class DateAndTimeZoneContext {
// Since we create the targetDate for next invoice using the date from the notificationQ, we need to make sure
// that this datetime once transformed into a LocalDate points to the correct day.
//
- // e.g If accountTimeZone is -8 and we want to invoice on the 16, with a toDateTimeAtCurrentTime = 00:00:23,
- // we will generate a datetime that is 16T08:00:23 => LocalDate in that timeZone stays on the 16.
- //
+ // All we need to do is figure is the transformation from DateTime (point in time) to LocalDate (date in account time zone)
+ // changed the day; if so, when we recompute a UTC date from LocalDate (date in account time zone), we can simply chose a reference
+ // time and apply the offset backward to end up on the right day
//
// We use clock.getUTCNow() to get the offset with account timezone but that may not be correct
// when we transition from standard time and daylight saving time. We could end up with a result
@@ -60,9 +69,7 @@ public final class DateAndTimeZoneContext {
// We will fix that by re-inserting ourselves in the notificationQ if we detect that there is no invoice
// and yet the subscription is recurring and not cancelled.
//
- final int utcOffest = accountTimeZone.getOffset(clock.getUTCNow());
- final int localToUTCOffest = -1 * utcOffest;
- return invoiceItemEndDate.toDateTime(referenceTime, DateTimeZone.UTC).plusMillis(localToUTCOffest);
+ return invoiceItemEndDate.toDateTime(referenceTime, DateTimeZone.UTC).plusDays(-offsetFromUtc);
}
public DateTime computeUTCDateTimeFromNow() {
diff --git a/util/src/test/java/com/ning/billing/util/timezone/TestDateAndTimeZoneContext.java b/util/src/test/java/com/ning/billing/util/timezone/TestDateAndTimeZoneContext.java
new file mode 100644
index 0000000..f73a120
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/timezone/TestDateAndTimeZoneContext.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2010-2013 Ning, 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 com.ning.billing.util.timezone;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.UtilTestSuiteNoDB;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+//
+// There are two categories of tests, one that test the offset calculation and one that calculates
+// how to get a DateTime from a LocalDate (in account time zone)
+//
+// Tests {1, 2, 3} use an account timezone with a negative offset (-8) and tests {A, B, C} use an account timezone with a positive offset (+8)
+//
+public class TestDateAndTimeZoneContext extends UtilTestSuiteNoDB {
+
+ private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTimeParser();
+
+ final String effectiveDateTime1 = "2012-01-20T07:30:42.000Z";
+ final String effectiveDateTime2 = "2012-01-20T08:00:00.000Z";
+ final String effectiveDateTime3 = "2012-01-20T08:45:33.000Z";
+
+ final String effectiveDateTimeA = "2012-01-20T16:30:42.000Z";
+ final String effectiveDateTimeB = "2012-01-20T16:00:00.000Z";
+ final String effectiveDateTimeC = "2012-01-20T15:30:42.000Z";
+
+
+ //
+ // Take an negative timezone offset and a reference time that is less than the offset (07:30:42 < 8)
+ // => to expect a negative offset of one day
+ //
+ @Test(groups = "fast")
+ public void testComputeOffset1() {
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime1);
+
+ int offset = DateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
+ assertEquals(offset, -1);
+ }
+
+ //
+ // Take an negative timezone offset and a reference time that is equal than the offset (08:00:00 = 8)
+ // => to expect an offset of 0
+ //
+ @Test(groups = "fast")
+ public void testComputeOffset2() {
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime2);
+
+ int offset = DateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
+ assertEquals(offset, 0);
+ }
+
+ //
+ // Take an negative timezone offset and a reference time that is greater than the offset (08:45:33 > 8)
+ // => to expect an offset of 0
+ //
+ @Test(groups = "fast")
+ public void testComputeOffset3() {
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime3);
+
+ int offset = DateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
+ assertEquals(offset, 0);
+ }
+
+ //
+ // Take an positive timezone offset and a reference time that closer to the end of the day than the timezone (16:30:42 + 8 > 24)
+ // => to expect a positive offset of one day
+ //
+ @Test(groups = "fast")
+ public void testComputeOffsetA() {
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeA);
+
+ int offset = DateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
+ assertEquals(offset, 1);
+ }
+
+ //
+ // Take an positive timezone offset and a reference time that brings us exactly at the end of the day (16:00:00 + 8 = 24)
+ // => to expect an offset of 1
+ //
+ @Test(groups = "fast")
+ public void testComputeOffsetB() {
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeB);
+
+ int offset = DateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
+ assertEquals(offset, 1);
+ }
+
+ //
+ // Take an positive timezone offset and a reference time that further away to the end of the day (15:30:42 + 8 < 24)
+ // => to expect an offset of 0
+ //
+ @Test(groups = "fast")
+ public void testComputeOffsetC() {
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeC);
+
+ int offset = DateAndTimeZoneContext.computeOffsetFromUtc(effectiveDateTime, timeZone);
+ assertEquals(offset, 0);
+ }
+
+ @Test(groups = "fast")
+ public void testComputeUTCDateTimeFromLocalDate1() {
+
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime1);
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
+ final DateAndTimeZoneContext dateContext = new DateAndTimeZoneContext(effectiveDateTime, timeZone, clock);
+
+ final LocalDate endDate = new LocalDate(2013, 01, 19);
+ final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
+ assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
+ }
+
+
+ @Test(groups = "fast")
+ public void testComputeUTCDateTimeFromLocalDate2() {
+
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime2);
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
+ final DateAndTimeZoneContext dateContext = new DateAndTimeZoneContext(effectiveDateTime, timeZone, clock);
+
+ final LocalDate endDate = new LocalDate(2013, 01, 20);
+ final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
+ assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
+ }
+
+
+ @Test(groups = "fast")
+ public void testComputeUTCDateTimeFromLocalDate3() {
+
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTime3);
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(-8);
+ final DateAndTimeZoneContext dateContext = new DateAndTimeZoneContext(effectiveDateTime, timeZone, clock);
+
+ final LocalDate endDate = new LocalDate(2013, 01, 20);
+ final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
+ assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
+ }
+
+ @Test(groups = "fast")
+ public void testComputeUTCDateTimeFromLocalDateA() {
+
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeA);
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
+ final DateAndTimeZoneContext dateContext = new DateAndTimeZoneContext(effectiveDateTime, timeZone, clock);
+
+ final LocalDate endDate = new LocalDate(2013, 01, 21);
+ final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
+ assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
+ }
+
+ @Test(groups = "fast")
+ public void testComputeUTCDateTimeFromLocalDateB() {
+
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeB);
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
+ final DateAndTimeZoneContext dateContext = new DateAndTimeZoneContext(effectiveDateTime, timeZone, clock);
+
+ final LocalDate endDate = new LocalDate(2013, 01, 21);
+ final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
+ assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
+ }
+
+ @Test(groups = "fast")
+ public void testComputeUTCDateTimeFromLocalDateC() {
+
+ final DateTime effectiveDateTime = DATE_TIME_FORMATTER.parseDateTime(effectiveDateTimeC);
+
+ final DateTimeZone timeZone = DateTimeZone.forOffsetHours(8);
+ final DateAndTimeZoneContext dateContext = new DateAndTimeZoneContext(effectiveDateTime, timeZone, clock);
+
+ final LocalDate endDate = new LocalDate(2013, 01, 20);
+ final DateTime endDateTimeInUTC = dateContext.computeUTCDateTimeFromLocalDate(endDate);
+ assertTrue(endDateTimeInUTC.compareTo(effectiveDateTime.plusYears(1)) == 0);
+ }
+}