killbill-memoizeit
Changes
entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java 28(+2 -26)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java 75(+67 -8)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java 4(+3 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java 75(+75 -0)
invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java 7(+3 -4)
junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java 42(+24 -18)
junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java 4(+3 -1)
overdue/pom.xml 7(+0 -7)
overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java 3(+2 -1)
Details
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
index 15c4a94..8d107ef 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
@@ -35,6 +35,7 @@ import com.ning.billing.analytics.dao.BusinessAccountDao;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.util.tag.Tag;
@@ -59,14 +60,14 @@ public class BusinessAccountRecorder {
Account account;
try {
account = accountApi.getAccountByKey(data.getExternalKey());
- final BusinessAccount bac = createBusinessAccountFromAccount(account);
+ final BusinessAccount bac = createBusinessAccountFromAccount(account);
- log.info("ACCOUNT CREATION " + bac);
- dao.createAccount(bac);
+ log.info("ACCOUNT CREATION " + bac);
+ dao.createAccount(bac);
} catch (AccountApiException e) {
- log.warn("Error encountered creating BusinessAccount",e);
+ log.warn("Error encountered creating BusinessAccount",e);
}
- }
+ }
/**
* Notification handler for Account changes
@@ -85,17 +86,19 @@ public class BusinessAccountRecorder {
* @param paymentInfo payment object (from the payment plugin)
*/
public void accountUpdated(final PaymentInfoEvent paymentInfo) {
- final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
- if (paymentAttempt == null) {
- return;
- }
try {
+ final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
+ if (paymentAttempt == null) {
+ return;
+ }
+
final Account account = accountApi.getAccountById(paymentAttempt.getAccountId());
accountUpdated(account.getId());
} catch (AccountApiException e) {
log.warn("Error encountered creating BusinessAccount",e);
+ } catch (PaymentApiException e) {
+ log.warn("Error encountered creating BusinessAccount",e);
}
-
}
/**
@@ -152,51 +155,56 @@ public class BusinessAccountRecorder {
}
private void updateBusinessAccountFromAccount(final Account account, final BusinessAccount bac) {
- DateTime lastInvoiceDate = null;
- BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
- String lastPaymentStatus = null;
- String paymentMethod = null;
- String creditCardType = null;
- String billingAddressCountry = null;
-
- // Retrieve invoices information
- final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
- if (invoices != null && invoices.size() > 0) {
- final List<String> invoiceIds = new ArrayList<String>();
- for (final Invoice invoice : invoices) {
- invoiceIds.add(invoice.getId().toString());
- totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
-
- if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
- lastInvoiceDate = invoice.getInvoiceDate();
+
+ try {
+ DateTime lastInvoiceDate = null;
+ BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
+ String lastPaymentStatus = null;
+ String paymentMethod = null;
+ String creditCardType = null;
+ String billingAddressCountry = null;
+
+ // Retrieve invoices information
+ final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
+ if (invoices != null && invoices.size() > 0) {
+ final List<String> invoiceIds = new ArrayList<String>();
+ for (final Invoice invoice : invoices) {
+ invoiceIds.add(invoice.getId().toString());
+ totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
+
+ if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
+ lastInvoiceDate = invoice.getInvoiceDate();
+ }
}
- }
- // Retrieve payments information for these invoices
- DateTime lastPaymentDate = null;
- final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
- if (payments != null) {
- for (final PaymentInfoEvent payment : payments) {
- // Use the last payment method/type/country as the default one for the account
- if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
- lastPaymentDate = payment.getCreatedDate();
-
- lastPaymentStatus = payment.getStatus();
- paymentMethod = payment.getPaymentMethod();
- creditCardType = payment.getCardType();
- billingAddressCountry = payment.getCardCountry();
+ // Retrieve payments information for these invoices
+ DateTime lastPaymentDate = null;
+ final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
+ if (payments != null) {
+ for (final PaymentInfoEvent payment : payments) {
+ // Use the last payment method/type/country as the default one for the account
+ if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
+ lastPaymentDate = payment.getCreatedDate();
+
+ lastPaymentStatus = payment.getStatus();
+ paymentMethod = payment.getPaymentMethod();
+ creditCardType = payment.getCardType();
+ billingAddressCountry = payment.getCardCountry();
+ }
}
}
}
- }
- bac.setLastPaymentStatus(lastPaymentStatus);
- bac.setPaymentMethod(paymentMethod);
- bac.setCreditCardType(creditCardType);
- bac.setBillingAddressCountry(billingAddressCountry);
- bac.setLastInvoiceDate(lastInvoiceDate);
- bac.setTotalInvoiceBalance(totalInvoiceBalance);
+ bac.setLastPaymentStatus(lastPaymentStatus);
+ bac.setPaymentMethod(paymentMethod);
+ bac.setCreditCardType(creditCardType);
+ bac.setBillingAddressCountry(billingAddressCountry);
+ bac.setLastInvoiceDate(lastInvoiceDate);
+ bac.setTotalInvoiceBalance(totalInvoiceBalance);
- bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+ bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+ } catch (PaymentApiException e) {
+ log.error("Failed to update Business account", e);
+ }
}
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
index 3a2baac..725c62b 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
@@ -28,6 +28,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun;
import com.ning.billing.junction.api.BlockingState;
import com.ning.billing.overdue.OverdueState;
import com.ning.billing.util.callcontext.CallContext;
@@ -136,4 +137,11 @@ public class MockEntitlementUserApi implements EntitlementUserApi
public Subscription getBaseSubscription(UUID bundleId) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(
+ UUID subscriptionId, String productName, DateTime requestedDate)
+ throws EntitlementUserApiException {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
index 0dec9b9..69eb454 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
@@ -29,7 +29,7 @@ public interface ChargeThruApi {
* @param subscriptionId
* @return UUID of
*/
- public UUID getAccountIdFromSubscriptionId(UUID subscriptionId);
+ public UUID getAccountIdFromSubscriptionId(UUID subscriptionId) throws EntitlementBillingApiException;
/**
* Sets the charged through date for the subscription with that Id.
@@ -39,16 +39,4 @@ public interface ChargeThruApi {
* @param context
*/
public void setChargedThroughDate(UUID subscriptionId, DateTime ctd, CallContext context);
-
- /**
- * Sets the charged through date for the subscription with that Id. Within the context of a SQL Transaction
- *
- * @param transactionalDao
- * @param subscriptionId
- * @param ctd
- * @param context
- */
- public void setChargedThroughDateFromTransaction(Transmogrifier transactionalDao, UUID subscriptionId,
- DateTime ctd, CallContext context);
-
}
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
index 0e74f86..1e8d7fd 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
@@ -21,6 +21,8 @@ import java.util.UUID;
import com.ning.billing.util.callcontext.CallContext;
import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
@@ -38,7 +40,7 @@ public interface EntitlementUserApi {
public List<Subscription> getSubscriptionsForKey(String bundleKey);
- public Subscription getBaseSubscription(UUID bundleId);
+ public Subscription getBaseSubscription(UUID bundleId) throws EntitlementUserApiException;
public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleKey, CallContext context)
throws EntitlementUserApiException;
@@ -46,5 +48,8 @@ public interface EntitlementUserApi {
public Subscription createSubscription(UUID bundleId, PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
throws EntitlementUserApiException;
+ public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(UUID subscriptionId, String productName, DateTime requestedDate)
+ throws EntitlementUserApiException;
+
public DateTime getNextBillingDate(UUID account);
}
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index 0dbada0..af8e237 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -41,7 +41,7 @@ public interface Subscription extends ExtendedEntity, Blockable {
throws EntitlementUserApiException;
public boolean changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate, CallContext context)
- throws EntitlementUserApiException;
+ throws EntitlementUserApiException;
public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
throws EntitlementUserApiException;
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionStatusDryRun.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionStatusDryRun.java
new file mode 100644
index 0000000..36048fa
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionStatusDryRun.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010-2011 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.entitlement.api.user;
+
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+
+public interface SubscriptionStatusDryRun {
+
+ public UUID getId();
+
+ public String getProductName();
+
+ public BillingPeriod getBillingPeriod();
+
+ public String getPriceList();
+
+ public PhaseType getPhaseType();
+
+ public DryRunChangeReason getReason();
+
+ public enum DryRunChangeReason {
+ AO_INCLUDED_IN_NEW_PLAN,
+ AO_NOT_AVAILABLE_IN_NEW_PLAN,
+ AO_AVAILABLE_IN_NEW_PLAN
+ }
+}
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 829ffe3..860ae6c 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -46,6 +46,8 @@ public enum ErrorCode {
/* Change plan */
ENT_CHANGE_NON_ACTIVE(1021, "Subscription %s is in state %s: Failed to change plan"),
ENT_CHANGE_FUTURE_CANCELLED(1022, "Subscription %s is future cancelled: Failed to change plan"),
+ ENT_CHANGE_DRY_RUN_NOT_BP(1022, "Change DryRun API is only available for BP"),
+
/* Cancellation */
ENT_CANCEL_BAD_STATE(1031, "Subscription %s is in state %s: Failed to cancel"),
/* Recreation */
@@ -59,6 +61,7 @@ public enum ErrorCode {
ENT_GET_INVALID_BUNDLE_ID(1081, "Could not find a bundle matching id %s"),
ENT_INVALID_SUBSCRIPTION_ID(1082, "Unknown subscription %s"),
ENT_GET_INVALID_BUNDLE_KEY(1083, "Could not find a bundle matching key %s"),
+ ENT_GET_NO_SUCH_BASE_SUBSCRIPTION(1084, "Could not base subscription for bundle %s"),
/* Repair */
ENT_REPAIR_INVALID_DELETE_SET(1091, "Event %s is not deleted for subscription %s but prior events were"),
@@ -80,6 +83,8 @@ public enum ErrorCode {
ENT_BUNDLE_IS_OVERDUE_BLOCKED(1090, "Changes to this bundle are blocked by overdue enforcement (%s : %s)"),
ENT_ACCOUNT_IS_OVERDUE_BLOCKED(1091, "Changes to this account are blocked by overdue enforcement (%s)"),
+
+
/*
*
* Range 2000 : CATALOG
@@ -197,7 +202,25 @@ public enum ErrorCode {
BLOCK_BLOCKED_ACTION(6000, "The action %s is block on this %s with id=%s"),
BLOCK_TYPE_NOT_SUPPORTED(6001, "The Blockable type '%s' is not supported"),
- /*
+
+ /*
+ * Range 7000 : Payment
+ */
+ PAYMENT_NO_SUCH_PAYMENT_METHOD(7001, "Payment method for account %s, and paymentId %s does not exist"),
+ PAYMENT_NO_PAYMENT_METHODS(7002, "Payment methods for account %s don't exist"),
+ PAYMENT_UPD_GATEWAY_FAILED(7003, "Failed to update payment gateway for account %s : %s"),
+ PAYMENT_GET_PAYMENT_PROVIDER(7004, "Failed to retrieve payment provider for account %s : %s"),
+ PAYMENT_ADD_PAYMENT_METHOD(7005, "Failed to add payment method for account %s : %s"),
+ PAYMENT_DEL_PAYMENT_METHOD(7006, "Failed to delete payment method for account %s : %s"),
+ PAYMENT_UPD_PAYMENT_METHOD(7007, "Failed to update payment method for account %s : %s"),
+ PAYMENT_CREATE_PAYMENT(7008, "Failed to create payment for account %s : %s"),
+ PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT(7009, "Failed to create payment for account %s and attempt %s : %s"),
+ PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_WITH_NON_POSITIVE_INV(70010, "Got payment attempt with negative or null invoice for account %s"),
+ PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_BAD(7011, "Failed to create payment for attempts %s "),
+ PAYMENT_CREATE_PAYMENT_PROVIDER_ACCOUNT(7012, "Failed to create payment provider account for account %s : %s"),
+ PAYMENT_UPD_PAYMENT_PROVIDER_ACCOUNT(7013, "Failed to update payment provider account for account %s : %s"),
+ PAYMENT_CREATE_REFUND(7014, "Failed to create refund for account %s : %s"),
+ /*
*
* Range 9000: Miscellaneous
*
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index 1679f50..c7b5965 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -26,36 +26,54 @@ import com.ning.billing.util.callcontext.CallContext;
public interface PaymentApi {
- Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context);
+ public void updatePaymentGateway(final String accountKey, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId);
+ public PaymentMethodInfo getPaymentMethod(final String accountKey, final String paymentMethodId)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
+ public List<PaymentMethodInfo> getPaymentMethods(final String accountKey)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context);
+ public String addPaymentMethod(final String accountKey, final PaymentMethodInfo paymentMethod, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context);
+ public PaymentMethodInfo updatePaymentMethod(final String accountKey, final PaymentMethodInfo paymentMethodInfo, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context);
+ public void deletePaymentMethod(final String accountKey, final String paymentMethodId, final CallContext context)
+ throws PaymentApiException;
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context);
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context);
- Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context);
+ public List<PaymentInfoEvent> createPayment(final String accountKey, final List<String> invoiceIds, final CallContext context)
+ throws PaymentApiException;
+
+ public List<PaymentInfoEvent> createPayment(final Account account, final List<String> invoiceIds, final CallContext context)
+ throws PaymentApiException;
+
+ public PaymentInfoEvent createPaymentForPaymentAttempt(final UUID paymentAttemptId, final CallContext context)
+ throws PaymentApiException;
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account, List<String> invoiceIds, CallContext context); //TODO
+ public List<PaymentInfoEvent> createRefund(final Account account, final List<String> invoiceIds, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
+ public PaymentProviderAccount getPaymentProviderAccount(final String accountKey)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context);
+ public String createPaymentProviderAccount(final Account account, final CallContext context)
+ throws PaymentApiException;
- Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String accountKey, CallContext context);
+ public void updatePaymentProviderAccountContact(String accountKey, CallContext context)
+ throws PaymentApiException;
- PaymentAttempt getPaymentAttemptForPaymentId(String id);
+ public PaymentAttempt getPaymentAttemptForPaymentId(final String id)
+ throws PaymentApiException;
- List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds);
+ public List<PaymentInfoEvent> getPaymentInfo(final List<String> invoiceIds)
+ throws PaymentApiException;
- List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
-
- PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
+ public List<PaymentAttempt> getPaymentAttemptsForInvoiceId(final String invoiceId)
+ throws PaymentApiException;
+ public PaymentInfoEvent getPaymentInfoForPaymentAttemptId(final String paymentAttemptId)
+ throws PaymentApiException;
}
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
new file mode 100644
index 0000000..ff81b16
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2011 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.payment.api;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.catalog.api.CatalogApiException;
+
+public class PaymentApiException extends BillingExceptionBase {
+
+ private static final long serialVersionUID = 39445033L;
+
+
+ public PaymentApiException(AccountApiException e) {
+ super(e, e.getCode(), e.getMessage());
+ }
+
+ /*
+ public PaymentApiException(CatalogApiException e) {
+ super(e, e.getCode(), e.getMessage());
+ }
+ */
+
+ public PaymentApiException(Throwable e, ErrorCode code, Object...args) {
+ super(e, code, args);
+ }
+
+ public PaymentApiException(Throwable e, int code, String message) {
+ super(e, code, message);
+ }
+
+ public PaymentApiException(ErrorCode code, Object...args) {
+ super(code, args);
+ }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index 5f442c6..7996141 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -185,7 +185,7 @@ public class TestIntegration extends TestIntegrationBase {
// TODO: Jeff implement repair
}
- @Test(groups = "slow", enabled = false)
+ @Test(groups = "slow", enabled = true)
public void testWithRecreatePlan() throws Exception {
log.info("Starting testWithRecreatePlan");
@@ -250,7 +250,7 @@ public class TestIntegration extends TestIntegrationBase {
term = BillingPeriod.MONTHLY;
planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- busHandler.pushExpectedEvent(NextEvent.CREATE);
+ busHandler.pushExpectedEvent(NextEvent.RE_CREATE);
busHandler.pushExpectedEvent(NextEvent.INVOICE);
busHandler.pushExpectedEvent(NextEvent.PAYMENT);
subscription.recreate(new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), endDate, context);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
index c733097..2203f41 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
@@ -54,13 +54,13 @@ import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
public class TestRepairIntegration extends TestIntegrationBase {
- @Test(groups={"slow"}, enabled=true)
+ @Test(groups={"slow"}, enabled=false)
public void testRepairChangeBPWithAddonIncludedIntrial() throws Exception {
log.info("Starting testRepairChangeBPWithAddonIncludedIntrial");
testRepairChangeBPWithAddonIncluded(true);
}
- @Test(groups={"slow"}, enabled=true)
+ @Test(groups={"slow"}, enabled=false)
public void testRepairChangeBPWithAddonIncludedOutOfTrial() throws Exception {
log.info("Starting testRepairChangeBPWithAddonIncludedOutOfTrial");
testRepairChangeBPWithAddonIncluded(false);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
index 7bde4a2..1c3cfc5 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
@@ -16,11 +16,9 @@ w * Copyright 2010-2011 Ning, Inc.
package com.ning.billing.entitlement.api.billing;
-import java.util.Date;
import java.util.UUID;
import org.joda.time.DateTime;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,19 +28,16 @@ import com.ning.billing.entitlement.api.SubscriptionFactory;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
-import com.ning.billing.entitlement.engine.dao.SubscriptionSqlDao;
-import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextFactory;
public class DefaultChargeThruApi implements ChargeThruApi {
- private static final Logger log = LoggerFactory.getLogger(DefaultChargeThruApi.class);
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultChargeThruApi.class);
private final EntitlementDao entitlementDao;
private final SubscriptionFactory subscriptionFactory;
- private static final String SUBSCRIPTION_TABLE_NAME = "subscriptions";
@Inject
public DefaultChargeThruApi(final CallContextFactory factory, final SubscriptionFactory subscriptionFactory, final EntitlementDao dao, final AccountUserApi accountApi) {
@@ -65,23 +60,4 @@ public class DefaultChargeThruApi implements ChargeThruApi {
.setPaidThroughDate(subscription.getPaidThroughDate());
entitlementDao.updateChargedThroughDate(new SubscriptionData(builder), context);
}
-
- @Override
- public void setChargedThroughDateFromTransaction(final Transmogrifier transactionalDao, final UUID subscriptionId,
- final DateTime ctd, final CallContext context) {
- SubscriptionSqlDao subscriptionSqlDao = transactionalDao.become(SubscriptionSqlDao.class);
- SubscriptionData subscription = (SubscriptionData) subscriptionSqlDao.getSubscriptionFromId(subscriptionId.toString());
-
- if (subscription == null) {
- log.warn("Subscription not found when setting CTD.");
- } else {
- DateTime chargedThroughDate = subscription.getChargedThroughDate();
- if (chargedThroughDate == null || chargedThroughDate.isBefore(ctd)) {
- subscriptionSqlDao.updateChargedThroughDate(subscriptionId.toString(),
- ctd.toDate(), context);
- AuditSqlDao auditSqlDao = transactionalDao.become(AuditSqlDao.class);
- auditSqlDao.insertAuditFromTransaction(SUBSCRIPTION_TABLE_NAME, subscriptionId.toString(), ChangeType.UPDATE, context);
- }
- }
- }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java
index 046b982..5b0f192 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java
@@ -15,6 +15,8 @@
*/
package com.ning.billing.entitlement.api;
+import java.util.List;
+
import org.joda.time.DateTime;
import com.ning.billing.catalog.api.BillingPeriod;
@@ -23,6 +25,7 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.util.callcontext.CallContext;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index 115c60b..b8745fe 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -16,6 +16,7 @@
package com.ning.billing.entitlement.api.user;
+import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -23,6 +24,7 @@ import org.joda.time.DateTime;
import com.google.inject.Inject;
import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.CatalogService;
@@ -31,9 +33,11 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionFactory;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun.DryRunChangeReason;
import com.ning.billing.entitlement.engine.addon.AddonUtils;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.exceptions.EntitlementError;
@@ -61,19 +65,32 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
this.subscriptionFactory = subscriptionFactory;
}
+
@Override
- public SubscriptionBundle getBundleFromId(UUID id) {
- return dao.getSubscriptionBundleFromId(id);
+ public SubscriptionBundle getBundleFromId(UUID id) throws EntitlementUserApiException {
+ SubscriptionBundle result = dao.getSubscriptionBundleFromId(id);
+ if (result == null) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_ID, id.toString());
+ }
+ return result;
}
@Override
- public Subscription getSubscriptionFromId(UUID id) {
- return dao.getSubscriptionFromId(subscriptionFactory, id);
+ public Subscription getSubscriptionFromId(UUID id) throws EntitlementUserApiException {
+ Subscription result = dao.getSubscriptionFromId(subscriptionFactory, id);
+ if (result == null) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, id);
+ }
+ return result;
}
@Override
- public SubscriptionBundle getBundleForKey(String bundleKey) {
- return dao.getSubscriptionBundleFromKey(bundleKey);
+ public SubscriptionBundle getBundleForKey(String bundleKey) throws EntitlementUserApiException {
+ SubscriptionBundle result = dao.getSubscriptionBundleFromKey(bundleKey);
+ if (result == null) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_KEY, bundleKey);
+ }
+ return result;
}
@Override
@@ -92,8 +109,12 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
}
@Override
- public Subscription getBaseSubscription(UUID bundleId) {
- return dao.getBaseSubscription(subscriptionFactory, bundleId);
+ public Subscription getBaseSubscription(UUID bundleId) throws EntitlementUserApiException {
+ Subscription result = dao.getBaseSubscription(subscriptionFactory, bundleId);
+ if (result == null) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_GET_NO_SUCH_BASE_SUBSCRIPTION, bundleId);
+ }
+ return result;
}
@@ -197,4 +218,42 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
}
return result;
}
+
+
+ @Override
+ public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(UUID subscriptionId, String baseProductName, DateTime requestedDate)
+ throws EntitlementUserApiException {
+
+ Subscription subscription = dao.getSubscriptionFromId(subscriptionFactory, subscriptionId);
+ if (subscription == null) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, subscriptionId);
+ }
+ if (subscription.getCategory() != ProductCategory.BASE) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_CHANGE_DRY_RUN_NOT_BP);
+ }
+
+ List<SubscriptionStatusDryRun> result = new LinkedList<SubscriptionStatusDryRun>();
+
+ List<Subscription> bundleSubscriptions = dao.getSubscriptions(subscriptionFactory, subscription.getBundleId());
+ for (Subscription cur : bundleSubscriptions) {
+ if (cur.getId().equals(subscriptionId)) {
+ continue;
+ }
+
+ DryRunChangeReason reason = null;
+ if (addonUtils.isAddonIncludedFromProdName(baseProductName, requestedDate, cur.getCurrentPlan())) {
+ reason = DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN;
+ } else if (addonUtils.isAddonAvailableFromProdName(baseProductName, requestedDate, cur.getCurrentPlan())) {
+ reason = DryRunChangeReason.AO_AVAILABLE_IN_NEW_PLAN;
+ } else {
+ reason = DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN;
+ }
+ SubscriptionStatusDryRun status = new DefaultSubscriptionStatusDryRun(cur.getId(),
+ cur.getCurrentPlan().getProduct().getName(), cur.getCurrentPhase().getPhaseType(),
+ cur.getCurrentPlan().getBillingPeriod(),
+ cur.getCurrentPriceList().getName(), reason);
+ result.add(status);
+ }
+ return result;
+ }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
index ed2cb05..0f2db75 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
@@ -17,6 +17,7 @@
package com.ning.billing.entitlement.api.user;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import org.joda.time.DateTime;
@@ -36,6 +37,7 @@ import com.ning.billing.catalog.api.PlanSpecifier;
import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.alignment.PlanAligner;
import com.ning.billing.entitlement.alignment.TimedPhase;
import com.ning.billing.entitlement.api.SubscriptionApiService;
@@ -229,7 +231,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
return true;
}
-
+
public boolean changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
String priceList, DateTime requestedDate, CallContext context)
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java
new file mode 100644
index 0000000..9971f41
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2011 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.entitlement.api.user;
+
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+
+public class DefaultSubscriptionStatusDryRun implements SubscriptionStatusDryRun {
+
+ private final UUID id;
+ private final String productName;
+ private final PhaseType phaseType;
+ private final BillingPeriod billingPeriod;
+ private final String priceList;
+ private final DryRunChangeReason reason;
+
+
+ public DefaultSubscriptionStatusDryRun(final UUID id, final String productName,
+ final PhaseType phaseType, final BillingPeriod billingPeriod, final String priceList,
+ final DryRunChangeReason reason) {
+ super();
+ this.id = id;
+ this.productName = productName;
+ this.phaseType = phaseType;
+ this.billingPeriod = billingPeriod;
+ this.priceList = priceList;
+ this.reason = reason;
+ }
+
+ @Override
+ public UUID getId() {
+ return id;
+ }
+
+ @Override
+ public String getProductName() {
+ return productName;
+ }
+
+ @Override
+ public PhaseType getPhaseType() {
+ return phaseType;
+ }
+
+
+ @Override
+ public BillingPeriod getBillingPeriod() {
+ return billingPeriod;
+ }
+
+ @Override
+ public String getPriceList() {
+ return priceList;
+ }
+
+ @Override
+ public DryRunChangeReason getReason() {
+ return reason;
+ }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index 703e0bc..0bc6bb9 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -200,7 +200,6 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
return apiService.recreatePlan(this, spec, requestedDate, context);
}
-
@Override
public SubscriptionEvent getPendingTransition() {
SubscriptionTransitionData data = getPendingTransitionData();
@@ -209,6 +208,11 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
}
return new DefaultSubscriptionEvent(data, startDate);
}
+
+ @Override
+ public BlockingState getBlockingState() {
+ throw new UnsupportedOperationException();
+ }
protected SubscriptionTransitionData getPendingTransitionData() {
if (transitions == null) {
@@ -520,10 +524,4 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
previousPriceList = nextPriceList;
}
}
-
- @Override
- public BlockingState getBlockingState() {
- throw new UnsupportedOperationException();
- }
-
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
index 3208f42..2a4a550 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
@@ -63,7 +63,16 @@ public class AddonUtils {
}
}
- public boolean isAddonAvailable(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+ public boolean isAddonAvailableFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+ try {
+ Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
+ return isAddonAvailable(product, targetAddOnPlan);
+ } catch (CatalogApiException e) {
+ throw new EntitlementError(e);
+ }
+ }
+
+ public boolean isAddonAvailableFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
try {
Plan plan = catalogService.getFullCatalog().findPlan(basePlanName, requestedDate);
Product product = plan.getProduct();
@@ -84,9 +93,19 @@ public class AddonUtils {
}
return false;
}
+
+ public boolean isAddonIncludedFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+ try {
+ Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
+ return isAddonIncluded(product, targetAddOnPlan);
+ } catch (CatalogApiException e) {
+ throw new EntitlementError(e);
+ }
- public boolean isAddonIncluded(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
- try {
+ }
+
+ public boolean isAddonIncludedFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+ try {
Plan plan = catalogService.getFullCatalog().findPlan(basePlanName, requestedDate);
Product product = plan.getProduct();
return isAddonIncluded(product, targetAddOnPlan);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
index 7534014..46ba0c3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
@@ -527,8 +527,8 @@ public class EntitlementSqlDao implements EntitlementDao {
boolean createCancelEvent = (futureBaseEvent != null) &&
((futureBaseEvent instanceof ApiEventCancel) ||
- ((! addonUtils.isAddonAvailable(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
- (addonUtils.isAddonIncluded(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
+ ((! addonUtils.isAddonAvailableFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
+ (addonUtils.isAddonIncludedFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
if (createCancelEvent) {
DateTime now = clock.getUTCNow();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index d412e59..7990084 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -21,6 +21,8 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
+import java.util.List;
+
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.testng.Assert;
@@ -42,6 +44,7 @@ import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun.DryRunChangeReason;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
import com.ning.billing.util.clock.DefaultClock;
@@ -153,9 +156,9 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"slow"})
- public void testChangeBPWithAddonNonIncluded() {
+ public void testChangeBPWithAddonIncluded() {
- log.info("Starting testChangeBPWithAddonNonIncluded");
+ log.info("Starting testChangeBPWithAddonIncluded");
try {
@@ -193,6 +196,15 @@ public class TestUserApiAddOn extends TestApiBase {
BillingPeriod newBaseTerm = BillingPeriod.MONTHLY;
String newBasePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+ List<SubscriptionStatusDryRun> aoStatus = entitlementApi.getDryRunChangePlanStatus(baseSubscription.getId(), newBaseProduct, now);
+ assertEquals(aoStatus.size(), 1);
+ assertEquals(aoStatus.get(0).getId(), aoSubscription.getId());
+ assertEquals(aoStatus.get(0).getProductName(), aoProduct);
+ assertEquals(aoStatus.get(0).getBillingPeriod(), aoTerm);
+ assertEquals(aoStatus.get(0).getPhaseType(), aoSubscription.getCurrentPhase().getPhaseType());
+ assertEquals(aoStatus.get(0).getPriceList(), aoSubscription.getCurrentPriceList().getName());
+ assertEquals(aoStatus.get(0).getReason(), DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN);
+
testListener.reset();
testListener.pushExpectedEvent(NextEvent.CHANGE);
testListener.pushExpectedEvent(NextEvent.CANCEL);
@@ -250,9 +262,17 @@ public class TestUserApiAddOn extends TestApiBase {
BillingPeriod newBaseTerm = BillingPeriod.MONTHLY;
String newBasePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+ List<SubscriptionStatusDryRun> aoStatus = entitlementApi.getDryRunChangePlanStatus(baseSubscription.getId(), newBaseProduct, now);
+ assertEquals(aoStatus.size(), 1);
+ assertEquals(aoStatus.get(0).getId(), aoSubscription.getId());
+ assertEquals(aoStatus.get(0).getProductName(), aoProduct);
+ assertEquals(aoStatus.get(0).getBillingPeriod(), aoTerm);
+ assertEquals(aoStatus.get(0).getPhaseType(), aoSubscription.getCurrentPhase().getPhaseType());
+ assertEquals(aoStatus.get(0).getPriceList(), aoSubscription.getCurrentPriceList().getName());
+ assertEquals(aoStatus.get(0).getReason(), DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN);
+
baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, now, context);
-
// REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 0b064bb..fb30979 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -153,11 +153,6 @@ public class DefaultInvoiceDao implements InvoiceDao {
@Override
public void create(final Invoice invoice, final CallContext context) {
- final InvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
- invoice.getBalance(), invoice.getCurrency(),
- invoice.getInvoiceDate(),
- context.getUserToken());
-
invoiceSqlDao.inTransaction(new Transaction<Void, InvoiceSqlDao>() {
@Override
public Void inTransaction(final InvoiceSqlDao transactional, final TransactionStatus status) throws Exception {
@@ -178,9 +173,6 @@ public class DefaultInvoiceDao implements InvoiceDao {
FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = transactional.become(FixedPriceInvoiceItemSqlDao.class);
fixedPriceInvoiceItemDao.batchCreateFromTransaction(fixedPriceInvoiceItems, context);
- setChargedThroughDates(transactional, fixedPriceInvoiceItems, recurringInvoiceItems, context);
-
- // STEPH Why do we need that? Are the payments not always null at this point?
List<InvoicePayment> invoicePayments = invoice.getPayments();
InvoicePaymentSqlDao invoicePaymentSqlDao = transactional.become(InvoicePaymentSqlDao.class);
invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
@@ -190,18 +182,10 @@ public class DefaultInvoiceDao implements InvoiceDao {
auditSqlDao.insertAuditFromTransaction("recurring_invoice_items", getIdsFromInvoiceItems(recurringInvoiceItems), ChangeType.INSERT, context);
auditSqlDao.insertAuditFromTransaction("fixed_invoice_items", getIdsFromInvoiceItems(fixedPriceInvoiceItems), ChangeType.INSERT, context);
auditSqlDao.insertAuditFromTransaction("invoice_payments", getIdsFromInvoicePayments(invoicePayments), ChangeType.INSERT, context);
-
- }
- try {
- eventBus.postFromTransaction(event, transactional);
- } catch (EventBusException e) {
- log.warn("Failed to post invoice event for invoiceId " + invoice.getId(), e);
}
return null;
}
});
-
-
}
private List<String> getIdsFromInvoiceItems(List<InvoiceItem> invoiceItems) {
@@ -377,34 +361,4 @@ public class DefaultInvoiceDao implements InvoiceDao {
}
}
}
-
- private void setChargedThroughDates(final InvoiceSqlDao dao, final Collection<InvoiceItem> fixedPriceItems,
- final Collection<InvoiceItem> recurringItems, CallContext context) {
- Map<UUID, DateTime> chargeThroughDates = new HashMap<UUID, DateTime>();
- addInvoiceItemsToChargeThroughDates(chargeThroughDates, fixedPriceItems);
- addInvoiceItemsToChargeThroughDates(chargeThroughDates, recurringItems);
-
- for (UUID subscriptionId : chargeThroughDates.keySet()) {
- if(subscriptionId != null) {
- DateTime chargeThroughDate = chargeThroughDates.get(subscriptionId);
- log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
- billingApi.setChargedThroughDateFromTransaction(dao, subscriptionId, chargeThroughDate, context);
- }
- }
- }
-
- private void addInvoiceItemsToChargeThroughDates(Map<UUID, DateTime> chargeThroughDates, Collection<InvoiceItem> items) {
- for (InvoiceItem item : items) {
- UUID subscriptionId = item.getSubscriptionId();
- DateTime endDate = item.getEndDate();
-
- if (chargeThroughDates.containsKey(subscriptionId)) {
- if (chargeThroughDates.get(subscriptionId).isBefore(endDate)) {
- chargeThroughDates.put(subscriptionId, endDate);
- }
- } else {
- chargeThroughDates.put(subscriptionId, endDate);
- }
- }
- }
}
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 53093a2..32d444d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -17,7 +17,9 @@
package com.ning.billing.invoice;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.SortedSet;
import java.util.UUID;
@@ -32,15 +34,20 @@ import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.entitlement.api.billing.BillingEvent;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.api.user.SubscriptionEvent;
import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.invoice.api.InvoiceNotifier;
import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.user.DefaultEmptyInvoiceEvent;
+import com.ning.billing.invoice.api.user.DefaultInvoiceCreationEvent;
import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.model.BillingEventSet;
+import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.invoice.model.InvoiceGenerator;
+import com.ning.billing.invoice.model.RecurringInvoiceItem;
import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
@@ -53,7 +60,7 @@ import com.ning.billing.util.globallocker.GlobalLocker.LockerService;
import com.ning.billing.util.globallocker.LockFailedException;
public class InvoiceDispatcher {
- private final static Logger log = LoggerFactory.getLogger(InvoiceDispatcher.class);
+ private final static Logger log = LoggerFactory.getLogger(InvoiceDispatcher.class);
private final static int NB_LOCK_TRY = 5;
private final InvoiceGenerator generator;
@@ -69,12 +76,12 @@ public class InvoiceDispatcher {
@Inject
public InvoiceDispatcher(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
- final BillingApi billingApi,
- final InvoiceDao invoiceDao,
- final InvoiceNotifier invoiceNotifier,
- final GlobalLocker locker,
- final Bus eventBus,
- final Clock clock) {
+ final BillingApi billingApi,
+ final InvoiceDao invoiceDao,
+ final InvoiceNotifier invoiceNotifier,
+ final GlobalLocker locker,
+ final Bus eventBus,
+ final Clock clock) {
this.generator = generator;
this.billingApi = billingApi;
this.accountUserApi = accountUserApi;
@@ -89,7 +96,7 @@ public class InvoiceDispatcher {
}
public void processSubscription(final SubscriptionEvent transition,
- final CallContext context) throws InvoiceApiException {
+ final CallContext context) throws InvoiceApiException {
UUID subscriptionId = transition.getSubscriptionId();
DateTime targetDate = transition.getEffectiveTransitionTime();
log.info("Got subscription transition from InvoiceListener. id: " + subscriptionId.toString() + "; targetDate: " + targetDate.toString());
@@ -98,25 +105,24 @@ public class InvoiceDispatcher {
}
public void processSubscription(final UUID subscriptionId, final DateTime targetDate,
- final CallContext context) throws InvoiceApiException {
- if (subscriptionId == null) {
- log.error("Failed handling entitlement change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
- return;
- }
-
- UUID accountId = billingApi.getAccountIdFromSubscriptionId(subscriptionId);
- if (accountId == null) {
+ final CallContext context) throws InvoiceApiException {
+ try {
+ if (subscriptionId == null) {
+ log.error("Failed handling entitlement change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
+ return;
+ }
+ UUID accountId = billingApi.getAccountIdFromSubscriptionId(subscriptionId);
+ processAccount(accountId, targetDate, false, context);
+ } catch (EntitlementBillingApiException e) {
log.error("Failed handling entitlement change.",
new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
- return;
}
-
- processAccount(accountId, targetDate, false, context);
+ return;
}
-
+
public Invoice processAccount(final UUID accountId, final DateTime targetDate,
- final boolean dryRun, final CallContext context) throws InvoiceApiException {
- GlobalLock lock = null;
+ final boolean dryRun, final CallContext context) throws InvoiceApiException {
+ GlobalLock lock = null;
try {
lock = locker.lockWithNumberOfTries(LockerService.INVOICE, accountId.toString(), NB_LOCK_TRY);
@@ -134,15 +140,7 @@ public class InvoiceDispatcher {
return null;
}
- private void postEmptyInvoiceEvent(final UUID accountId, final UUID userToken) {
- try {
- BusEvent event = new DefaultEmptyInvoiceEvent(accountId, clock.getUTCNow(), userToken);
- eventBus.post(event);
- } catch (EventBusException e){
- log.error("Failed to post DefaultEmptyInvoiceNotification event for account {} ", accountId, e);
- }
- }
-
+
private Invoice processAccountWithLock(final UUID accountId, final DateTime targetDate,
final boolean dryRun, final CallContext context) throws InvoiceApiException {
try {
@@ -159,7 +157,8 @@ public class InvoiceDispatcher {
log.info("Generated null invoice.");
outputDebugData(events, invoices);
if (!dryRun) {
- postEmptyInvoiceEvent(accountId, context.getUserToken());
+ BusEvent event = new DefaultEmptyInvoiceEvent(accountId, clock.getUTCNow(), context.getUserToken());
+ postEvent(event, accountId);
}
} else {
log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
@@ -172,6 +171,17 @@ public class InvoiceDispatcher {
outputDebugData(events, invoices);
if (!dryRun) {
invoiceDao.create(invoice, context);
+
+ List<InvoiceItem> fixedPriceInvoiceItems = invoice.getInvoiceItems(FixedPriceInvoiceItem.class);
+ List<InvoiceItem> recurringInvoiceItems = invoice.getInvoiceItems(RecurringInvoiceItem.class);
+ setChargedThroughDates(fixedPriceInvoiceItems, recurringInvoiceItems, context);
+
+ final InvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
+ invoice.getBalance(), invoice.getCurrency(),
+ invoice.getInvoiceDate(),
+ context.getUserToken());
+
+ postEvent(event, accountId);
}
}
@@ -186,6 +196,47 @@ public class InvoiceDispatcher {
}
}
+ private void setChargedThroughDates(final Collection<InvoiceItem> fixedPriceItems,
+ final Collection<InvoiceItem> recurringItems, CallContext context) {
+
+ Map<UUID, DateTime> chargeThroughDates = new HashMap<UUID, DateTime>();
+ addInvoiceItemsToChargeThroughDates(chargeThroughDates, fixedPriceItems);
+ addInvoiceItemsToChargeThroughDates(chargeThroughDates, recurringItems);
+
+ for (UUID subscriptionId : chargeThroughDates.keySet()) {
+ if(subscriptionId != null) {
+ DateTime chargeThroughDate = chargeThroughDates.get(subscriptionId);
+ log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
+ billingApi.setChargedThroughDate(subscriptionId, chargeThroughDate, context);
+ }
+ }
+ }
+
+ private void postEvent(final BusEvent event, final UUID accountId) {
+ try {
+ eventBus.post(event);
+ } catch (EventBusException e){
+ log.error(String.format("Failed to post event {} for account {} ", event.getBusEventType(), accountId), e);
+ }
+ }
+
+
+ private void addInvoiceItemsToChargeThroughDates(Map<UUID, DateTime> chargeThroughDates, Collection<InvoiceItem> items) {
+ for (InvoiceItem item : items) {
+ UUID subscriptionId = item.getSubscriptionId();
+ DateTime endDate = item.getEndDate();
+
+ if (chargeThroughDates.containsKey(subscriptionId)) {
+ if (chargeThroughDates.get(subscriptionId).isBefore(endDate)) {
+ chargeThroughDates.put(subscriptionId, endDate);
+ }
+ } else {
+ chargeThroughDates.put(subscriptionId, endDate);
+ }
+ }
+ }
+
+
private void outputDebugData(Collection<BillingEvent> events, Collection<Invoice> invoices) {
if (VERBOSE_OUTPUT) {
log.info("Events");
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index 5d7d14f..a7b0f09 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -132,7 +132,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoicingTestBase {
busService.getBus().start();
- ((ZombieControl)billingApi).addResult("setChargedThroughDateFromTransaction", BrainDeadProxyFactory.ZOMBIE_VOID);
+ ((ZombieControl)billingApi).addResult("setChargedThroughDate", BrainDeadProxyFactory.ZOMBIE_VOID);
migrationInvoiceId = createAndCheckMigrationInvoice();
regularInvoiceId = generateRegularInvoice();
@@ -189,11 +189,10 @@ public class TestDefaultInvoiceMigrationApi extends InvoicingTestBase {
fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
- BillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(BillingApi.class);
- ((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
+ ((ZombieControl)billingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
- InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi,
+ InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, billingApi,
invoiceDao, invoiceNotifier, locker, busService.getBus(), clock);
CallContext context = new DefaultCallContextFactory(clock).createCallContext("Migration test", CallOrigin.TEST, UserType.TEST);
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 e591dfa..26403d0 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -115,7 +115,7 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
context = new DefaultCallContextFactory(clock).createCallContext("Miracle Max", CallOrigin.TEST, UserType.TEST);
busService.getBus().start();
- ((ZombieControl)billingApi).addResult("setChargedThroughDateFromTransaction", BrainDeadProxyFactory.ZOMBIE_VOID);
+ ((ZombieControl)billingApi).addResult("setChargedThroughDate", BrainDeadProxyFactory.ZOMBIE_VOID);
}
@AfterClass(alwaysRun = true)
@@ -155,13 +155,12 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
- BillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(BillingApi.class);
- ((ZombieControl) entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
+ ((ZombieControl) billingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
DateTime target = new DateTime();
InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
- InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao,
+ InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, billingApi, invoiceDao,
invoiceNotifier, locker, busService.getBus(), clock);
Invoice invoice = dispatcher.processAccount(accountId, target, true, context);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index 9061eac..07502cc 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -67,6 +67,7 @@ import com.ning.billing.jaxrs.util.Context;
import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
import com.ning.billing.jaxrs.util.TagHelper;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.util.api.TagDefinitionApiException;
@@ -268,6 +269,9 @@ public class AccountResource implements BaseJaxrsResource {
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
return Response.status(Status.NO_CONTENT).build();
+ } catch (PaymentApiException e) {
+ log.error(e.getMessage());
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
} catch (EntitlementRepairException e) {
log.error(e.getMessage());
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
index aeb3f7a..67c5b5c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
@@ -92,7 +92,6 @@ public class SubscriptionResource implements BaseJaxrsResource {
try {
UUID uuid = UUID.fromString(subscriptionId);
Subscription subscription = entitlementApi.getSubscriptionFromId(uuid);
-
SubscriptionJsonNoEvents json = new SubscriptionJsonNoEvents(subscription);
return Response.status(Status.OK).entity(json).build();
} catch (EntitlementUserApiException e) {
@@ -101,7 +100,6 @@ public class SubscriptionResource implements BaseJaxrsResource {
} else {
throw e;
}
-
}
}
@@ -185,14 +183,13 @@ public class SubscriptionResource implements BaseJaxrsResource {
return operationResponse;
}
try {
- return getSubscription(subscriptionId);
+ return getSubscription(subscriptionId);
} catch (EntitlementUserApiException e) {
if (e.getCode() == ErrorCode.ENT_GET_INVALID_BUNDLE_ID.getCode()) {
return Response.status(Status.NO_CONTENT).build();
} else {
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
-
}
}
};
@@ -333,13 +330,10 @@ public class SubscriptionResource implements BaseJaxrsResource {
return callback.doResponseOk(operationValue);
} catch (EntitlementUserApiException e) {
log.info(String.format("Failed to complete operation"), e);
- //throw new WebApplicationException(Response.Status.BAD_REQUEST);
return Response.status(Status.BAD_REQUEST).build();
} catch (InterruptedException e) {
- //throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
} catch (TimeoutException e) {
- //throw new WebApplicationException(Response.Status.fromStatusCode(408));
return Response.status(Status.fromStatusCode(408)).build();
} finally {
if (waiter != null) {
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java
index 3d340da..9452146 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java
@@ -29,6 +29,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun;
import com.ning.billing.junction.api.Blockable;
import com.ning.billing.junction.api.BlockingApi;
import com.ning.billing.junction.api.BlockingApiException;
@@ -40,7 +41,7 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
private final EntitlementUserApi entitlementUserApi;
private final BlockingApi blockingApi;
private final BlockingChecker checker;
-
+
@Inject
public BlockingEntitlementUserApi(@RealImplementation EntitlementUserApi userApi, BlockingApi blockingApi, BlockingChecker checker) {
this.entitlementUserApi = userApi;
@@ -48,32 +49,25 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
this.checker = checker;
}
+ @Override
public SubscriptionBundle getBundleFromId(UUID id) throws EntitlementUserApiException {
SubscriptionBundle bundle = entitlementUserApi.getBundleFromId(id);
- if(bundle == null) {
- throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_ID, id);
- }
return new BlockingSubscriptionBundle(bundle, blockingApi);
}
+ @Override
public Subscription getSubscriptionFromId(UUID id) throws EntitlementUserApiException {
Subscription subscription = entitlementUserApi.getSubscriptionFromId(id);
- if(subscription == null) {
- throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, id);
- }
return new BlockingSubscription(subscription, blockingApi, checker);
}
-
+ @Override
public SubscriptionBundle getBundleForKey(String bundleKey) throws EntitlementUserApiException {
SubscriptionBundle bundle = entitlementUserApi.getBundleForKey(bundleKey);
- if(bundle == null) {
- throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_KEY, bundleKey);
- }
-
return new BlockingSubscriptionBundle(bundle, blockingApi);
}
+ @Override
public List<SubscriptionBundle> getBundlesForAccount(UUID accountId) {
List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>();
List<SubscriptionBundle> bundles = entitlementUserApi.getBundlesForAccount(accountId);
@@ -83,6 +77,7 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
return result;
}
+ @Override
public List<Subscription> getSubscriptionsForBundle(UUID bundleId) {
List<Subscription> result = new ArrayList<Subscription>();
List<Subscription> subscriptions = entitlementUserApi.getSubscriptionsForBundle(bundleId);
@@ -92,6 +87,7 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
return result;
}
+ @Override
public List<Subscription> getSubscriptionsForKey(String bundleKey) {
List<Subscription> result = new ArrayList<Subscription>();
List<Subscription> subscriptions = entitlementUserApi.getSubscriptionsForKey(bundleKey);
@@ -101,20 +97,30 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
return result;
}
- public Subscription getBaseSubscription(UUID bundleId) {
+ @Override
+ public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(
+ UUID subscriptionId, String productName, DateTime requestedDate)
+ throws EntitlementUserApiException {
+ return entitlementUserApi.getDryRunChangePlanStatus(subscriptionId, productName, requestedDate);
+ }
+
+ @Override
+ public Subscription getBaseSubscription(UUID bundleId) throws EntitlementUserApiException {
return new BlockingSubscription(entitlementUserApi.getBaseSubscription(bundleId), blockingApi, checker);
}
+ @Override
public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleKey, CallContext context)
- throws EntitlementUserApiException {
+ throws EntitlementUserApiException {
try {
- checker.checkBlockedChange(accountId, Blockable.Type.ACCOUNT);
- return new BlockingSubscriptionBundle(entitlementUserApi.createBundleForAccount(accountId, bundleKey, context), blockingApi);
+ checker.checkBlockedChange(accountId, Blockable.Type.ACCOUNT);
+ return new BlockingSubscriptionBundle(entitlementUserApi.createBundleForAccount(accountId, bundleKey, context), blockingApi);
}catch (BlockingApiException e) {
throw new EntitlementUserApiException(e, e.getCode(), e.getMessage());
}
- }
+ }
+ @Override
public Subscription createSubscription(UUID bundleId, PlanPhaseSpecifier spec, DateTime requestedDate,
CallContext context) throws EntitlementUserApiException {
try {
@@ -125,8 +131,8 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
}
}
+ @Override
public DateTime getNextBillingDate(UUID account) {
return entitlementUserApi.getNextBillingDate(account);
}
-
}
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index 07dccb8..b1c5558 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -34,6 +34,7 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionEvent;
@@ -51,7 +52,8 @@ public class BillCycleDayCalculator {
this.entitlementApi = entitlementApi;
}
- protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionEvent transition, final Account account) throws CatalogApiException, AccountApiException {
+ protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionEvent transition, final Account account)
+ throws CatalogApiException, AccountApiException, EntitlementUserApiException {
Catalog catalog = catalogService.getFullCatalog();
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
index e8945c5..3f14062 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
@@ -27,6 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
@@ -35,6 +36,7 @@ import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.ChargeThruApi;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -108,27 +110,22 @@ public class DefaultBillingApi implements BillingApi {
} catch (AccountApiException e) {
log.warn("Failed while getting BillingEvent", e);
}
-
blockCalculator.insertBlockingEvents(result);
-
return result;
}
@Override
- public UUID getAccountIdFromSubscriptionId(UUID subscriptionId) {
- return chargeThruApi.getAccountIdFromSubscriptionId(subscriptionId);
+ public UUID getAccountIdFromSubscriptionId(UUID subscriptionId) throws EntitlementBillingApiException {
+ UUID result = chargeThruApi.getAccountIdFromSubscriptionId(subscriptionId);
+ if (result == null) {
+ throw new EntitlementBillingApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, subscriptionId.toString());
+ }
+ return result;
}
@Override
public void setChargedThroughDate(UUID subscriptionId, DateTime ctd, CallContext context) {
chargeThruApi.setChargedThroughDate(subscriptionId, ctd, context);
}
-
- @Override
- public void setChargedThroughDateFromTransaction(Transmogrifier transactionalDao, UUID subscriptionId,
- DateTime ctd, CallContext context) {
- chargeThruApi.setChargedThroughDateFromTransaction(transactionalDao, subscriptionId, ctd, context);
- }
-
}
overdue/pom.xml 7(+0 -7)
diff --git a/overdue/pom.xml b/overdue/pom.xml
index 6d98d63..3662f2b 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -104,13 +104,6 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <groups>fast,slow, stress</groups>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
diff --git a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
index 8da7713..83487ea 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
@@ -21,6 +21,7 @@ import org.apache.commons.lang.NotImplementedException;
import com.google.inject.Inject;
import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.junction.api.Blockable;
import com.ning.billing.junction.api.BlockingApi;
@@ -35,7 +36,7 @@ import com.ning.billing.overdue.service.ExtendedOverdueService;
import com.ning.billing.overdue.wrapper.OverdueWrapper;
import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
-public class DefaultOverdueUserApi implements OverdueUserApi{
+public class DefaultOverdueUserApi implements OverdueUserApi {
private final OverdueWrapperFactory factory;
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
index 640ca9a..d47f3f3 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
@@ -27,6 +27,7 @@ import java.util.UUID;
import org.joda.time.DateTime;
import com.google.inject.Inject;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.junction.api.Blockable;
@@ -56,7 +57,7 @@ public abstract class BillingStateCalculator<T extends Blockable> {
this.clock = clock;
}
- public abstract BillingState<T> calculateBillingState(T overdueable);
+ public abstract BillingState<T> calculateBillingState(T overdueable) throws EntitlementUserApiException;
protected DateTime earliest(SortedSet<Invoice> unpaidInvoices) {
return unpaidInvoices.first().getInvoiceDate();
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
index 544420f..89a7cc6 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
@@ -29,6 +29,7 @@ import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.invoice.api.Invoice;
@@ -50,7 +51,7 @@ public class BillingStateCalculatorBundle extends BillingStateCalculator<Subscr
}
@Override
- public BillingStateBundle calculateBillingState(SubscriptionBundle bundle) {
+ public BillingStateBundle calculateBillingState(SubscriptionBundle bundle) throws EntitlementUserApiException {
SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForBundle(bundle.getId(), bundle.getAccountId());
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
index 1aa4822..97220d5 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
@@ -16,8 +16,7 @@
package com.ning.billing.overdue.wrapper;
-import org.joda.time.Period;
-
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.junction.api.Blockable;
import com.ning.billing.junction.api.BlockingApi;
import com.ning.billing.overdue.OverdueApiException;
@@ -51,15 +50,19 @@ public class OverdueWrapper<T extends Blockable> {
}
public OverdueState<T> refresh() throws OverdueError, OverdueApiException {
- OverdueState<T> nextOverdueState;
- BillingState<T> billingState = billingStateCalcuator.calculateBillingState(overdueable);
- String previousOverdueStateName = api.getBlockingStateFor(overdueable).getStateName();
- nextOverdueState = overdueStateSet.calculateOverdueState(billingState, clock.getUTCNow());
+ try {
+ OverdueState<T> nextOverdueState;
+ BillingState<T> billingState = billingStateCalcuator.calculateBillingState(overdueable);
+ String previousOverdueStateName = api.getBlockingStateFor(overdueable).getStateName();
+ nextOverdueState = overdueStateSet.calculateOverdueState(billingState, clock.getUTCNow());
- if(!previousOverdueStateName.equals(nextOverdueState.getName())) {
- overdueStateApplicator.apply(overdueable, nextOverdueState, nextOverdueState);
- }
+ if(!previousOverdueStateName.equals(nextOverdueState.getName())) {
+ overdueStateApplicator.apply(overdueable, nextOverdueState, nextOverdueState);
+ }
- return nextOverdueState;
+ return nextOverdueState;
+ } catch (EntitlementUserApiException e) {
+ throw new OverdueError(e);
+ }
}
}
\ No newline at end of file
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
index 3d5b855..bb7ece3 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
@@ -86,7 +86,8 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
}
@Test(groups = {"fast"}, enabled=true)
- public void testcalculateBillingStateForBundle() {
+ public void testcalculateBillingStateForBundle() throws Exception {
+
UUID thisBundleId = new UUID(0L,0L);
UUID thatBundleId = new UUID(0L,1L);
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 2ed490c..2ac89d2 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -18,6 +18,7 @@ package com.ning.billing.payment.api;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -29,6 +30,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
@@ -68,9 +70,14 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId) {
+ public PaymentMethodInfo getPaymentMethod(final String accountKey, final String paymentMethodId)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.getPaymentMethodInfo(paymentMethodId);
+ Either<PaymentErrorEvent, PaymentMethodInfo> result = plugin.getPaymentMethodInfo(paymentMethodId);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, accountKey, paymentMethodId);
+ }
+ return result.getRight();
}
private PaymentProviderPlugin getPaymentProviderPlugin(String accountKey) {
@@ -100,60 +107,86 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey) {
+ public List<PaymentMethodInfo> getPaymentMethods(String accountKey)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.getPaymentMethods(accountKey);
+ Either<PaymentErrorEvent, List<PaymentMethodInfo>> result = plugin.getPaymentMethods(accountKey);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_PAYMENT_METHODS, accountKey);
+ }
+ return result.getRight();
}
@Override
- public Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context) {
+ public void updatePaymentGateway(String accountKey, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.updatePaymentGateway(accountKey);
+ Either<PaymentErrorEvent, Void> result = plugin.updatePaymentGateway(accountKey);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_UPD_GATEWAY_FAILED, accountKey, result.getLeft().getMessage());
+ }
+ return;
}
@Override
- public Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
+ public PaymentProviderAccount getPaymentProviderAccount(String accountKey)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.getPaymentProviderAccount(accountKey);
+ Either<PaymentErrorEvent, PaymentProviderAccount> result = plugin.getPaymentProviderAccount(accountKey);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_GET_PAYMENT_PROVIDER, accountKey, result.getLeft().getMessage());
+ }
+ return result.getRight();
}
@Override
- public Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context) {
+ public String addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.addPaymentMethod(accountKey, paymentMethod);
+ Either<PaymentErrorEvent, String> result = plugin.addPaymentMethod(accountKey, paymentMethod);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_ADD_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+ }
+ return result.getRight();
}
+
@Override
- public Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context) {
+ public void deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.deletePaymentMethod(accountKey, paymentMethodId);
+ Either<PaymentErrorEvent, Void> result = plugin.deletePaymentMethod(accountKey, paymentMethodId);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_DEL_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+ }
+ return;
}
@Override
- public Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context) {
+ public PaymentMethodInfo updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
- return plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
+ Either<PaymentErrorEvent, PaymentMethodInfo> result = plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_UPD_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+ }
+ return result.getRight();
}
@Override
- public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context) {
+ public List<PaymentInfoEvent> createPayment(String accountKey, List<String> invoiceIds, CallContext context)
+ throws PaymentApiException {
try {
final Account account = accountUserApi.getAccountByKey(accountKey);
return createPayment(account, invoiceIds, context);
} catch (AccountApiException e) {
- log.error("Error getting payment provider plugin.", e);
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = new ArrayList<Either<PaymentErrorEvent, PaymentInfoEvent>>();
- result.add(new Either.Left<PaymentErrorEvent, PaymentInfoEvent>((PaymentErrorEvent) new DefaultPaymentErrorEvent("createPaymentError", e.getMessage(),
- null,
- null,
- context.getUserToken())));
- return result;
+ throw new PaymentApiException(e);
}
-
}
@Override
- public Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context) {
+ public PaymentInfoEvent createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context)
+ throws PaymentApiException {
PaymentAttempt paymentAttempt = paymentDao.getPaymentAttemptById(paymentAttemptId);
if (paymentAttempt != null) {
@@ -165,40 +198,35 @@ public class DefaultPaymentApi implements PaymentApi {
if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0 ) {
// TODO: send a notification that invoice was ignored?
log.info("Received invoice for payment with outstanding amount of 0 {} ", invoice);
- return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("invoice_balance_0",
- "Invoice balance was 0 or less",
- paymentAttempt.getAccountId(),
- paymentAttempt.getInvoiceId(),
- context.getUserToken()));
- }
- else {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_WITH_NON_POSITIVE_INV, account.getId());
+
+ } else {
+
PaymentAttempt newPaymentAttempt = new PaymentAttempt.Builder(paymentAttempt)
.setRetryCount(paymentAttempt.getRetryCount() + 1)
.setPaymentAttemptId(UUID.randomUUID())
.build();
paymentDao.createPaymentAttempt(newPaymentAttempt, context);
- return processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
+ Either<PaymentErrorEvent, PaymentInfoEvent> result = processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT, account.getId(), paymentAttemptId, result.getLeft().getMessage());
+ }
+ return result.getRight();
+
}
}
} catch (AccountApiException e) {
- log.error("Error creating payment attempt.", e);
- return new Either.Left<PaymentErrorEvent, PaymentInfoEvent>((PaymentErrorEvent) new DefaultPaymentErrorEvent("createPaymentError", e.getMessage(),
- null,
- null,
- context.getUserToken()));
-
+ throw new PaymentApiException(e);
}
}
- return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("retry_payment_error",
- "Could not load payment attempt, invoice or account for id " + paymentAttemptId,
- paymentAttempt.getAccountId(),
- paymentAttempt.getInvoiceId(),
- context.getUserToken()));
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_BAD, paymentAttemptId);
}
@Override
- public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context) {
+ public List<PaymentInfoEvent> createPayment(Account account, List<String> invoiceIds, CallContext context)
+ throws PaymentApiException {
+
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
List<Either<PaymentErrorEvent, PaymentInfoEvent>> processedPaymentsOrErrors = new ArrayList<Either<PaymentErrorEvent, PaymentInfoEvent>>(invoiceIds.size());
@@ -225,7 +253,15 @@ public class DefaultPaymentApi implements PaymentApi {
}
}
- return processedPaymentsOrErrors;
+ List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = processedPaymentsOrErrors;
+ List<PaymentInfoEvent> info = new LinkedList<PaymentInfoEvent>();
+ for (Either<PaymentErrorEvent, PaymentInfoEvent> cur : result) {
+ if (cur.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT, account.getId(), cur.getLeft().getMessage());
+ }
+ info.add(cur.getRight());
+ }
+ return info;
}
private Either<PaymentErrorEvent, PaymentInfoEvent> processPayment(PaymentProviderPlugin plugin, Account account, Invoice invoice,
@@ -271,10 +307,10 @@ public class DefaultPaymentApi implements PaymentApi {
invoice.getId(),
paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : paymentInfo.getAmount(),
// paymentInfo.getRefundAmount(), TODO
- paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
- paymentAttempt.getPaymentAttemptId(),
- paymentAttempt.getPaymentAttemptDate(),
- context);
+ paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
+ paymentAttempt.getPaymentAttemptId(),
+ paymentAttempt.getPaymentAttemptDate(),
+ context);
return paymentOrError;
}
@@ -311,24 +347,29 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context) {
+ public String createPaymentProviderAccount(Account account, CallContext context)
+ throws PaymentApiException {
final PaymentProviderPlugin plugin = getPaymentProviderPlugin((Account)null);
- return plugin.createPaymentProviderAccount(account);
+ Either<PaymentErrorEvent, String> result = plugin.createPaymentProviderAccount(account);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_PROVIDER_ACCOUNT, account.getId(), result.getLeft().getMessage());
+ }
+ return result.getRight();
}
@Override
- public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String externalKey, CallContext context) {
+ public void updatePaymentProviderAccountContact(String externalKey, CallContext context)
+ throws PaymentApiException {
try {
Account account = accountUserApi.getAccountByKey(externalKey);
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
- return plugin.updatePaymentProviderAccountExistingContact(account);
+ Either<PaymentErrorEvent, Void> result = plugin.updatePaymentProviderAccountExistingContact(account);
+ if (result.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_UPD_PAYMENT_PROVIDER_ACCOUNT, account.getId(), result.getLeft().getMessage());
+ }
+ return;
} catch (AccountApiException e) {
- log.error("Error updating payment provider account contact.", e);
- return new Either.Left<PaymentErrorEvent, Void>((PaymentErrorEvent) new DefaultPaymentErrorEvent("updatePaymentProviderAccountContactError", e.getMessage(),
- null,
- null,
- context.getUserToken()));
-
+ throw new PaymentApiException(e);
}
}
@@ -338,11 +379,19 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account,
- List<String> invoiceIds,
- CallContext context) {
+ public List<PaymentInfoEvent> createRefund(Account account, List<String> invoiceIds, CallContext context)
+ throws PaymentApiException {
+
final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
- return plugin.processRefund(account);
+ List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = plugin.processRefund(account);
+ List<PaymentInfoEvent> info = new LinkedList<PaymentInfoEvent>();
+ for (Either<PaymentErrorEvent, PaymentInfoEvent> cur : result) {
+ if (cur.isLeft()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_REFUND, account.getId(), cur.getLeft().getMessage());
+ }
+ info.add(cur.getRight());
+ }
+ return info;
}
@Override
diff --git a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
index 3102e5c..2077c5e 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -18,23 +18,29 @@ package com.ning.billing.payment;
import java.util.Arrays;
import java.util.List;
+import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.payment.api.DefaultPaymentErrorEvent;
import com.ning.billing.payment.api.Either;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
+import com.ning.billing.util.bus.BusEvent.BusEventType;
+import com.ning.billing.util.bus.BusEvent;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallOrigin;
import com.ning.billing.util.callcontext.DefaultCallContext;
@@ -52,39 +58,51 @@ public class RequestProcessor {
@Inject
public RequestProcessor(Clock clock,
- AccountUserApi accountUserApi,
- PaymentApi paymentApi,
- PaymentProviderPluginRegistry pluginRegistry,
- Bus eventBus) {
+ AccountUserApi accountUserApi,
+ PaymentApi paymentApi,
+ PaymentProviderPluginRegistry pluginRegistry,
+ Bus eventBus) {
this.clock = clock;
this.accountUserApi = accountUserApi;
this.paymentApi = paymentApi;
this.eventBus = eventBus;
}
+
+ private void postPaymentEvent(BusEvent ev, UUID accountId) {
+ if (ev == null) {
+ return;
+ }
+ try {
+ eventBus.post(ev);
+ } catch (EventBusException e) {
+ log.error("Failed to post Payment event event for account {} ", accountId, e);
+ }
+ }
@Subscribe
public void receiveInvoice(InvoiceCreationEvent event) {
+
+
log.info("Received invoice creation notification for account {} and invoice {}", event.getAccountId(), event.getInvoiceId());
+ PaymentErrorEvent errorEvent = null;
try {
final Account account = accountUserApi.getAccountById(event.getAccountId());
-
- if (account == null) {
- log.info("could not process invoice payment: could not find a valid account for event {}", event);
- }
- else {
+ if (account != null) {
CallContext context = new DefaultCallContext("PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, clock);
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
- if (!results.isEmpty()) {
- Either<PaymentErrorEvent, PaymentInfoEvent> result = results.get(0);
- try {
- eventBus.post(result.isLeft() ? result.getLeft() : result.getRight());
- } catch (EventBusException e) {
- log.error("Failed to post Payment event event for account {} ", account.getId(), e);
- }
- }
+ List<PaymentInfoEvent> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
+ PaymentInfoEvent infoEvent = (!results.isEmpty()) ? results.get(0) : null;
+ postPaymentEvent(infoEvent, account.getId());
+ return;
+ } else {
+ errorEvent = new DefaultPaymentErrorEvent(null, "Failed to retrieve account", event.getAccountId(), null, null);
}
} catch(AccountApiException e) {
- log.warn("could not process invoice payment", e);
+ log.error("Failed to process invoice payment", e);
+ errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);
+ } catch (PaymentApiException e) {
+ log.error("Failed to process invoice payment", e);
+ errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);
}
+ postPaymentEvent(errorEvent, event.getAccountId());
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/RetryService.java b/payment/src/main/java/com/ning/billing/payment/RetryService.java
index 447bb74..abc1fde 100644
--- a/payment/src/main/java/com/ning/billing/payment/RetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/RetryService.java
@@ -24,6 +24,8 @@ import com.ning.billing.util.callcontext.DefaultCallContext;
import com.ning.billing.util.callcontext.UserType;
import com.ning.billing.util.clock.Clock;
import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.ning.billing.config.PaymentConfig;
@@ -31,6 +33,7 @@ import com.ning.billing.lifecycle.KillbillService;
import com.ning.billing.lifecycle.LifecycleHandlerType;
import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.api.PaymentStatus;
@@ -42,6 +45,9 @@ import com.ning.billing.util.notificationq.NotificationQueueService.Notification
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
public class RetryService implements KillbillService {
+
+ private static final Logger log = LoggerFactory.getLogger(RetryService.class);
+
public static final String SERVICE_NAME = "retry-service";
public static final String QUEUE_NAME = "retry-events";
@@ -107,15 +113,14 @@ public class RetryService implements KillbillService {
}
private void retry(String paymentAttemptId, CallContext context) {
- PaymentInfoEvent paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
-
- if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
- // update payment attempt with success and notify invoice api of payment
- System.out.println("Found processed payment");
- }
- else {
- System.out.println("Creating payment for payment attempt " + paymentAttemptId);
+ try {
+ PaymentInfoEvent paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
+ if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
+ return;
+ }
paymentApi.createPaymentForPaymentAttempt(UUID.fromString(paymentAttemptId), context);
+ } catch (PaymentApiException e) {
+ log.error(String.format("Failed to retry payment for %s"), e);
}
}
}
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 4d3c630..85aa07b 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -102,12 +102,11 @@ public abstract class TestPaymentApi {
new BigDecimal("1.0"),
Currency.USD));
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+ List<PaymentInfoEvent> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
assertEquals(results.size(), 1);
- assertTrue(results.get(0).isRight());
- PaymentInfoEvent paymentInfo = results.get(0).getRight();
+ PaymentInfoEvent paymentInfo = results.get(0);
assertNotNull(paymentInfo.getPaymentId());
assertTrue(paymentInfo.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
@@ -145,7 +144,7 @@ public abstract class TestPaymentApi {
}
- private PaymentProviderAccount setupAccountWithPaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
+ private PaymentProviderAccount setupAccountWithPaypalPaymentMethod() throws Exception {
final Account account = testHelper.createTestPayPalAccount();
paymentApi.createPaymentProviderAccount(account, context);
@@ -156,32 +155,23 @@ public abstract class TestPaymentApi {
.setEmail(account.getEmail())
.setDefaultMethod(true)
.build();
- Either<PaymentErrorEvent, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
+ String paymentMethodId = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
- assertTrue(paymentMethodIdOrError.isRight());
- assertNotNull(paymentMethodIdOrError.getRight());
+ PaymentMethodInfo paymentMethodInfo = paymentApi.getPaymentMethod(accountKey, paymentMethodId);
- Either<PaymentErrorEvent, PaymentMethodInfo> paymentMethodInfoOrError = paymentApi.getPaymentMethod(accountKey, paymentMethodIdOrError.getRight());
-
- assertTrue(paymentMethodInfoOrError.isRight());
- assertNotNull(paymentMethodInfoOrError.getRight());
-
- Either<PaymentErrorEvent, PaymentProviderAccount> accountOrError = paymentApi.getPaymentProviderAccount(accountKey);
-
- assertTrue(accountOrError.isRight());
-
- return accountOrError.getRight();
+ PaymentProviderAccount accountResult = paymentApi.getPaymentProviderAccount(accountKey);
+ return accountResult;
}
@Test(enabled=true)
- public void testCreatePaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
+ public void testCreatePaypalPaymentMethod() throws Exception {
PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
assertNotNull(account);
paymentApi.getPaymentMethods(account.getAccountKey());
}
@Test(enabled=true)
- public void testUpdatePaymentProviderAccountContact() throws AccountApiException, EntityPersistenceException {
+ public void testUpdatePaymentProviderAccountContact() throws Exception {
final Account account = testHelper.createTestPayPalAccount();
paymentApi.createPaymentProviderAccount(account, context);
@@ -198,19 +188,12 @@ public abstract class TestPaymentApi {
.billingCycleDay(account.getBillCycleDay())
.build();
- Either<PaymentErrorEvent, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
- assertTrue(voidOrError.isRight());
+ paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
}
@Test(enabled=true)
- public void testCannotDeleteDefaultPaymentMethod() throws AccountApiException, EntityPersistenceException {
+ public void testCannotDeleteDefaultPaymentMethod() throws Exception {
PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
-
- Either<PaymentErrorEvent, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
-
- assertTrue(errorOrVoid.isLeft());
+ paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
}
-
-
-
}
diff --git a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
index 5ab2157..9a49780 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -44,6 +44,7 @@ import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
import com.ning.billing.mock.glue.MockJunctionModule;
import com.ning.billing.payment.api.Either;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
@@ -139,11 +140,13 @@ public class TestRetryService {
Currency.USD));
mockPaymentProviderPlugin.makeNextInvoiceFail();
-
- List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
-
- assertEquals(results.size(), 1);
- assertTrue(results.get(0).isLeft());
+ boolean failed = false;
+ try {
+ paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+ } catch (PaymentApiException e) {
+ failed = true;
+ }
+ assertTrue(failed);
List<Notification> pendingNotifications = mockNotificationQueue.getPendingEvents();