killbill-memoizeit
Changes
analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java 4(+2 -2)
beatrix/pom.xml 29(+29 -0)
beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java 140(+140 -0)
beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/MockPaymentInfoReceiver.java 2(+1 -1)
beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java 74(+74 -0)
beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestNotifyInvoicePaymentApi.java 6(+3 -3)
beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentInvoiceIntegration.java 5(+3 -2)
beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentProvider.java 7(+4 -3)
bin/clean-and-install 22(+22 -0)
entitlement/pom.xml 54(+24 -30)
entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java 33(+1 -32)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java 19(+4 -15)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java 1(+0 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionApiService.java 4(+2 -2)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java 6(+3 -3)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java 4(+0 -4)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java 75(+66 -9)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java 2(+1 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java 19(+19 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java 1(+0 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java 75(+75 -0)
entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java 168(+82 -86)
entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java 38(+32 -6)
entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java 8(+4 -4)
entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java 117(+76 -41)
entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java 117(+75 -42)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java 232(+125 -107)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java 8(+4 -4)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java 185(+109 -76)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java 12(+6 -6)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java 2(+1 -1)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java 10(+5 -5)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java 36(+22 -14)
entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java 14(+7 -7)
entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java 3(+1 -2)
invoice/pom.xml 45(+12 -33)
invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg 22(+22 -0)
invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg 22(+22 -0)
invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java 7(+3 -4)
invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java 67(+13 -54)
junction/pom.xml 14(+2 -12)
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 7(+5 -2)
junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java 202(+202 -0)
junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscriptionEvent.java 333(+333 -0)
junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java 107(+72 -35)
overdue/pom.xml 21(+1 -20)
overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java 3(+2 -1)
overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java 3(+2 -1)
payment/pom.xml 28(+11 -17)
pom.xml 12(+12 -0)
server/pom.xml 12(+8 -4)
Details
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
index f944ccb..5dabd40 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
@@ -19,6 +19,7 @@ package com.ning.billing.account.api.user;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountCreationEvent;
import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.DefaultAccount;
import com.ning.billing.catalog.api.Currency;
import java.util.UUID;
@@ -45,7 +46,7 @@ public class DefaultAccountCreationEvent implements AccountCreationEvent {
public DefaultAccountCreationEvent(Account data, UUID userToken) {
this.id = data.getId();
- this.data = data;
+ this.data = new DefaultAccountData(data);
this.userToken = userToken;
}
@@ -131,6 +132,29 @@ public class DefaultAccountCreationEvent implements AccountCreationEvent {
private final boolean isMigrated;
private final boolean isNotifiedForInvoices;
+
+ public DefaultAccountData(Account d) {
+ this(d.getExternalKey() != null ? d.getExternalKey().toString() : null,
+ d.getName(),
+ d.getFirstNameLength(),
+ d.getEmail(),
+ d.getBillCycleDay(),
+ d.getCurrency() != null ? d.getCurrency().name() : null,
+ d.getPaymentProviderName(),
+ d.getTimeZone() != null ? d.getTimeZone().getID() : null,
+ d.getLocale(),
+ d.getAddress1(),
+ d.getAddress2(),
+ d.getCompanyName(),
+ d.getCity(),
+ d.getStateOrProvince(),
+ d.getPostalCode(),
+ d.getCountry(),
+ d.getPhone(),
+ d.isMigrated(),
+ d.isNotifiedForInvoices());
+ }
+
@JsonCreator
public DefaultAccountData(@JsonProperty("externalKey") String externalKey,
@JsonProperty("name") String name,
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java
index b9eaa99..8ed05ee 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java
@@ -37,7 +37,7 @@ import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTempla
@ExternalizedSqlViaStringTemplate3
@RegisterMapper({UuidMapper.class, AccountMapper.class})
-public interface AccountSqlDao extends UpdatableEntitySqlDao<Account>, Transactional<AccountSqlDao>, Transmogrifier, AuditSqlDao {
+public interface AccountSqlDao extends UpdatableEntitySqlDao<Account>, Transactional<AccountSqlDao>, Transmogrifier {
@SqlQuery
public Account getAccountByKey(@Bind("externalKey") final String key);
diff --git a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
index 01c3dca..6d52d10 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
@@ -32,6 +32,9 @@ import com.ning.billing.util.tag.dao.TagDao;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.Transaction;
import org.skife.jdbi.v2.TransactionStatus;
+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;
@@ -43,9 +46,12 @@ import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
import com.ning.billing.util.customfield.CustomField;
import com.ning.billing.util.customfield.dao.CustomFieldSqlDao;
import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.Bus.EventBusException;
import com.ning.billing.util.tag.Tag;
public class AuditedAccountDao implements AccountDao {
+ private final static Logger log = LoggerFactory.getLogger(AuditedAccountDao.class);
+
private final AccountSqlDao accountSqlDao;
private final TagDao tagDao;
private final CustomFieldDao customFieldDao;
@@ -127,19 +133,23 @@ public class AuditedAccountDao implements AccountDao {
transactionalDao.create(account, context);
// insert history
- Long recordId = accountSqlDao.getRecordId(TableName.ACCOUNT, account.getId().toString());
+ Long recordId = accountSqlDao.getRecordId(account.getId().toString());
EntityHistory<Account> history = new EntityHistory<Account>(account.getId(), recordId, account, ChangeType.INSERT);
accountSqlDao.insertHistoryFromTransaction(history, context);
// insert audit
- Long historyRecordId = accountSqlDao.getHistoryRecordId(TableName.ACCOUNT_HISTORY, recordId);
- EntityAudit audit = new EntityAudit(historyRecordId, ChangeType.INSERT);
- accountSqlDao.insertAuditFromTransaction(TableName.ACCOUNT_HISTORY, audit, context);
+ Long historyRecordId = accountSqlDao.getHistoryRecordId(recordId);
+ EntityAudit audit = new EntityAudit(TableName.ACCOUNT_HISTORY, historyRecordId, ChangeType.INSERT);
+ accountSqlDao.insertAuditFromTransaction(audit, context);
saveTagsFromWithinTransaction(account, transactionalDao, context);
saveCustomFieldsFromWithinTransaction(account, transactionalDao, context);
AccountCreationEvent creationEvent = new DefaultAccountCreationEvent(account, context.getUserToken());
- eventBus.post(creationEvent);
+ try {
+ eventBus.postFromTransaction(creationEvent, transactionalDao);
+ } catch (EventBusException e) {
+ log.warn("Failed to post account creation event for account " + account.getId(), e);
+ }
return null;
}
});
@@ -159,9 +169,9 @@ public class AuditedAccountDao implements AccountDao {
try {
accountSqlDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
@Override
- public Void inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws EntityPersistenceException, Bus.EventBusException {
+ public Void inTransaction(final AccountSqlDao transactional, final TransactionStatus status) throws EntityPersistenceException, Bus.EventBusException {
String accountId = account.getId().toString();
- Account currentAccount = accountSqlDao.getById(accountId);
+ Account currentAccount = transactional.getById(accountId);
if (currentAccount == null) {
throw new EntityPersistenceException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
}
@@ -171,22 +181,26 @@ public class AuditedAccountDao implements AccountDao {
throw new EntityPersistenceException(ErrorCode.ACCOUNT_CANNOT_CHANGE_EXTERNAL_KEY, currentKey);
}
- accountSqlDao.update(account, context);
+ transactional.update(account, context);
- Long recordId = accountSqlDao.getRecordId(TableName.ACCOUNT, account.getId().toString());
+ Long recordId = accountSqlDao.getRecordId(account.getId().toString());
EntityHistory<Account> history = new EntityHistory<Account>(account.getId(), recordId, account, ChangeType.INSERT);
accountSqlDao.insertHistoryFromTransaction(history, context);
- Long historyRecordId = accountSqlDao.getHistoryRecordId(TableName.ACCOUNT_HISTORY, recordId);
- EntityAudit audit = new EntityAudit(historyRecordId, ChangeType.INSERT);
- accountSqlDao.insertAuditFromTransaction(TableName.ACCOUNT_HISTORY, audit, context);
+ Long historyRecordId = accountSqlDao.getHistoryRecordId(recordId);
+ EntityAudit audit = new EntityAudit(TableName.ACCOUNT_HISTORY, historyRecordId, ChangeType.INSERT);
+ accountSqlDao.insertAuditFromTransaction(audit, context);
- saveTagsFromWithinTransaction(account, accountSqlDao, context);
- saveCustomFieldsFromWithinTransaction(account, accountSqlDao, context);
+ saveTagsFromWithinTransaction(account, transactional, context);
+ saveCustomFieldsFromWithinTransaction(account, transactional, context);
AccountChangeEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), context.getUserToken(), currentAccount, account);
if (changeEvent.hasChanges()) {
- eventBus.post(changeEvent);
+ try {
+ eventBus.postFromTransaction(changeEvent, transactional);
+ } catch (EventBusException e) {
+ log.warn("Failed to post account change event for account " + account.getId(), e);
+ }
}
return null;
}
diff --git a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
index e3009e8..956d878 100644
--- a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
+++ b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
@@ -23,15 +23,17 @@ import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.account.api.DefaultAccountService;
import com.ning.billing.account.api.user.DefaultAccountUserApi;
import com.ning.billing.account.dao.AccountDao;
+import com.ning.billing.account.dao.AccountEmailDao;
import com.ning.billing.account.dao.AuditedAccountDao;
+import com.ning.billing.account.dao.AuditedAccountEmailDao;
import com.ning.billing.util.glue.RealImplementation;
public class AccountModule extends AbstractModule {
-
private void installConfig() {
}
protected void installAccountDao() {
+ bind(AccountEmailDao.class).to(AuditedAccountEmailDao.class).asEagerSingleton();
bind(AccountDao.class).to(AuditedAccountDao.class).asEagerSingleton();
}
diff --git a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
index fb3c480..9eb462f 100644
--- a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
+++ b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
@@ -101,6 +101,8 @@ public abstract class AccountDaoTestBase {
public Void inTransaction(Handle h, TransactionStatus status) throws Exception {
h.execute("truncate table accounts");
h.execute("truncate table notifications");
+ h.execute("truncate table bus_events");
+ h.execute("truncate table claimed_bus_events");
h.execute("truncate table claimed_notifications");
h.execute("truncate table tag_definitions");
h.execute("truncate table tags");
diff --git a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
index 74fe321..1559420 100644
--- a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
+++ b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
@@ -17,7 +17,9 @@
package com.ning.billing.account.glue;
import com.ning.billing.account.dao.AccountDao;
+import com.ning.billing.account.dao.AccountEmailDao;
import com.ning.billing.account.dao.MockAccountDao;
+import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.util.clock.MockClockModule;
import com.ning.billing.util.glue.CallContextModule;
import com.ning.billing.util.glue.FieldStoreModule;
@@ -27,6 +29,8 @@ public class AccountModuleWithMocks extends AccountModule {
@Override
protected void installAccountDao() {
bind(MockAccountDao.class).asEagerSingleton();
+ AccountEmailDao accountEmailDao = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountEmailDao.class);
+ bind(AccountEmailDao.class).toInstance(accountEmailDao);
bind(AccountDao.class).to(MockAccountDao.class);
}
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 aa6d6fa..e692eb7 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,17 +60,17 @@ 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
+ * Notification handler for Account changes
*
* @param accountId account id changed
* @param changedFields list of changed fields
@@ -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.getId());
+ 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);
}
-
}
/**
@@ -173,21 +176,25 @@ public class BusinessAccountRecorder {
}
// Retrieve payments information for these invoices
- final PaymentInfoEvent payment = paymentApi.getLastPaymentInfo(invoiceIds);
-
- lastPaymentStatus = payment.getStatus();
- paymentMethod = payment.getPaymentMethod();
- creditCardType = payment.getCardType();
- billingAddressCountry = payment.getCardCountry();
+ try {
+ final PaymentInfoEvent payment = paymentApi.getLastPaymentInfo(invoiceIds);
+
+ 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.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+ } catch (PaymentApiException ex) {
+ // TODO: handle this exception
+ }
}
-
- bac.setLastPaymentStatus(lastPaymentStatus);
- bac.setPaymentMethod(paymentMethod);
- bac.setCreditCardType(creditCardType);
- bac.setBillingAddressCountry(billingAddressCountry);
- bac.setLastInvoiceDate(lastInvoiceDate);
- bac.setTotalInvoiceBalance(totalInvoiceBalance);
-
- bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
index 57d164f..0044758 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
@@ -98,13 +98,13 @@ public class BusinessSubscriptionTransitionRecorder
final SubscriptionBundle bundle = entitlementApi.getBundleFromId(transition.getBundleId());
if (bundle != null) {
transitionKey = bundle.getKey();
-
+
final Account account = accountApi.getAccountById(bundle.getAccountId());
if (account != null) {
accountKey = account.getExternalKey();
currency = account.getCurrency();
}
- }
+ }
// The ISubscriptionTransition interface gives us all the prev/next information we need but the start date
// of the previous plan. We need to retrieve it from our own transitions table
diff --git a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
index cbab941..e1df28b 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
@@ -16,22 +16,22 @@
package com.ning.billing.analytics;
-import com.ning.billing.util.email.EmailModule;
-import com.ning.billing.util.glue.GlobalLockerModule;
import org.skife.jdbi.v2.IDBI;
import com.ning.billing.account.glue.AccountModule;
import com.ning.billing.analytics.setup.AnalyticsModule;
import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.entitlement.glue.EntitlementModule;
-import com.ning.billing.invoice.glue.InvoiceModule;
-import com.ning.billing.junction.MockBlockingModule;
-import com.ning.billing.junction.glue.JunctionModule;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
+import com.ning.billing.invoice.glue.DefaultInvoiceModule;
+import com.ning.billing.junction.glue.DefaultJunctionModule;
import com.ning.billing.payment.setup.PaymentModule;
+import com.ning.billing.util.email.EmailModule;
+import com.ning.billing.util.email.templates.TemplateModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.CallContextModule;
import com.ning.billing.util.glue.ClockModule;
import com.ning.billing.util.glue.FieldStoreModule;
+import com.ning.billing.util.glue.GlobalLockerModule;
import com.ning.billing.util.glue.NotificationQueueModule;
import com.ning.billing.util.glue.TagStoreModule;
import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
@@ -52,12 +52,13 @@ public class AnalyticsTestModule extends AnalyticsModule
install(new TagStoreModule());
install(new AccountModule());
install(new BusModule());
- install(new EntitlementModule());
- install(new InvoiceModule());
+ install(new DefaultEntitlementModule());
+ install(new DefaultInvoiceModule());
+ install(new TemplateModule());
install(new PaymentModule());
install(new TagStoreModule());
install(new NotificationQueueModule());
- install(new JunctionModule());
+ install(new DefaultJunctionModule());
// Install the Dao layer
final MysqlTestingHelper helper = new MysqlTestingHelper();
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index 0a01c34..1477dfa 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -33,7 +33,6 @@ import org.joda.time.DateTime;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
@@ -157,15 +156,7 @@ public class TestAnalyticsService {
private CatalogService catalogService;
private Catalog catalog;
-
- @BeforeMethod(groups = "slow")
- public void cleanup() throws Exception
- {
- helper.cleanupTable("bst");
- helper.cleanupTable("bac");
- }
-
-
+
@BeforeClass(groups = "slow")
public void startMysql() throws IOException, ClassNotFoundException, SQLException, EntitlementUserApiException {
@@ -176,6 +167,8 @@ public class TestAnalyticsService {
// Killbill generic setup
setupBusAndMySQL();
+ helper.cleanupAllTables();
+
tagDao.create(TAG_ONE, context);
tagDao.create(TAG_TWO, context);
@@ -197,7 +190,6 @@ public class TestAnalyticsService {
}
private void setupBusAndMySQL() throws IOException {
- bus.start();
final String analyticsDdl = IOUtils.toString(BusinessSubscriptionTransitionDao.class.getResourceAsStream("/com/ning/billing/analytics/ddl.sql"));
final String accountDdl = IOUtils.toString(BusinessSubscriptionTransitionDao.class.getResourceAsStream("/com/ning/billing/account/ddl.sql"));
@@ -216,7 +208,9 @@ public class TestAnalyticsService {
helper.initDb(utilDdl);
helper.initDb(junctionDdl);
- helper.cleanupAllTables();
+ helper.cleanupAllTables();
+
+ bus.start();
}
private void createSubscriptionTransitionEvent(final Account account) throws EntitlementUserApiException {
@@ -283,9 +277,9 @@ public class TestAnalyticsService {
invoiceCreationNotification = new DefaultInvoiceCreationEvent(invoice.getId(), account.getId(),
INVOICE_AMOUNT, ACCOUNT_CURRENCY, clock.getUTCNow(), null);
- paymentInfoNotification = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString()).setPaymentMethod(PAYMENT_METHOD).setCardCountry(CARD_COUNTRY).build();
+ paymentInfoNotification = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID()).setPaymentMethod(PAYMENT_METHOD).setCardCountry(CARD_COUNTRY).build();
final PaymentAttempt paymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice.getId(), account.getId(), BigDecimal.TEN,
- ACCOUNT_CURRENCY, clock.getUTCNow(), clock.getUTCNow(), paymentInfoNotification.getPaymentId(), 1);
+ ACCOUNT_CURRENCY, clock.getUTCNow(), clock.getUTCNow(), paymentInfoNotification.getId(), 1, null, null);
paymentDao.createPaymentAttempt(paymentAttempt, context);
paymentDao.savePaymentInfo(paymentInfoNotification, context);
Assert.assertEquals(paymentDao.getPaymentInfoList(Arrays.asList(invoice.getId().toString())).size(), 1);
@@ -296,7 +290,7 @@ public class TestAnalyticsService {
helper.stopMysql();
}
- @Test(groups = "slow")
+ @Test(groups = "slow", enabled=true)
public void testRegisterForNotifications() throws Exception {
// Make sure the service has been instantiated
Assert.assertEquals(service.getName(), "analytics-service");
@@ -312,9 +306,8 @@ public class TestAnalyticsService {
// Send events and wait for the async part...
bus.post(transition);
-
bus.post(accountCreationNotification);
- Thread.sleep(1000);
+ Thread.sleep(5000);
Assert.assertEquals(subscriptionDao.getTransitions(KEY).size(), 1);
Assert.assertEquals(subscriptionDao.getTransitions(KEY).get(0), expectedTransition);
@@ -329,12 +322,12 @@ public class TestAnalyticsService {
// Post the same invoice event again - the invoice balance shouldn't change
bus.post(invoiceCreationNotification);
- Thread.sleep(1000);
+ Thread.sleep(5000);
Assert.assertTrue(accountDao.getAccount(ACCOUNT_KEY).getTotalInvoiceBalance().compareTo(INVOICE_AMOUNT) == 0);
// Test payment integration - the fields have already been populated, just make sure the code is exercised
bus.post(paymentInfoNotification);
- Thread.sleep(1000);
+ Thread.sleep(5000);
Assert.assertEquals(accountDao.getAccount(ACCOUNT_KEY).getPaymentMethod(), PAYMENT_METHOD);
Assert.assertEquals(accountDao.getAccount(ACCOUNT_KEY).getBillingAddressCountry(), CARD_COUNTRY);
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
index 079df6e..d8c856d 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
@@ -263,10 +263,8 @@ public class TestAnalyticsDao
Assert.assertEquals(transitions.get(0).getKey(), transition.getKey());
Assert.assertEquals(transitions.get(0).getRequestedTimestamp(), transition.getRequestedTimestamp());
Assert.assertEquals(transitions.get(0).getEvent(), transition.getEvent());
- // Null Plan and Phase doesn't make sense so we turn the subscription into a null
- // STEPH not sure why that fails ?
- //Assert.assertNull(transitions.get(0).getPreviousSubscription());
- //Assert.assertNull(transitions.get(0).getNextSubscription());
+ Assert.assertNull(transitions.get(0).getPreviousSubscription());
+ Assert.assertNull(transitions.get(0).getNextSubscription());
}
@Test(groups = "slow")
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/SubscriptionEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvent.java
index 8dc3312..2745c33 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvent.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEvent.java
@@ -65,4 +65,5 @@ public interface SubscriptionEvent extends BusEvent {
Integer getRemainingEventsForUserOperation();
Long getTotalOrdering();
+
}
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 f6856eb..3aa190b 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
@@ -196,7 +201,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/glue/EntitlementModule.java b/api/src/main/java/com/ning/billing/glue/EntitlementModule.java
new file mode 100644
index 0000000..421e68d
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/glue/EntitlementModule.java
@@ -0,0 +1,31 @@
+/*
+ * 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.glue;
+
+public interface EntitlementModule {
+
+ public abstract void installEntitlementService();
+
+ public abstract void installEntitlementUserApi();
+
+ public abstract void installEntitlementMigrationApi();
+
+ public abstract void installChargeThruApi();
+
+ public abstract void installEntitlementTimelineApi();
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
index 9fb0bb3..0a34604 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
@@ -42,7 +42,7 @@ public interface InvoicePaymentApi {
public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context);
public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amountOutstanding, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context);
-
+
public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context);
}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java b/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
index 4399176..74764b3 100644
--- a/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
@@ -17,13 +17,14 @@
package com.ning.billing.overdue;
import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.junction.api.Blockable;
import com.ning.billing.overdue.config.api.BillingState;
import com.ning.billing.overdue.config.api.OverdueError;
public interface OverdueUserApi {
- public <T extends Blockable> OverdueState<T> refreshOverdueStateFor(T overdueable) throws OverdueError, CatalogApiException;
+ public <T extends Blockable> OverdueState<T> refreshOverdueStateFor(T overdueable) throws OverdueError, CatalogApiException, EntitlementUserApiException;
public <T extends Blockable> void setOverrideBillingStateForAccount(T overdueable, BillingState<T> state) throws OverdueError;
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 f73f2a9..b1bef23 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,37 +26,57 @@ 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 UUID id)
+ throws PaymentApiException;
- List<PaymentInfoEvent> getPaymentInfoList(List<String> invoiceIds);
- PaymentInfoEvent getLastPaymentInfo(List<String> invoiceIds);
+ public List<PaymentInfoEvent> getPaymentInfoList(final List<String> invoiceIds)
+ throws PaymentApiException;
- List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
+ public PaymentInfoEvent getLastPaymentInfo(final List<String> invoiceIds)
+ throws PaymentApiException;
- 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/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java b/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
index 6dca30c..a424fc6 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
@@ -26,7 +26,7 @@ import java.util.UUID;
public interface PaymentAttempt extends Entity {
DateTime getInvoiceDate();
- String getPaymentId();
+ UUID getPaymentId();
DateTime getPaymentAttemptDate();
@@ -39,4 +39,8 @@ public interface PaymentAttempt extends Entity {
Currency getCurrency();
Integer getRetryCount();
+
+ DateTime getCreatedDate();
+
+ DateTime getUpdatedDate();
}
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java b/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
index c3b1850..c4cabb9 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
@@ -23,9 +23,6 @@ import org.joda.time.DateTime;
import com.ning.billing.util.bus.BusEvent;
public interface PaymentInfoEvent extends Entity, BusEvent {
-
- public String getPaymentId();
-
public BigDecimal getAmount();
public String getBankIdentificationNumber();
@@ -49,5 +46,4 @@ public interface PaymentInfoEvent extends Entity, BusEvent {
public String getStatus();
public String getType();
-
}
diff --git a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
index f1aa318..18d987c 100644
--- a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
+++ b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
@@ -21,6 +21,7 @@ public enum ObjectType {
ACCOUNT_EMAIL("account email"),
BUNDLE("subscription bundle"),
INVOICE("invoice"),
+ RECURRING_INVOICE_ITEM("recurring_invoice_item"),
SUBSCRIPTION("subscription");
private final String objectName;
diff --git a/api/src/main/java/com/ning/billing/util/queue/QueueLifecycle.java b/api/src/main/java/com/ning/billing/util/queue/QueueLifecycle.java
new file mode 100644
index 0000000..8db4ec7
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/queue/QueueLifecycle.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util.queue;
+
+public interface QueueLifecycle {
+ /**
+ * Starts the queue
+ */
+ public void startQueue();
+
+ /**
+ * Stop the queue
+ *
+ */
+ public void stopQueue();
+
+ /**
+ * Processes event from queue
+ */
+ public int doProcessEvents();
+}
beatrix/pom.xml 29(+29 -0)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index bed20c1..0e5dc26 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -65,6 +65,13 @@
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
+
+ <!-- TEST SCOPE -->
+ <dependency>
+ <groupId>com.jayway.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-junction</artifactId>
@@ -78,6 +85,28 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-invoice</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-account</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-account</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-overdue</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi</artifactId>
<scope>test</scope>
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
index 8eafa8d..ea75433 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
@@ -22,8 +22,7 @@ import java.io.IOException;
import java.net.URL;
import java.util.Set;
-import com.ning.billing.util.email.EmailConfig;
-import com.ning.billing.util.email.EmailModule;
+import com.ning.billing.account.api.AccountService;
import org.skife.config.ConfigurationObjectFactory;
import org.skife.jdbi.v2.IDBI;
@@ -41,10 +40,10 @@ import com.ning.billing.dbi.DBIProvider;
import com.ning.billing.dbi.DbiConfig;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.api.EntitlementService;
-import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
import com.ning.billing.invoice.api.InvoiceService;
-import com.ning.billing.invoice.glue.InvoiceModule;
-import com.ning.billing.junction.glue.JunctionModule;
+import com.ning.billing.invoice.glue.DefaultInvoiceModule;
+import com.ning.billing.junction.glue.DefaultJunctionModule;
import com.ning.billing.lifecycle.KillbillService;
import com.ning.billing.payment.api.PaymentService;
import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
@@ -52,6 +51,8 @@ import com.ning.billing.payment.setup.PaymentModule;
import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.email.EmailModule;
+import com.ning.billing.util.email.templates.TemplateModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.CallContextModule;
import com.ning.billing.util.glue.FieldStoreModule;
@@ -61,8 +62,6 @@ import com.ning.billing.util.glue.TagStoreModule;
public class MockModule extends AbstractModule {
-
-
public static final String PLUGIN_NAME = "yoyo";
@Override
@@ -94,10 +93,11 @@ public class MockModule extends AbstractModule {
install(new FieldStoreModule());
install(new AccountModule());
install(new CatalogModule());
- install(new EntitlementModule());
- install(new InvoiceModule());
+ install(new DefaultEntitlementModule());
+ install(new DefaultInvoiceModule());
+ install(new TemplateModule());
install(new PaymentMockModule());
- install(new JunctionModule());
+ install(new DefaultJunctionModule());
}
private static final class PaymentMockModule extends PaymentModule {
@@ -127,6 +127,7 @@ public class MockModule extends AbstractModule {
@Override
protected Set<? extends KillbillService> findServices() {
ImmutableSet<? extends KillbillService> services = new ImmutableSet.Builder<KillbillService>()
+ .add(injector.getInstance(AccountService.class))
.add(injector.getInstance(BusService.class))
.add(injector.getInstance(CatalogService.class))
.add(injector.getInstance(EntitlementService.class))
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
new file mode 100644
index 0000000..2dfe2ee
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -0,0 +1,140 @@
+/*
+ * 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.beatrix.integration.overdue;
+//
+//import static org.testng.Assert.assertNotNull;
+//
+//import java.io.ByteArrayInputStream;
+//import java.io.InputStream;
+//
+//import org.joda.time.DateTime;
+//import org.joda.time.Interval;
+//
+//import com.google.inject.Inject;
+//import com.ning.billing.account.api.Account;
+//import com.ning.billing.beatrix.integration.TestIntegrationBase;
+//import com.ning.billing.catalog.api.BillingPeriod;
+//import com.ning.billing.catalog.api.Duration;
+//import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+//import com.ning.billing.catalog.api.PriceListSet;
+//import com.ning.billing.catalog.api.ProductCategory;
+//import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+//import com.ning.billing.entitlement.api.user.SubscriptionData;
+//import com.ning.billing.junction.api.BlockingApi;
+//import com.ning.billing.overdue.config.OverdueConfig;
+//import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
+//import com.ning.billing.util.clock.ClockMock;
+//import com.ning.billing.util.config.XMLLoader;
+//
+//public class TestOverdueIntegration extends TestIntegrationBase {
+// private final String configXml =
+// "<overdueConfig>" +
+// " <bundleOverdueStates>" +
+// " <state name=\"OD1\">" +
+// " <condition>" +
+// " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+// " <unit>MONTHS</unit><number>1</number>" +
+// " </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+// " </condition>" +
+// " <externalMessage>Reached OD1</externalMessage>" +
+// " <blockChanges>true</blockChanges>" +
+// " <disableEntitlementAndChangesBlocked>false</disableEntitlementAndChangesBlocked>" +
+// " </state>" +
+// " <state name=\"OD2\">" +
+// " <condition>" +
+// " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+// " <unit>MONTHS</unit><number>2</number>" +
+// " </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+// " </condition>" +
+// " <externalMessage>Reached OD1</externalMessage>" +
+// " <blockChanges>true</blockChanges>" +
+// " <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>" +
+// " </state>" +
+// " </bundleOverdueStates>" +
+// "</overdueConfig>";
+// private OverdueConfig config;
+//
+// @Inject
+// private ClockMock clock;
+//
+// @Inject
+// private MockPaymentProviderPlugin paymentPlugin;
+//
+// @Inject
+// private BlockingApi blockingApi;
+//
+// private Account account;
+// private SubscriptionBundle bundle;
+// private String productName;
+// private BillingPeriod term;
+// private String planSetName;
+//
+// long twoWeeks = new Interval(clock.getUTCNow(), clock.getUTCNow().plusWeeks(2)).toDurationMillis();
+// long fourWeeks = new Interval(clock.getUTCNow(), clock.getUTCNow().plusWeeks(4)).toDurationMillis();
+//
+// //@BeforeMethod
+// public void setup() throws Exception {
+// InputStream is = new ByteArrayInputStream(configXml.getBytes());
+// config = XMLLoader.getObjectFromStreamNoValidation(is, OverdueConfig.class);
+// Account account = accountUserApi.createAccount(getAccountData(25), null, null, context);
+// assertNotNull(account);
+//
+// bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", context);
+//
+// productName = "Shotgun";
+// term = BillingPeriod.MONTHLY;
+// planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+//
+// // create account
+// // set mock payments to fail
+// // reset clock
+// // configure basic OD state rules for 2 states OD1 1-2month, OD2 2-3 month
+// }
+//
+// //@AfterMethod
+// public void cleanup(){
+// // Clear databases
+// }
+//
+// public void testBasicOverdueState() throws Exception {
+// DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+// clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+//
+//
+// // set next invoice to fail and create network
+// paymentPlugin.makeNextInvoiceFail();
+// SubscriptionData baseSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
+// new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null, context));
+// assertNotNull(baseSubscription);
+//
+//
+// // advance time 2weeks
+// clock.addDeltaFromReality(twoWeeks);
+//
+// // should still be in clear state
+// blockingApi.getBlockingStateFor(bundle);
+//
+// // set next invoice to fail and advance time 1 month
+// clock.addDeltaFromReality(fourWeeks);
+//
+// // should now be in OD1 state
+// // set next invoice to fail and advance time 1 month
+// // should now be in OD2 state
+//
+//
+// }
+//}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java
new file mode 100644
index 0000000..d444776
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java
@@ -0,0 +1,74 @@
+/*
+ * 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.beatrix.integration.payment;
+
+import com.ning.billing.account.dao.MockAccountDao;
+import com.ning.billing.invoice.dao.MockInvoiceDao;
+import org.apache.commons.collections.MapUtils;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Provider;
+import com.ning.billing.account.dao.AccountDao;
+import com.ning.billing.config.PaymentConfig;
+import com.ning.billing.invoice.dao.InvoiceDao;
+import com.ning.billing.junction.api.BillingApi;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.payment.dao.MockPaymentDao;
+import com.ning.billing.payment.dao.PaymentDao;
+import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
+import com.ning.billing.payment.setup.PaymentModule;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.InMemoryBus;
+import com.ning.billing.util.notificationq.MockNotificationQueueService;
+import com.ning.billing.util.notificationq.NotificationQueueService;
+
+public class PaymentTestModule extends PaymentModule {
+ public static class MockProvider implements Provider<BillingApi> {
+ @Override
+ public BillingApi get() {
+ return BrainDeadProxyFactory.createBrainDeadProxyFor(BillingApi.class);
+ }
+
+ }
+
+ public PaymentTestModule() {
+ super(MapUtils.toProperties(ImmutableMap.of("killbill.payment.provider.default", "my-mock",
+ "killbill.payment.engine.events.off", "false")));
+ }
+
+ @Override
+ protected void installPaymentDao() {
+ bind(PaymentDao.class).to(MockPaymentDao.class).asEagerSingleton();
+ }
+
+ @Override
+ protected void installPaymentProviderPlugins(PaymentConfig config) {
+ install(new MockPaymentProviderPluginModule("my-mock"));
+ }
+
+ @Override
+ protected void configure() {
+ super.configure();
+ bind(Bus.class).to(InMemoryBus.class).asEagerSingleton();
+ bind(MockAccountDao.class).asEagerSingleton();
+ bind(AccountDao.class).to(MockAccountDao.class);
+ bind(MockInvoiceDao.class).asEagerSingleton();
+ bind(InvoiceDao.class).to(MockInvoiceDao.class);
+ bind(NotificationQueueService.class).to(MockNotificationQueueService.class).asEagerSingleton();
+
+ }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java
new file mode 100644
index 0000000..631a7dc
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java
@@ -0,0 +1,128 @@
+/*
+ * 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.beatrix.integration.payment;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import org.apache.commons.lang.RandomStringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.google.inject.Inject;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.test.InvoiceTestApi;
+import com.ning.billing.invoice.model.DefaultInvoice;
+import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.entity.EntityPersistenceException;
+
+public class TestHelper {
+ protected final AccountUserApi accountUserApi;
+ protected final InvoiceTestApi invoiceTestApi;
+ private final CallContext context;
+
+ @Inject
+ public TestHelper(CallContextFactory factory, AccountUserApi accountUserApi, InvoiceTestApi invoiceTestApi) {
+ this.accountUserApi = accountUserApi;
+ this.invoiceTestApi = invoiceTestApi;
+ context = factory.createCallContext("Payment Test", CallOrigin.TEST, UserType.TEST);
+ }
+
+ // These helper methods can be overridden in a plugin implementation
+ public Account createTestCreditCardAccount() throws EntityPersistenceException {
+ String email = "ccuser" + RandomStringUtils.randomAlphanumeric(8) + "@example.com";
+ final Account account = createTestAccount(email);
+
+ ((ZombieControl)accountUserApi).addResult("getAccountById", account);
+ ((ZombieControl)accountUserApi).addResult("getAccountByKey", account);
+ return account;
+ }
+
+ public Account createTestPayPalAccount() throws EntityPersistenceException {
+ final Account account = createTestAccount("ppuser@example.com");
+ ((ZombieControl)accountUserApi).addResult("getAccountById", account);
+ ((ZombieControl)accountUserApi).addResult("getAccountByKey", account);
+ return account;
+ }
+
+ private Account createTestAccount(String email) {
+ Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+ ZombieControl zombie = (ZombieControl) account;
+ zombie.addResult("getId", UUID.randomUUID());
+ String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
+ zombie.addResult("getName", name);
+ zombie.addResult("getFirstNameLength", 10);
+ String externalKey = RandomStringUtils.randomAlphanumeric(10);
+ zombie.addResult("getExternalKey", externalKey);
+ zombie.addResult("getPhone", "123-456-7890");
+ zombie.addResult("getEmail", email);
+ zombie.addResult("getCurrency", Currency.USD);
+ zombie.addResult("getBillCycleDay", 1);
+
+ return account;
+ }
+
+ public Invoice createTestInvoice(Account account,
+ DateTime targetDate,
+ Currency currency,
+ InvoiceItem... items) {
+ Invoice invoice = new DefaultInvoice(account.getId(), new DateTime(), targetDate, currency);
+
+ for (InvoiceItem item : items) {
+ if (item instanceof RecurringInvoiceItem) {
+ RecurringInvoiceItem recurringInvoiceItem = (RecurringInvoiceItem) item;
+ invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(),
+ account.getId(),
+ recurringInvoiceItem.getBundleId(),
+ recurringInvoiceItem.getSubscriptionId(),
+ recurringInvoiceItem.getPlanName(),
+ recurringInvoiceItem.getPhaseName(),
+ recurringInvoiceItem.getStartDate(),
+ recurringInvoiceItem.getEndDate(),
+ recurringInvoiceItem.getAmount(),
+ recurringInvoiceItem.getRate(),
+ recurringInvoiceItem.getCurrency()));
+ }
+ }
+
+ invoiceTestApi.create(invoice, context);
+ return invoice;
+ }
+
+ public Invoice createTestInvoice(Account account) {
+ final DateTime now = new DateTime(DateTimeZone.UTC);
+ final UUID subscriptionId = UUID.randomUUID();
+ final UUID bundleId = UUID.randomUUID();
+ final BigDecimal amount = new BigDecimal("10.00");
+
+ final InvoiceItem item = new RecurringInvoiceItem(null, account.getId(), bundleId, subscriptionId, "test plan", "test phase", now, now.plusMonths(1),
+ amount, new BigDecimal("1.0"), Currency.USD);
+
+
+ return createTestInvoice(account, now, Currency.USD, item);
+ }
+}
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 3e8dfb4..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
@@ -32,7 +32,7 @@ import org.testng.annotations.Test;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountData;
-import com.ning.billing.beatrix.integration.TestBusHandler.NextEvent;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.PhaseType;
@@ -49,32 +49,32 @@ import com.ning.billing.invoice.api.Invoice;
public class TestIntegration extends TestIntegrationBase {
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayInPast() throws Exception {
+ log.info("Starting testBasePlanCompleteWithBillingDayInPast");
DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
testBasePlanComplete(startDate, 31, false);
}
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayPresent() throws Exception {
+ log.info("Starting testBasePlanCompleteWithBillingDayPresent");
DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
testBasePlanComplete(startDate, 1, false);
}
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayAlignedWithTrial() throws Exception {
+ log.info("Starting testBasePlanCompleteWithBillingDayAlignedWithTrial");
DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
testBasePlanComplete(startDate, 2, false);
}
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayInFuture() throws Exception {
+ log.info("Starting testBasePlanCompleteWithBillingDayInFuture");
DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
testBasePlanComplete(startDate, 3, true);
}
-// private void waitForDebug() throws Exception {
-// Thread.sleep(600000);
-// }
-
@Test(groups = {"slow", "stress"}, enabled = false)
public void stressTest() throws Exception {
final int maxIterations = 7;
@@ -95,9 +95,12 @@ public class TestIntegration extends TestIntegrationBase {
}
}
- @Test(groups = "slow", enabled = true)
+ // STEPH set to disabled until test written properly and fixed
+ @Test(groups = "slow", enabled = false)
public void testRepairChangeBPWithAddonIncluded() throws Exception {
+ log.info("Starting testRepairChangeBPWithAddonIncluded");
+
DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
@@ -146,10 +149,13 @@ public class TestIntegration extends TestIntegrationBase {
busHandler.pushExpectedEvent(NextEvent.PAYMENT);
clock.addDeltaFromReality(it.toDurationMillis());
assertTrue(busHandler.isCompleted(DELAY));
+
+ assertListenerStatus();
}
@Test(groups = {"slow"})
public void testRepairForInvoicing() throws AccountApiException, EntitlementUserApiException {
+
log.info("Starting testRepairForInvoicing");
Account account = accountUserApi.createAccount(getAccountData(1), null, null, context);
@@ -179,9 +185,11 @@ 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");
+
DateTime initialDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
int billingDay = 2;
@@ -242,13 +250,13 @@ 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);
assertTrue(busHandler.isCompleted(DELAY));
-
+ assertListenerStatus();
}
private void testBasePlanComplete(DateTime initialCreationDate, int billingDay,
@@ -444,12 +452,18 @@ public class TestIntegration extends TestIntegrationBase {
// The invoice system is still working to verify there is nothing to do
Thread.sleep(DELAY);
+
+ assertListenerStatus();
+
log.info("TEST PASSED !");
}
@Test(groups = "slow")
public void testForMultipleRecurringPhases() throws AccountApiException, EntitlementUserApiException, InterruptedException {
+
+ log.info("Starting testForMultipleRecurringPhases");
+
DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
clock.setDeltaFromReality(initialCreationDate.getMillis() - clock.getUTCNow().getMillis());
@@ -509,5 +523,7 @@ public class TestIntegration extends TestIntegrationBase {
invoices = invoiceUserApi.getInvoicesByAccount(accountId);
assertNotNull(invoices);
assertEquals(invoices.size(),14);
+
+ assertListenerStatus();
}
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index a70bce9..579f47c 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -36,6 +36,7 @@ import org.skife.jdbi.v2.TransactionCallback;
import org.skife.jdbi.v2.TransactionStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
@@ -45,7 +46,10 @@ import com.google.inject.Inject;
import com.ning.billing.account.api.AccountData;
import com.ning.billing.account.api.AccountService;
import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.api.TestApiListener;
+import com.ning.billing.api.TestListenerStatus;
import com.ning.billing.beatrix.lifecycle.Lifecycle;
+import com.ning.billing.catalog.DefaultCatalogService;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.api.EntitlementService;
@@ -54,6 +58,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.SubscriptionData;
+import com.ning.billing.entitlement.engine.core.Engine;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.InvoiceService;
@@ -67,7 +72,7 @@ import com.ning.billing.util.callcontext.DefaultCallContextFactory;
import com.ning.billing.util.callcontext.UserType;
import com.ning.billing.util.clock.ClockMock;
-public class TestIntegrationBase implements TestFailure {
+public class TestIntegrationBase implements TestListenerStatus {
protected static final int NUMBER_OF_DECIMALS = InvoicingConfiguration.getNumberOfDecimals();
protected static final int ROUNDING_METHOD = InvoicingConfiguration.getRoundingMode();
@@ -80,7 +85,7 @@ public class TestIntegrationBase implements TestFailure {
protected static final Logger log = LoggerFactory.getLogger(TestIntegration.class);
protected static long AT_LEAST_ONE_MONTH_MS = 31L * 24L * 3600L * 1000L;
- protected static final long DELAY = 5000;
+ protected static final long DELAY = 10000;
@Inject
protected IDBI dbi;
@@ -119,28 +124,29 @@ public class TestIntegrationBase implements TestFailure {
@Inject
protected AccountUserApi accountUserApi;
- protected TestBusHandler busHandler;
+ protected TestApiListener busHandler;
- private boolean currentTestStatusSuccess;
- private String currentTestFailedMsg;
+ private boolean isListenerFailed;
+ private String listenerFailedMsg;
@Override
public void failed(String msg) {
- currentTestStatusSuccess = false;
- currentTestFailedMsg = msg;
+ isListenerFailed = true;
+ listenerFailedMsg = msg;
}
@Override
- public void reset() {
- currentTestStatusSuccess = true;
- currentTestFailedMsg = null;
+ public void resetTestListenerStatus() {
+ isListenerFailed = false;
+ listenerFailedMsg = null;
}
- protected void assertFailureFromBusHandler() {
- if (!currentTestStatusSuccess) {
- log.error(currentTestFailedMsg);
- fail();
+
+ protected void assertListenerStatus() {
+ if (isListenerFailed) {
+ log.error(listenerFailedMsg);
+ Assert.fail(listenerFailedMsg);
}
}
@@ -163,73 +169,50 @@ public class TestIntegrationBase implements TestFailure {
helper.initDb(junctionDb);
}
+
@BeforeClass(groups = "slow")
public void setup() throws Exception{
setupMySQL();
- cleanupData();
-
context = new DefaultCallContextFactory(clock).createCallContext("Integration Test", CallOrigin.TEST, UserType.TEST);
-
- /**
- * Initialize lifecyle for subset of services
- */
- busHandler = new TestBusHandler(this);
- lifecycle.fireStartupSequencePriorEventRegistration();
- busService.getBus().register(busHandler);
- lifecycle.fireStartupSequencePostEventRegistration();
+ busHandler = new TestApiListener(this);
+
}
@AfterClass(groups = "slow")
public void tearDown() throws Exception {
- lifecycle.fireShutdownSequencePriorEventUnRegistration();
- busService.getBus().unregister(busHandler);
- lifecycle.fireShutdownSequencePostEventUnRegistration();
helper.stopMysql();
}
@BeforeMethod(groups = "slow")
- public void setupTest() {
+ public void setupTest() throws Exception {
log.warn("\n");
log.warn("RESET TEST FRAMEWORK\n\n");
- cleanupData();
- busHandler.reset();
+
+ // Pre test cleanup
+ helper.cleanupAllTables();
+
clock.resetDeltaFromReality();
- reset();
+ resetTestListenerStatus();
+
+ // Start services
+ lifecycle.fireStartupSequencePriorEventRegistration();
+ busService.getBus().register(busHandler);
+ lifecycle.fireStartupSequencePostEventRegistration();
}
@AfterMethod(groups = "slow")
- public void cleanupTest() {
+ public void cleanupTest() throws Exception {
+ lifecycle.fireShutdownSequencePriorEventUnRegistration();
+ busService.getBus().unregister(busHandler);
+ lifecycle.fireShutdownSequencePostEventUnRegistration();
+
log.warn("DONE WITH TEST\n");
}
- protected void cleanupData() {
- dbi.inTransaction(new TransactionCallback<Void>() {
- @Override
- public Void inTransaction(Handle h, TransactionStatus status)
- throws Exception {
- h.execute("truncate table accounts");
- h.execute("truncate table entitlement_events");
- h.execute("truncate table subscriptions");
- h.execute("truncate table bundles");
- h.execute("truncate table notifications");
- h.execute("truncate table claimed_notifications");
- h.execute("truncate table invoices");
- h.execute("truncate table fixed_invoice_items");
- h.execute("truncate table recurring_invoice_items");
- h.execute("truncate table tag_definitions");
- h.execute("truncate table tags");
- h.execute("truncate table custom_fields");
- h.execute("truncate table invoice_payments");
- h.execute("truncate table payment_attempts");
- h.execute("truncate table payments");
- return null;
- }
- });
- }
protected void verifyTestResult(UUID accountId, UUID subscriptionId,
DateTime startDate, DateTime endDate,
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 6490640..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
@@ -32,7 +32,7 @@ import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import com.ning.billing.account.api.Account;
-import com.ning.billing.beatrix.integration.TestBusHandler.NextEvent;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
@@ -54,13 +54,15 @@ 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);
}
@@ -168,7 +170,7 @@ public class TestRepairIntegration extends TestIntegrationBase {
assertEquals(newBaseSubscription.getAllTransitions().size(), 3);
assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
- assertFailureFromBusHandler();
+ assertListenerStatus();
}
}
@@ -327,6 +329,4 @@ public class TestRepairIntegration extends TestIntegrationBase {
}
});
}
-
-
}
bin/clean-and-install 22(+22 -0)
diff --git a/bin/clean-and-install b/bin/clean-and-install
new file mode 100755
index 0000000..c6c3ac4
--- /dev/null
+++ b/bin/clean-and-install
@@ -0,0 +1,22 @@
+#! /usr/bin/env bash
+
+###################################################################################
+# #
+# 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. #
+# #
+###################################################################################
+
+bin/db-helper -a clean -d killbill;
+mvn -Dcom.ning.billing.dbi.test.useLocalDb=true clean install
entitlement/pom.xml 54(+24 -30)
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 426d9f8..172287f 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -39,23 +39,6 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
- <artifactId>killbill-catalog</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-catalog</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-util</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
<artifactId>killbill-util</artifactId>
</dependency>
<dependency>
@@ -63,14 +46,7 @@
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
- <!-- Same here, this is really debatable whether or not we should keep that here -->
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-account</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
+ <dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
@@ -87,11 +63,6 @@
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
- <groupId>org.testng</groupId>
- <artifactId>testng</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
@@ -108,11 +79,34 @@
<artifactId>stringtemplate</artifactId>
<scope>runtime</scope>
</dependency>
+ <!-- TEST SCOPE -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-mxj</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-catalog</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-catalog</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-util</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-mxj-db-files</artifactId>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
index ae3cde0..0e44528 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
@@ -21,7 +21,6 @@ import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.*;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
import com.ning.billing.entitlement.exceptions.EntitlementError;
import com.ning.billing.util.clock.DefaultClock;
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 f47ac5e..21b97f8 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
@@ -18,29 +18,19 @@ package com.ning.billing.entitlement.api.billing;
import java.util.UUID;
-import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.util.dao.EntityAudit;
-import com.ning.billing.util.dao.TableName;
import org.joda.time.DateTime;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
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.callcontext.CallContext;
public class DefaultChargeThruApi implements ChargeThruApi {
- private static final Logger log = LoggerFactory.getLogger(DefaultChargeThruApi.class);
-
private final EntitlementDao entitlementDao;
private final SubscriptionFactory subscriptionFactory;
-
+
@Inject
public DefaultChargeThruApi(final SubscriptionFactory subscriptionFactory, final EntitlementDao dao) {
super();
@@ -62,25 +52,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);
-
- Long recordId = subscriptionSqlDao.getRecordId(TableName.SUBSCRIPTIONS, subscriptionId.toString());
- EntityAudit audit = new EntityAudit(recordId, ChangeType.UPDATE);
- subscriptionSqlDao.insertAuditFromTransaction(TableName.SUBSCRIPTIONS, audit, 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/timeline/DefaultEntitlementTimelineApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
index 9cee03c..cf9db7c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
@@ -18,11 +18,9 @@ package com.ning.billing.entitlement.api.timeline;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
@@ -34,28 +32,19 @@ import com.google.inject.name.Named;
import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.catalog.api.CatalogUserApi;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionFactory;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.events.EntitlementEvent;
-import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
-import com.ning.billing.entitlement.exceptions.EntitlementError;
-import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
import com.ning.billing.util.callcontext.CallContext;
public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
@@ -74,8 +63,8 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
@Inject
- public DefaultEntitlementTimelineApi(@Named(EntitlementModule.REPAIR_NAMED) final SubscriptionFactory factory, final CatalogService catalogService,
- @Named(EntitlementModule.REPAIR_NAMED) final RepairEntitlementLifecycleDao repairDao, final EntitlementDao dao) {
+ public DefaultEntitlementTimelineApi(@Named(DefaultEntitlementModule.REPAIR_NAMED) final SubscriptionFactory factory, final CatalogService catalogService,
+ @Named(DefaultEntitlementModule.REPAIR_NAMED) final RepairEntitlementLifecycleDao repairDao, final EntitlementDao dao) {
this.catalogService = catalogService;
this.dao = dao;
this.repairDao = repairDao;
@@ -350,7 +339,7 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
if (firstBPDeletedTime != null &&
! cur.getEffectiveDate().isBefore(firstBPDeletedTime) &&
! foundDeletedEvent) {
- throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_MISSING_AO_DELETE_EVENT, cur.getId(), data.getId());
+ throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_MISSING_AO_DELETE_EVENT, cur.getId(), data.getId());
}
if (nbDeleted == 0) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java
index 315550d..4080326 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java
@@ -32,7 +32,6 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
import com.ning.billing.entitlement.events.EntitlementEvent;
import com.ning.billing.entitlement.events.phase.PhaseEvent;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionApiService.java
index 659b3be..dcc0c95 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionApiService.java
@@ -23,13 +23,13 @@ import com.ning.billing.entitlement.alignment.PlanAligner;
import com.ning.billing.entitlement.api.SubscriptionApiService;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionApiService;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
-import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
import com.ning.billing.util.clock.Clock;
public class RepairSubscriptionApiService extends DefaultSubscriptionApiService implements SubscriptionApiService {
@Inject
- public RepairSubscriptionApiService(Clock clock, @Named(EntitlementModule.REPAIR_NAMED) EntitlementDao dao,
+ public RepairSubscriptionApiService(Clock clock, @Named(DefaultEntitlementModule.REPAIR_NAMED) EntitlementDao dao,
CatalogService catalogService, PlanAligner planAligner) {
super(clock, dao, catalogService, planAligner);
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java
index e63c3a4..61933c3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/RepairSubscriptionFactory.java
@@ -29,7 +29,7 @@ import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.Subscrip
import com.ning.billing.entitlement.engine.addon.AddonUtils;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.events.EntitlementEvent;
-import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
import com.ning.billing.util.clock.Clock;
public class RepairSubscriptionFactory extends DefaultSubscriptionFactory implements SubscriptionFactory {
@@ -38,8 +38,8 @@ public class RepairSubscriptionFactory extends DefaultSubscriptionFactory implem
private final EntitlementDao repairDao;
@Inject
- public RepairSubscriptionFactory(@Named(EntitlementModule.REPAIR_NAMED) SubscriptionApiService apiService,
- @Named(EntitlementModule.REPAIR_NAMED) EntitlementDao dao,
+ public RepairSubscriptionFactory(@Named(DefaultEntitlementModule.REPAIR_NAMED) SubscriptionApiService apiService,
+ @Named(DefaultEntitlementModule.REPAIR_NAMED) EntitlementDao dao,
Clock clock, CatalogService catalogService, AddonUtils addonUtils) {
super(apiService, clock, catalogService);
this.addonUtils = addonUtils;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
index 75574d3..7f526d4 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
@@ -17,11 +17,9 @@ package com.ning.billing.entitlement.api.timeline;
import java.util.Collection;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import org.joda.time.DateTime;
-import org.omg.CORBA.Request;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
@@ -35,10 +33,8 @@ import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionApiService;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
import com.ning.billing.entitlement.engine.addon.AddonUtils;
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..7d92852 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;
@@ -30,10 +31,11 @@ import com.ning.billing.catalog.api.Plan;
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 +63,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 +107,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 +216,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..44ed086 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
@@ -229,7 +229,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/DefaultSubscriptionEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java
index ea310f9..3cf74ec 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionEvent.java
@@ -348,5 +348,24 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
return false;
return true;
}
+
+ @Override
+ public String toString() {
+ return "DefaultSubscriptionEvent [transitionType=" + transitionType
+ + ", effectiveTransitionTime=" + effectiveTransitionTime
+ + ", totalOrdering=" + totalOrdering
+ + ", subscriptionId=" + subscriptionId + ", bundleId="
+ + bundleId + ", eventId=" + eventId
+ + ", requestedTransitionTime=" + requestedTransitionTime
+ + ", previousState=" + previousState + ", previousPriceList="
+ + previousPriceList + ", previousPlan=" + previousPlan
+ + ", previousPhase=" + previousPhase + ", nextState="
+ + nextState + ", nextPriceList=" + nextPriceList
+ + ", nextPlan=" + nextPlan + ", nextPhase=" + nextPhase
+ + ", remainingEventsForUserOperation="
+ + remainingEventsForUserOperation + ", userToken=" + userToken
+ + ", startDate=" + startDate + "]";
+
+ }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
index eb59d38..37a94f6 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
@@ -21,7 +21,6 @@ import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionApiService;
import com.ning.billing.entitlement.api.SubscriptionFactory;
-import com.ning.billing.entitlement.api.timeline.SubscriptionDataRepair;
import com.ning.billing.entitlement.events.EntitlementEvent;
import com.ning.billing.entitlement.exceptions.EntitlementError;
import com.ning.billing.util.clock.Clock;
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 1a3e792..815410a 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/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index c8f82a2..accb829 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -30,8 +30,6 @@ import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
-import com.google.inject.name.Named;
-
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.Product;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
index f973ab0..c503d91 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
@@ -129,12 +129,12 @@ public class AuditedEntitlementDao implements EntitlementDao {
public SubscriptionBundle createSubscriptionBundle(final SubscriptionBundleData bundle, final CallContext context) {
return bundlesDao.inTransaction(new Transaction<SubscriptionBundle, BundleSqlDao>() {
@Override
- public SubscriptionBundle inTransaction(BundleSqlDao bundlesDao, TransactionStatus status) {
+ public SubscriptionBundle inTransaction(BundleSqlDao transactional, TransactionStatus status) {
bundlesDao.insertBundle(bundle, context);
- Long recordId = bundlesDao.getRecordId(TableName.ENTITLEMENT_EVENTS, bundle.getId().toString());
+ Long recordId = bundlesDao.getRecordId(bundle.getId().toString());
- EntityAudit audit = new EntityAudit(recordId, ChangeType.INSERT);
- bundlesDao.insertAuditFromTransaction(TableName.BUNDLES, audit, context);
+ EntityAudit audit = new EntityAudit(TableName.BUNDLES, recordId, ChangeType.INSERT);
+ bundlesDao.insertAuditFromTransaction(audit, context);
return bundle;
}
@@ -198,18 +198,18 @@ public class AuditedEntitlementDao implements EntitlementDao {
public Void inTransaction(SubscriptionSqlDao transactionalDao,
TransactionStatus status) throws Exception {
String subscriptionId = subscription.getId().toString();
- transactionalDao.updateChargedThroughDate(subscriptionId, ctd, context);
- Long subscriptionRecordId = transactionalDao.getRecordId(TableName.SUBSCRIPTIONS, subscriptionId);
- EntityAudit subscriptionAudit = new EntityAudit(subscriptionRecordId, ChangeType.UPDATE);
- transactionalDao.insertAuditFromTransaction(TableName.SUBSCRIPTIONS, subscriptionAudit, context);
+ transactionalDao.updateChargedThroughDate(subscription.getId().toString(), ctd, context);
+ Long subscriptionRecordId = transactionalDao.getRecordId(subscriptionId);
+ EntityAudit subscriptionAudit = new EntityAudit(TableName.SUBSCRIPTIONS, subscriptionRecordId, ChangeType.UPDATE);
+ transactionalDao.insertAuditFromTransaction(subscriptionAudit, context);
BundleSqlDao bundleSqlDao = transactionalDao.become(BundleSqlDao.class);
String bundleId = subscription.getBundleId().toString();
bundleSqlDao.updateBundleLastSysTime(bundleId, clock.getUTCNow().toDate());
// SubscriptionBundle bundle = bundleSqlDao.getById(bundleId);
- Long recordId = bundleSqlDao.getRecordId(TableName.ENTITLEMENT_EVENTS, bundleId);
- EntityAudit bundleAudit = new EntityAudit(recordId, ChangeType.UPDATE);
- bundleSqlDao.insertAuditFromTransaction(TableName.SUBSCRIPTIONS, bundleAudit, context);
+ Long recordId = bundleSqlDao.getRecordId(bundleId);
+ EntityAudit bundleAudit = new EntityAudit(TableName.BUNDLES, recordId, ChangeType.UPDATE);
+ bundleSqlDao.insertAuditFromTransaction(bundleAudit, context);
return null;
}
});
@@ -219,15 +219,15 @@ public class AuditedEntitlementDao implements EntitlementDao {
public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
- public Void inTransaction(EntitlementEventSqlDao dao, TransactionStatus status) throws Exception {
- cancelNextPhaseEventFromTransaction(subscriptionId, dao, context);
- dao.insertEvent(nextPhase, context);
+ public Void inTransaction(EntitlementEventSqlDao transactional, TransactionStatus status) throws Exception {
+ cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
+ transactional.insertEvent(nextPhase, context);
- Long recordId = dao.getRecordId(TableName.ENTITLEMENT_EVENTS, nextPhase.getId().toString());
- EntityAudit audit = new EntityAudit(recordId, ChangeType.INSERT);
- dao.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, audit, context);
+ Long recordId = transactional.getRecordId(nextPhase.getId().toString());
+ EntityAudit audit = new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.INSERT);
+ transactional.insertAuditFromTransaction(audit, context);
- recordFutureNotificationFromTransaction(dao,
+ recordFutureNotificationFromTransaction(transactional,
nextPhase.getEffectiveDate(),
new EntitlementNotificationKey(nextPhase.getId()));
return null;
@@ -279,28 +279,28 @@ public class AuditedEntitlementDao implements EntitlementDao {
subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
@Override
- public Void inTransaction(SubscriptionSqlDao dao,
+ public Void inTransaction(SubscriptionSqlDao transactional,
TransactionStatus status) throws Exception {
- dao.insertSubscription(subscription, context);
- Long subscriptionRecordId = dao.getRecordId(TableName.SUBSCRIPTIONS, subscription.getId().toString());
- EntityAudit audit = new EntityAudit(subscriptionRecordId, ChangeType.INSERT);
- dao.insertAuditFromTransaction(TableName.SUBSCRIPTIONS, audit, context);
+ transactional.insertSubscription(subscription, context);
+ Long subscriptionRecordId = transactional.getRecordId(subscription.getId().toString());
+ EntityAudit audit = new EntityAudit(TableName.SUBSCRIPTIONS, subscriptionRecordId, ChangeType.INSERT);
+ transactional.insertAuditFromTransaction(audit, context);
// STEPH batch as well
- EntitlementEventSqlDao eventsDaoFromSameTransaction = dao.become(EntitlementEventSqlDao.class);
+ EntitlementEventSqlDao eventsDaoFromSameTransaction = transactional.become(EntitlementEventSqlDao.class);
List<EntityAudit> audits = new ArrayList<EntityAudit>();
for (final EntitlementEvent cur : initialEvents) {
eventsDaoFromSameTransaction.insertEvent(cur, context);
- Long recordId = eventsDaoFromSameTransaction.getRecordId(TableName.ENTITLEMENT_EVENTS, cur.getId().toString());
- audits.add(new EntityAudit(recordId, ChangeType.INSERT));
- recordFutureNotificationFromTransaction(dao,
+ Long recordId = eventsDaoFromSameTransaction.getRecordId(cur.getId().toString());
+ audits.add(new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.INSERT));
+ recordFutureNotificationFromTransaction(transactional,
cur.getEffectiveDate(),
new EntitlementNotificationKey(cur.getId()));
}
- eventsDaoFromSameTransaction.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, audits, context);
+ eventsDaoFromSameTransaction.insertAuditFromTransaction(audits, context);
return null;
}
});
@@ -312,21 +312,21 @@ public class AuditedEntitlementDao implements EntitlementDao {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
- public Void inTransaction(EntitlementEventSqlDao dao,
+ public Void inTransaction(EntitlementEventSqlDao transactional,
TransactionStatus status) throws Exception {
List<EntityAudit> audits = new ArrayList<EntityAudit>();
for (final EntitlementEvent cur : recreateEvents) {
- dao.insertEvent(cur, context);
- Long recordId = dao.getRecordId(TableName.ENTITLEMENT_EVENTS, cur.getId().toString());
- audits.add(new EntityAudit(recordId, ChangeType.INSERT));
- recordFutureNotificationFromTransaction(dao,
+ transactional.insertEvent(cur, context);
+ Long recordId = transactional.getRecordId(cur.getId().toString());
+ audits.add(new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.INSERT));
+ recordFutureNotificationFromTransaction(transactional,
cur.getEffectiveDate(),
new EntitlementNotificationKey(cur.getId()));
}
- dao.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, audits, context);
+ transactional.insertAuditFromTransaction(audits, context);
return null;
}
});
@@ -337,19 +337,19 @@ public class AuditedEntitlementDao implements EntitlementDao {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
- public Void inTransaction(EntitlementEventSqlDao dao,
+ public Void inTransaction(EntitlementEventSqlDao transactional,
TransactionStatus status) throws Exception {
- cancelNextCancelEventFromTransaction(subscriptionId, dao, context);
- cancelNextChangeEventFromTransaction(subscriptionId, dao, context);
- cancelNextPhaseEventFromTransaction(subscriptionId, dao, context);
- dao.insertEvent(cancelEvent, context);
+ cancelNextCancelEventFromTransaction(subscriptionId, transactional, context);
+ cancelNextChangeEventFromTransaction(subscriptionId, transactional, context);
+ cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
+ transactional.insertEvent(cancelEvent, context);
String cancelEventId = cancelEvent.getId().toString();
- Long recordId = dao.getRecordId(TableName.ENTITLEMENT_EVENTS, cancelEventId);
- EntityAudit audit = new EntityAudit(recordId, ChangeType.INSERT);
- dao.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, audit, context);
+ Long recordId = transactional.getRecordId(cancelEventId);
+ EntityAudit audit = new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.INSERT);
+ transactional.insertAuditFromTransaction(audit, context);
- recordFutureNotificationFromTransaction(dao,
+ recordFutureNotificationFromTransaction(transactional,
cancelEvent.getEffectiveDate(),
new EntitlementNotificationKey(cancelEvent.getId(), seqId));
return null;
@@ -363,12 +363,12 @@ public class AuditedEntitlementDao implements EntitlementDao {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
- public Void inTransaction(EntitlementEventSqlDao dao,
+ public Void inTransaction(EntitlementEventSqlDao transactional,
TransactionStatus status) throws Exception {
EntitlementEvent cancelledEvent = null;
Date now = clock.getUTCNow().toDate();
- List<EntitlementEvent> events = dao.getFutureActiveEventForSubscription(subscriptionId.toString(), now);
+ List<EntitlementEvent> events = transactional.getFutureActiveEventForSubscription(subscriptionId.toString(), now);
for (EntitlementEvent cur : events) {
if (cur.getType() == EventType.API_USER && ((ApiEvent) cur).getEventType() == ApiEventType.CANCEL) {
@@ -383,20 +383,20 @@ public class AuditedEntitlementDao implements EntitlementDao {
List<EntityAudit> eventAudits = new ArrayList<EntityAudit>();
String cancelledEventId = cancelledEvent.getId().toString();
- dao.unactiveEvent(cancelledEventId, context);
- Long cancelledRecordId = dao.getRecordId(TableName.ENTITLEMENT_EVENTS, cancelledEventId);
- eventAudits.add(new EntityAudit(cancelledRecordId, ChangeType.UPDATE));
+ transactional.unactiveEvent(cancelledEventId, context);
+ Long cancelledRecordId = transactional.getRecordId(cancelledEventId);
+ eventAudits.add(new EntityAudit(TableName.ENTITLEMENT_EVENTS, cancelledRecordId, ChangeType.UPDATE));
for (final EntitlementEvent cur : uncancelEvents) {
- dao.insertEvent(cur, context);
- Long recordId = dao.getRecordId(TableName.ENTITLEMENT_EVENTS, cur.getId().toString());
- eventAudits.add(new EntityAudit(recordId, ChangeType.INSERT));
- recordFutureNotificationFromTransaction(dao,
+ transactional.insertEvent(cur, context);
+ Long recordId = transactional.getRecordId(cur.getId().toString());
+ eventAudits.add(new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.INSERT));
+ recordFutureNotificationFromTransaction(transactional,
cur.getEffectiveDate(),
new EntitlementNotificationKey(cur.getId()));
}
- dao.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, eventAudits, context);
+ transactional.insertAuditFromTransaction(eventAudits, context);
}
return null;
}
@@ -407,22 +407,22 @@ public class AuditedEntitlementDao implements EntitlementDao {
public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
- public Void inTransaction(EntitlementEventSqlDao dao, TransactionStatus status) throws Exception {
- cancelNextChangeEventFromTransaction(subscriptionId, dao, context);
- cancelNextPhaseEventFromTransaction(subscriptionId, dao, context);
+ public Void inTransaction(EntitlementEventSqlDao transactional, TransactionStatus status) throws Exception {
+ cancelNextChangeEventFromTransaction(subscriptionId, transactional, context);
+ cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
List<EntityAudit> eventAudits = new ArrayList<EntityAudit>();
for (final EntitlementEvent cur : changeEvents) {
- dao.insertEvent(cur, context);
- Long recordId = dao.getRecordId(TableName.ENTITLEMENT_EVENTS, cur.getId().toString());
- eventAudits.add(new EntityAudit(recordId, ChangeType.INSERT));
+ transactional.insertEvent(cur, context);
+ Long recordId = transactional.getRecordId(cur.getId().toString());
+ eventAudits.add(new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.INSERT));
- recordFutureNotificationFromTransaction(dao,
+ recordFutureNotificationFromTransaction(transactional,
cur.getEffectiveDate(),
new EntitlementNotificationKey(cur.getId()));
}
- dao.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, eventAudits, context);
+ transactional.insertAuditFromTransaction(eventAudits, context);
return null;
}
});
@@ -462,9 +462,9 @@ public class AuditedEntitlementDao implements EntitlementDao {
if (futureEvent != null) {
String eventId = futureEvent.getId().toString();
dao.unactiveEvent(eventId, context);
- Long recordId = dao.getRecordId(TableName.ENTITLEMENT_EVENTS, eventId);
- EntityAudit audit = new EntityAudit(recordId, ChangeType.UPDATE);
- dao.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, audit, context);
+ Long recordId = dao.getRecordId(eventId);
+ EntityAudit audit = new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.UPDATE);
+ dao.insertAuditFromTransaction(audit, context);
}
}
@@ -536,8 +536,8 @@ public class AuditedEntitlementDao 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();
@@ -571,15 +571,13 @@ public class AuditedEntitlementDao implements EntitlementDao {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
- public Void inTransaction(EntitlementEventSqlDao transEventDao,
+ public Void inTransaction(EntitlementEventSqlDao transactional,
TransactionStatus status) throws Exception {
- SubscriptionSqlDao transSubDao = transEventDao.become(SubscriptionSqlDao.class);
- BundleSqlDao transBundleDao = transEventDao.become(BundleSqlDao.class);
+ SubscriptionSqlDao transSubDao = transactional.become(SubscriptionSqlDao.class);
+ BundleSqlDao transBundleDao = transactional.become(BundleSqlDao.class);
- List<EntityAudit> bundleAudits = new ArrayList<EntityAudit>();
- List<EntityAudit> subscriptionAudits = new ArrayList<EntityAudit>();
- List<EntityAudit> eventAudits = new ArrayList<EntityAudit>();
+ List<EntityAudit> audits = new ArrayList<EntityAudit>();
Long recordId;
@@ -590,27 +588,25 @@ public class AuditedEntitlementDao implements EntitlementDao {
SubscriptionData subData = curSubscription.getData();
for (final EntitlementEvent curEvent : curSubscription.getInitialEvents()) {
- transEventDao.insertEvent(curEvent, context);
- recordId = transEventDao.getRecordId(TableName.ENTITLEMENT_EVENTS, curEvent.getId().toString());
- eventAudits.add(new EntityAudit(recordId, ChangeType.INSERT));
+ transactional.insertEvent(curEvent, context);
+ recordId = transactional.getRecordId(curEvent.getId().toString());
+ audits.add(new EntityAudit(TableName.ENTITLEMENT_EVENTS, recordId, ChangeType.INSERT));
- recordFutureNotificationFromTransaction(transEventDao,
+ recordFutureNotificationFromTransaction(transactional,
curEvent.getEffectiveDate(),
new EntitlementNotificationKey(curEvent.getId()));
}
transSubDao.insertSubscription(subData, context);
- recordId = transSubDao.getRecordId(TableName.SUBSCRIPTIONS, subData.getId().toString());
- subscriptionAudits.add(new EntityAudit(recordId, ChangeType.INSERT));
+ recordId = transSubDao.getRecordId(subData.getId().toString());
+ audits.add(new EntityAudit(TableName.SUBSCRIPTIONS, recordId, ChangeType.INSERT));
}
transBundleDao.insertBundle(bundleData, context);
- recordId = transBundleDao.getRecordId(TableName.BUNDLES, bundleData.getId().toString());
- bundleAudits.add(new EntityAudit(recordId, ChangeType.INSERT));
+ recordId = transBundleDao.getRecordId(bundleData.getId().toString());
+ audits.add(new EntityAudit(TableName.BUNDLES, recordId, ChangeType.INSERT));
}
// add audit records for bundles, subscriptions, and events
- transSubDao.insertAuditFromTransaction(TableName.SUBSCRIPTIONS, subscriptionAudits, context);
- transBundleDao.insertAuditFromTransaction(TableName.BUNDLES, bundleAudits, context);
- transEventDao.insertAuditFromTransaction(TableName.ENTITLEMENT_EVENTS, eventAudits, context);
+ transSubDao.insertAuditFromTransaction(audits, context);
return null;
}
@@ -643,7 +639,7 @@ public class AuditedEntitlementDao implements EntitlementDao {
RepairEntitlementEvent busEvent = new DefaultRepairEntitlementEvent(context.getUserToken(), accountId, bundleId, clock.getUTCNow());
eventBus.postFromTransaction(busEvent, transactional);
} catch (EventBusException e) {
- log.warn("Failed to post repair entitlement event for bundle " + bundleId);
+ log.warn("Failed to post repair entitlement event for bundle " + bundleId, e);
}
return null;
}
@@ -675,9 +671,9 @@ public class AuditedEntitlementDao implements EntitlementDao {
public void saveCustomFields(final SubscriptionData subscription, final CallContext context) {
subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
@Override
- public Void inTransaction(SubscriptionSqlDao transactionalDao,
+ public Void inTransaction(SubscriptionSqlDao transactional,
TransactionStatus status) throws Exception {
- updateCustomFieldsFromTransaction(transactionalDao, subscription, context);
+ updateCustomFieldsFromTransaction(transactional, subscription, context);
return null;
}
});
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
index 5861e5d..4afc75d 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
@@ -17,7 +17,6 @@
package com.ning.billing.entitlement.events;
import com.ning.billing.entitlement.events.user.ApiEvent;
-import com.ning.billing.entitlement.exceptions.EntitlementError;
import org.joda.time.DateTime;
import java.util.UUID;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java
index 47546ea..23f7b2b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java
@@ -17,7 +17,6 @@
package com.ning.billing.entitlement.events.phase;
-import com.ning.billing.entitlement.alignment.TimedPhase;
import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.entitlement.events.EventBase;
import org.joda.time.DateTime;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
index c68da2b..d2ea706 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
@@ -17,7 +17,6 @@
package com.ning.billing.entitlement.events.user;
import com.ning.billing.entitlement.events.EventBase;
-import org.joda.time.DateTime;
import java.util.UUID;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
index 7380ec9..2681a0b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
@@ -27,15 +27,15 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.Assert;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.EntitlementAccountMigration;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.EntitlementBundleMigration;
@@ -44,20 +44,22 @@ import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.Entitl
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import org.testng.annotations.Test;
public abstract class TestMigration extends TestApiBase {
public void testSingleBasePlan() {
try {
+
+ log.info("Starting testSingleBasePlan");
+
final DateTime startDate = clock.getUTCNow().minusMonths(2);
- DateTime beforeMigration = clock.getUTCNow();
+ DateTime beforeMigration = clock.getUTCNow();
EntitlementAccountMigration toBeMigrated = createAccountWithRegularBasePlan(startDate);
DateTime afterMigration = clock.getUTCNow();
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
migrationApi.migrate(toBeMigrated, context);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(toBeMigrated.getAccountKey());
assertEquals(bundles.size(), 1);
@@ -73,6 +75,8 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-annual");
assertEquals(subscription.getChargedThroughDate(), startDate.plusYears(1));
+
+ assertListenerStatus();
} catch (EntitlementMigrationApiException e) {
Assert.fail("", e);
}
@@ -80,16 +84,17 @@ public abstract class TestMigration extends TestApiBase {
public void testPlanWithAddOn() {
try {
+ log.info("Starting testPlanWithAddOn");
DateTime beforeMigration = clock.getUTCNow();
final DateTime initalBPStart = clock.getUTCNow().minusMonths(3);
final DateTime initalAddonStart = clock.getUTCNow().minusMonths(1).plusDays(7);
EntitlementAccountMigration toBeMigrated = createAccountWithRegularBasePlanAndAddons(initalBPStart, initalAddonStart);
DateTime afterMigration = clock.getUTCNow();
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
migrationApi.migrate(toBeMigrated, context);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(toBeMigrated.getAccountKey());
assertEquals(bundles.size(), 1);
@@ -120,6 +125,7 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(aoSubscription.getCurrentPlan().getName(), "telescopic-scope-monthly");
assertEquals(aoSubscription.getChargedThroughDate(), initalAddonStart.plusMonths(1));
+ assertListenerStatus();
} catch (EntitlementMigrationApiException e) {
Assert.fail("", e);
}
@@ -128,15 +134,15 @@ public abstract class TestMigration extends TestApiBase {
public void testSingleBasePlanFutureCancelled() {
try {
-
+ log.info("Starting testSingleBasePlanFutureCancelled");
final DateTime startDate = clock.getUTCNow().minusMonths(1);
DateTime beforeMigration = clock.getUTCNow();
EntitlementAccountMigration toBeMigrated = createAccountWithRegularBasePlanFutreCancelled(startDate);
DateTime afterMigration = clock.getUTCNow();
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
migrationApi.migrate(toBeMigrated, context);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(toBeMigrated.getAccountKey());
assertEquals(bundles.size(), 1);
@@ -153,11 +159,13 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-annual");
assertEquals(subscription.getChargedThroughDate(), startDate.plusYears(1));
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_BILLING);
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
- Duration oneYear = getDurationYear(1);
- clock.setDeltaFromReality(oneYear, 0);
- assertTrue(testListener.isApiCompleted(5000));
+
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_BILLING);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusYears(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
assertDateWithin(subscription.getStartDate(), beforeMigration, afterMigration);
assertNotNull(subscription.getEndDate());
@@ -167,6 +175,8 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(subscription.getState(), SubscriptionState.CANCELLED);
assertNull(subscription.getCurrentPlan());
+ assertListenerStatus();
+
} catch (EntitlementMigrationApiException e) {
Assert.fail("", e);
}
@@ -175,12 +185,14 @@ public abstract class TestMigration extends TestApiBase {
public void testSingleBasePlanWithPendingPhase() {
try {
+
+ log.info("Starting testSingleBasePlanWithPendingPhase");
final DateTime trialDate = clock.getUTCNow().minusDays(10);
EntitlementAccountMigration toBeMigrated = createAccountFuturePendingPhase(trialDate);
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
migrationApi.migrate(toBeMigrated, context);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(toBeMigrated.getAccountKey());
assertEquals(bundles.size(), 1);
@@ -198,11 +210,12 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-monthly");
assertEquals(subscription.getChargedThroughDate(), trialDate.plusDays(30));
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_BILLING);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- Duration thirtyDays = getDurationDay(30);
- clock.setDeltaFromReality(thirtyDays, 0);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_BILLING);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(30));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
assertEquals(subscription.getStartDate(), trialDate);
assertEquals(subscription.getEndDate(), null);
@@ -212,6 +225,8 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-monthly");
assertEquals(subscription.getCurrentPhase().getName(), "assault-rifle-monthly-evergreen");
+ assertListenerStatus();
+
} catch (EntitlementMigrationApiException e) {
Assert.fail("", e);
}
@@ -220,13 +235,14 @@ public abstract class TestMigration extends TestApiBase {
public void testSingleBasePlanWithPendingChange() {
try {
+ log.info("Starting testSingleBasePlanWithPendingChange");
DateTime beforeMigration = clock.getUTCNow();
EntitlementAccountMigration toBeMigrated = createAccountFuturePendingChange();
DateTime afterMigration = clock.getUTCNow();
- testListener.pushNextApiExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
+ testListener.pushExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
migrationApi.migrate(toBeMigrated, context);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(toBeMigrated.getAccountKey());
assertEquals(bundles.size(), 1);
@@ -242,10 +258,11 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-monthly");
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
- Duration oneMonth = getDurationMonth(1);
- clock.setDeltaFromReality(oneMonth, 0);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
assertDateWithin(subscription.getStartDate(), beforeMigration, afterMigration);
assertEquals(subscription.getEndDate(), null);
@@ -255,6 +272,8 @@ public abstract class TestMigration extends TestApiBase {
assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
assertEquals(subscription.getCurrentPlan().getName(), "shotgun-annual");
+ assertListenerStatus();
+
} catch (EntitlementMigrationApiException e) {
Assert.fail("", e);
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
index 6ea53bc..0195d69 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
@@ -31,26 +31,26 @@ public class TestMigrationMemory extends TestMigration {
}
@Override
- @Test(enabled=false, groups="fast")
+ @Test(enabled=true, groups="fast")
public void testSingleBasePlan() {
super.testSingleBasePlan();
}
@Override
- @Test(enabled=false, groups="fast")
+ @Test(enabled=true, groups="fast")
public void testSingleBasePlanFutureCancelled() {
super.testSingleBasePlanFutureCancelled();
}
@Override
- @Test(enabled=false, groups="fast")
+ @Test(enabled=true, groups="fast")
public void testPlanWithAddOn() {
super.testPlanWithAddOn();
}
@Override
- @Test(enabled=false, groups="fast")
+ @Test(enabled=true, groups="fast")
public void testSingleBasePlanWithPendingPhase() {
super.testSingleBasePlanWithPendingPhase();
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
index 8289ca9..7d1389e 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
@@ -34,6 +34,7 @@ import org.joda.time.DateTimeZone;
import org.joda.time.Period;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
@@ -42,6 +43,9 @@ import org.testng.annotations.BeforeMethod;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.ning.billing.account.api.AccountData;
+import com.ning.billing.api.TestApiListener;
+import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.api.TestListenerStatus;
import com.ning.billing.catalog.DefaultCatalogService;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Catalog;
@@ -54,7 +58,6 @@ import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.catalog.api.TimeUnit;
import com.ning.billing.config.EntitlementConfig;
import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.billing.ChargeThruApi;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
@@ -80,7 +83,8 @@ import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.glue.RealImplementation;
-public abstract class TestApiBase {
+public abstract class TestApiBase implements TestListenerStatus {
+
protected static final Logger log = LoggerFactory.getLogger(TestApiBase.class);
protected static final long DAY_IN_MS = (24 * 3600 * 1000);
@@ -100,12 +104,23 @@ public abstract class TestApiBase {
protected AccountData accountData;
protected Catalog catalog;
- protected ApiTestListener testListener;
+ protected TestApiListener testListener;
protected SubscriptionBundle bundle;
private MysqlTestingHelper helper;
protected CallContext context = new TestCallContext("Api Test");
+ private boolean isListenerFailed;
+ private String listenerFailedMsg;
+
+ //
+ // The date on which we make our test start; just to ensure that running tests at different dates does not
+ // produce different results. nothing specific about that date; we could change it to anything.
+ //
+ protected DateTime testStartDate = new DateTime(2012, 5, 7, 0, 3, 42, 0);
+
+
+
public static void loadSystemPropertiesFromClasspath(final String resource) {
final URL url = TestApiBase.class.getResource(resource);
assertNotNull(url);
@@ -131,6 +146,19 @@ public abstract class TestApiBase {
}
}
+
+ @Override
+ public void failed(final String msg) {
+ this.isListenerFailed = true;
+ this.listenerFailedMsg = msg;
+ }
+
+ @Override
+ public void resetTestListenerStatus() {
+ this.isListenerFailed = false;
+ this.listenerFailedMsg = null;
+ }
+
@BeforeClass(alwaysRun = true)
public void setup() throws Exception {
@@ -149,18 +177,24 @@ public abstract class TestApiBase {
dao = g.getInstance(EntitlementDao.class);
clock = (ClockMock) g.getInstance(Clock.class);
helper = (isSqlTest(dao)) ? g.getInstance(MysqlTestingHelper.class) : null;
+ init();
+ }
+
+ private void init() throws Exception {
+
+ setupDao();
((DefaultCatalogService) catalogService).loadCatalog();
- ((DefaultBusService) busService).startBus();
((Engine) entitlementService).initialize();
- init(g);
- }
- private static boolean isSqlTest(EntitlementDao theDao) {
- return (! (theDao instanceof MockEntitlementDaoMemory));
+ accountData = getAccountData();
+ assertNotNull(accountData);
+ catalog = catalogService.getFullCatalog();
+ assertNotNull(catalog);
+ testListener = new TestApiListener(this);
}
- private void setupMySQL() throws IOException {
+ private void setupDao() throws IOException {
if (helper != null) {
final String entitlementDdl = IOUtils.toString(TestApiBase.class.getResourceAsStream("/com/ning/billing/entitlement/ddl.sql"));
final String utilDdl = IOUtils.toString(TestApiBase.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
@@ -170,47 +204,70 @@ public abstract class TestApiBase {
}
}
- private void init(Injector g) throws Exception {
-
- setupMySQL();
- accountData = getAccountData();
- assertNotNull(accountData);
- catalog = catalogService.getFullCatalog();
- assertNotNull(catalog);
- testListener = new ApiTestListener(busService.getBus());
+ private static boolean isSqlTest(EntitlementDao theDao) {
+ return (! (theDao instanceof MockEntitlementDaoMemory));
}
-
+
@BeforeMethod(alwaysRun = true)
public void setupTest() throws Exception {
log.warn("RESET TEST FRAMEWORK\n\n");
+ // CLEANUP ALL DB TABLES OR IN MEMORY STRUCTURES
+ cleanupDao();
+
+ // RESET LIST OF EXPECTED EVENTS
if (testListener != null) {
testListener.reset();
+ resetTestListenerStatus();
}
-
+
+ // RESET CLOCK
clock.resetDeltaFromReality();
- ((MockEntitlementDao) dao).reset();
+ // START BUS AND REGISTER LISTENER
+ busService.getBus().start();
busService.getBus().register(testListener);
+
+ // START NOTIFICATION QUEUE FOR ENTITLEMENT
+ ((Engine)entitlementService).start();
+
+ // SETUP START DATE
+ clock.setDeltaFromReality(testStartDate.getMillis() - clock.getUTCNow().getMillis());
+
+ // CREATE NEW BUNDLE FOR TEST
UUID accountId = UUID.randomUUID();
bundle = entitlementApi.createBundleForAccount(accountId, "myDefaultBundle", context);
assertNotNull(bundle);
-
- ((Engine)entitlementService).start();
}
@AfterMethod(alwaysRun = true)
public void cleanupTest() throws Exception {
- if (busService != null) {
- busService.getBus().unregister(testListener);
- }
+
+ // UNREGISTER TEST LISTENER AND STOP BUS
+ busService.getBus().unregister(testListener);
+ busService.getBus().stop();
+
+ // STOP NOTIFICATION QUEUE
+ ((Engine)entitlementService).stop();
- if (entitlementService != null) {
- ((Engine)entitlementService).stop();
- }
log.warn("DONE WITH TEST\n");
}
+
+ protected void assertListenerStatus() {
+ if (isListenerFailed) {
+ log.error(listenerFailedMsg);
+ Assert.fail(listenerFailedMsg);
+ }
+ }
+
+ private void cleanupDao() {
+ if (helper != null) {
+ helper.cleanupAllTables();
+ } else {
+ ((MockEntitlementDao) dao).reset();
+ }
+ }
protected SubscriptionData createSubscription(final String productName, final BillingPeriod term, final String planSet, final DateTime requestedDate)
throws EntitlementUserApiException {
@@ -223,13 +280,13 @@ public abstract class TestApiBase {
protected SubscriptionData createSubscriptionWithBundle(final UUID bundleId, final String productName, final BillingPeriod term, final String planSet, final DateTime requestedDate)
throws EntitlementUserApiException {
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
-
+
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundleId,
new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSet, null),
requestedDate == null ? clock.getUTCNow() : requestedDate, context);
assertNotNull(subscription);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
return subscription;
}
@@ -325,7 +382,7 @@ public abstract class TestApiBase {
@Override
public DateTime addToDateTime(DateTime dateTime) {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ return dateTime.plusYears(years);
}
@Override
public Period toJodaPeriod() {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
index e988805..9e864cd 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
@@ -21,21 +21,20 @@ import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.util.Collections;
-import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
-import org.testng.Assert;
+import org.joda.time.Interval;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.ErrorCode;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
@@ -43,10 +42,6 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.DeletedEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
@@ -67,6 +62,8 @@ public class TestRepairBP extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testFetchBundleRepair() throws Exception {
+ log.info("Starting testFetchBundleRepair");
+
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
@@ -125,11 +122,14 @@ public class TestRepairBP extends TestApiBaseRepair {
assertEquals(events.get(1).getPlanPhaseSpecifier().getBillingPeriod(), aoTerm);
}
}
+ assertListenerStatus();
}
@Test(groups={"slow"})
public void testBPRepairWithCancellationOnstart() throws Exception {
+ log.info("Starting testBPRepairWithCancellationOnstart");
+
String baseProduct = "Shotgun";
DateTime startDate = clock.getUTCNow();
@@ -137,8 +137,8 @@ public class TestRepairBP extends TestApiBaseRepair {
Subscription baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
// Stays in trial-- for instance
- Duration durationShift = getDurationDay(10);
- clock.setDeltaFromReality(durationShift, 0);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(10));
+ clock.addDeltaFromReality(it.toDurationMillis());
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -190,9 +190,9 @@ public class TestRepairBP extends TestApiBaseRepair {
// SECOND RE-ISSUE CALL-- NON DRY RUN
dryRun = false;
- testListener.expectRepairCompletion();
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
- assertTrue(testListener.isRepairCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
subscriptionRepair = realRunBundleRepair.getSubscriptions();
assertEquals(subscriptionRepair.size(), 1);
@@ -211,10 +211,15 @@ public class TestRepairBP extends TestApiBaseRepair {
assertEquals(realRunBaseSubscription.getStartDate(), startDate);
assertEquals(realRunBaseSubscription.getState(), SubscriptionState.CANCELLED);
+
+ assertListenerStatus();
}
@Test(groups={"slow"})
public void testBPRepairReplaceCreateBeforeTrial() throws Exception {
+
+ log.info("Starting testBPRepairReplaceCreateBeforeTrial");
+
String baseProduct = "Shotgun";
String newBaseProduct = "Assault-Rifle";
@@ -229,10 +234,14 @@ public class TestRepairBP extends TestApiBaseRepair {
ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, restartDate.plusDays(30)));
testBPRepairCreate(true, startDate, clockShift, baseProduct, newBaseProduct, expected);
+ assertListenerStatus();
}
@Test(groups={"slow"}, enabled=true)
public void testBPRepairReplaceCreateInTrial() throws Exception {
+
+ log.info("Starting testBPRepairReplaceCreateInTrial");
+
String baseProduct = "Shotgun";
String newBaseProduct = "Assault-Rifle";
@@ -248,9 +257,10 @@ public class TestRepairBP extends TestApiBaseRepair {
UUID baseSubscriptionId = testBPRepairCreate(true, startDate, clockShift, baseProduct, newBaseProduct, expected);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.addDeltaFromReality(getDurationDay(32));
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(32));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// CHECK WHAT"S GOING ON AFTER WE MOVE CLOCK-- FUTURE MOTIFICATION SHOULD KICK IN
SubscriptionData subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscriptionId);
@@ -269,11 +279,16 @@ public class TestRepairBP extends TestApiBaseRepair {
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
+
+ assertListenerStatus();
}
@Test(groups={"slow"})
public void testBPRepairReplaceCreateAfterTrial() throws Exception {
+
+ log.info("Starting testBPRepairReplaceCreateAfterTrial");
+
String baseProduct = "Shotgun";
String newBaseProduct = "Assault-Rifle";
@@ -288,25 +303,28 @@ public class TestRepairBP extends TestApiBaseRepair {
ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, restartDate.plusDays(30)));
testBPRepairCreate(false, startDate, clockShift, baseProduct, newBaseProduct, expected);
-
+ assertListenerStatus();
}
private UUID testBPRepairCreate(boolean inTrial, DateTime startDate, int clockShift,
String baseProduct, String newBaseProduct, List<ExistingEvent> expectedEvents) throws Exception {
+ log.info("Starting testBPRepairCreate");
+
// CREATE BP
Subscription baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
// MOVE CLOCK
if (clockShift > 0) {
if (!inTrial) {
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
}
- Duration durationShift = getDurationDay(clockShift);
- clock.setDeltaFromReality(durationShift, 0);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(clockShift));
+ clock.addDeltaFromReality(it.toDurationMillis());
if (!inTrial) {
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
}
}
@@ -327,7 +345,7 @@ public class TestRepairBP extends TestApiBaseRepair {
// FIRST ISSUE DRY RUN
BundleTimeline bRepair = createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
- boolean dryRun = true;
+ boolean dryRun = true;
BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
List<SubscriptionTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
assertEquals(subscriptionRepair.size(), 1);
@@ -362,8 +380,9 @@ public class TestRepairBP extends TestApiBaseRepair {
// SECOND RE-ISSUE CALL-- NON DRY RUN
dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
-
+ assertTrue(testListener.isCompleted(5000));
subscriptionRepair = realRunBundleRepair.getSubscriptions();
assertEquals(subscriptionRepair.size(), 1);
cur = subscriptionRepair.get(0);
@@ -402,6 +421,8 @@ public class TestRepairBP extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testBPRepairAddChangeInTrial() throws Exception {
+ log.info("Starting testBPRepairAddChangeInTrial");
+
String baseProduct = "Shotgun";
String newBaseProduct = "Assault-Rifle";
@@ -420,9 +441,10 @@ public class TestRepairBP extends TestApiBaseRepair {
UUID baseSubscriptionId = testBPRepairAddChange(true, startDate, clockShift, baseProduct, newBaseProduct, expected, 3);
// CHECK WHAT"S GOING ON AFTER WE MOVE CLOCK-- FUTURE MOTIFICATION SHOULD KICK IN
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.addDeltaFromReality(getDurationDay(32));
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(32));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
SubscriptionData subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscriptionId);
assertEquals(subscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -439,11 +461,15 @@ public class TestRepairBP extends TestApiBaseRepair {
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
+
+ assertListenerStatus();
}
@Test(groups={"slow"})
public void testBPRepairAddChangeAfterTrial() throws Exception {
+ log.info("Starting testBPRepairAddChangeAfterTrial");
+
String baseProduct = "Shotgun";
String newBaseProduct = "Assault-Rifle";
@@ -459,24 +485,27 @@ public class TestRepairBP extends TestApiBaseRepair {
expected.add(createExistingEventForAssertion(SubscriptionTransitionType.CHANGE, newBaseProduct, PhaseType.EVERGREEN,
ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, changeDate));
testBPRepairAddChange(false, startDate, clockShift, baseProduct, newBaseProduct, expected, 3);
+
+ assertListenerStatus();
}
private UUID testBPRepairAddChange(boolean inTrial, DateTime startDate, int clockShift,
String baseProduct, String newBaseProduct, List<ExistingEvent> expectedEvents, int expectedTransitions) throws Exception {
+
// CREATE BP
Subscription baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
// MOVE CLOCK
if (!inTrial) {
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
}
-
- Duration durationShift = getDurationDay(clockShift);
- clock.setDeltaFromReality(durationShift, 0);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(clockShift));
+ clock.addDeltaFromReality(it.toDurationMillis());
if (!inTrial) {
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
}
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
@@ -498,6 +527,7 @@ public class TestRepairBP extends TestApiBaseRepair {
boolean dryRun = true;
BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
+
List<SubscriptionTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
assertEquals(subscriptionRepair.size(), 1);
SubscriptionTimeline cur = subscriptionRepair.get(0);
@@ -532,7 +562,9 @@ public class TestRepairBP extends TestApiBaseRepair {
// SECOND RE-ISSUE CALL-- NON DRY RUN
dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
+ assertTrue(testListener.isCompleted(5000));
subscriptionRepair = realRunBundleRepair.getSubscriptions();
assertEquals(subscriptionRepair.size(), 1);
@@ -572,15 +604,19 @@ public class TestRepairBP extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testRepairWithFurureCancelEvent() throws Exception {
+ log.info("Starting testRepairWithFurureCancelEvent");
+
DateTime startDate = clock.getUTCNow();
// CREATE BP
Subscription baseSubscription = createSubscription("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
// MOVE CLOCK -- OUT OF TRIAL
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(getDurationDay(35), 0);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(35));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// SET CTD to BASE SUBSCRIPTION SP CANCEL OCCURS EOT
DateTime newChargedThroughDate = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
@@ -616,7 +652,9 @@ public class TestRepairBP extends TestApiBaseRepair {
BundleTimeline bRepair = createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
boolean dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
repairApi.repairBundle(bRepair, dryRun, context);
+ assertTrue(testListener.isCompleted(5000));
baseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
@@ -633,6 +671,8 @@ public class TestRepairBP extends TestApiBaseRepair {
PlanPhase currentPhase = baseSubscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
+
+ assertListenerStatus();
}
@@ -640,12 +680,11 @@ public class TestRepairBP extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testENT_REPAIR_VIEW_CHANGED_newEvent() throws Exception {
+ log.info("Starting testENT_REPAIR_VIEW_CHANGED_newEvent");
+
TestWithException test = new TestWithException();
DateTime startDate = clock.getUTCNow();
- testListener.reset();
- clock.resetDeltaFromReality();
-
final Subscription baseSubscription = createSubscription("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
test.withException(new TestWithExceptionCallback() {
@@ -663,12 +702,13 @@ public class TestRepairBP extends TestApiBaseRepair {
BundleTimeline bRepair = createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
DateTime changeTime = clock.getUTCNow();
baseSubscription.changePlan("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, changeTime, context);
- assertTrue(testListener.isApiCompleted(5000));
-
+ assertTrue(testListener.isCompleted(5000));
+
repairApi.repairBundle(bRepair, true, context);
+ assertListenerStatus();
}
}, ErrorCode.ENT_REPAIR_VIEW_CHANGED);
}
@@ -676,12 +716,11 @@ public class TestRepairBP extends TestApiBaseRepair {
@Test(groups={"slow"}, enabled=false)
public void testENT_REPAIR_VIEW_CHANGED_ctd() throws Exception {
+ log.info("Starting testENT_REPAIR_VIEW_CHANGED_ctd");
+
TestWithException test = new TestWithException();
DateTime startDate = clock.getUTCNow();
- testListener.reset();
- clock.resetDeltaFromReality();
-
final Subscription baseSubscription = createSubscription("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
test.withException(new TestWithExceptionCallback() {
@@ -704,6 +743,8 @@ public class TestRepairBP extends TestApiBaseRepair {
entitlementApi.getSubscriptionFromId(baseSubscription.getId());
repairApi.repairBundle(bRepair, true, context);
+
+ assertListenerStatus();
}
}, ErrorCode.ENT_REPAIR_VIEW_CHANGED);
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
index 57a78e6..d7fd642 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
@@ -24,13 +24,14 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
@@ -38,9 +39,6 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.DeletedEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
@@ -59,6 +57,8 @@ public class TestRepairWithAO extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testRepairChangeBPWithAddonIncluded() throws Exception {
+ log.info("Starting testRepairChangeBPWithAddonIncluded");
+
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
@@ -67,15 +67,16 @@ public class TestRepairWithAO extends TestApiBaseRepair {
SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
SubscriptionData aoSubscription2 = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
- clock.addDeltaFromReality(someTimeLater);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -165,8 +166,11 @@ public class TestRepairWithAO extends TestApiBaseRepair {
assertEquals(newBaseSubscription.getAllTransitions().size(), 2);
assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
- dryRun = false;
+ dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, context);
+ assertTrue(testListener.isCompleted(5000));
+
aoRepair = getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
@@ -210,6 +214,8 @@ public class TestRepairWithAO extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testRepairChangeBPWithAddonNonAvailable() throws Exception {
+ log.info("Starting testRepairChangeBPWithAddonNonAvailable");
+
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
@@ -218,17 +224,18 @@ public class TestRepairWithAO extends TestApiBaseRepair {
SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- AFTER TRIAL
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- someTimeLater = getDurationDay(32);
- clock.addDeltaFromReality(someTimeLater);
- assertTrue(testListener.isApiCompleted(7000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(32));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(7000));
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -295,8 +302,10 @@ public class TestRepairWithAO extends TestApiBaseRepair {
assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, context);
-
+ assertTrue(testListener.isCompleted(5000));
+
aoRepair = getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
assertEquals(aoRepair.getExistingEvents().size(), 3);
@@ -327,6 +336,8 @@ public class TestRepairWithAO extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testRepairCancelBP_EOT_WithAddons() throws Exception {
+ log.info("Starting testRepairCancelBP_EOT_WithAddons");
+
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
@@ -335,17 +346,19 @@ public class TestRepairWithAO extends TestApiBaseRepair {
SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- AFTER TRIAL
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- someTimeLater = getDurationDay(40);
- clock.addDeltaFromReality(someTimeLater);
- assertTrue(testListener.isApiCompleted(7000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(40));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(7000));
// SET CTD to BASE SUBSCRIPTION SP CANCEL OCCURS EOT
DateTime newChargedThroughDate = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
@@ -414,7 +427,9 @@ public class TestRepairWithAO extends TestApiBaseRepair {
assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, context);
+ assertTrue(testListener.isCompleted(5000));
aoRepair = getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
assertEquals(aoRepair.getExistingEvents().size(), 3);
@@ -443,11 +458,12 @@ public class TestRepairWithAO extends TestApiBaseRepair {
assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
// MOVE CLOCK AFTER CANCEL DATE
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
- someTimeLater = getDurationDay(32);
- clock.addDeltaFromReality(someTimeLater);
- assertTrue(testListener.isApiCompleted(7000));
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(32));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(7000));
newAoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
assertEquals(newAoSubscription.getState(), SubscriptionState.CANCELLED);
@@ -464,6 +480,9 @@ public class TestRepairWithAO extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testRepairCancelAO() throws Exception {
+
+ log.info("Starting testRepairCancelAO");
+
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
@@ -472,13 +491,14 @@ public class TestRepairWithAO extends TestApiBaseRepair {
SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
- clock.addDeltaFromReality(someTimeLater);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -530,7 +550,10 @@ public class TestRepairWithAO extends TestApiBaseRepair {
assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
+ assertTrue(testListener.isCompleted(5000));
+
aoRepair = getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
assertEquals(aoRepair.getExistingEvents().size(), 2);
@@ -553,6 +576,9 @@ public class TestRepairWithAO extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testRepairRecreateAO() throws Exception {
+
+ log.info("Starting testRepairRecreateAO");
+
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
@@ -561,13 +587,14 @@ public class TestRepairWithAO extends TestApiBaseRepair {
SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
- clock.addDeltaFromReality(someTimeLater);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -616,7 +643,9 @@ public class TestRepairWithAO extends TestApiBaseRepair {
// NOW COMMIT
dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
+ assertTrue(testListener.isCompleted(5000));
aoRepair = getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
assertEquals(aoRepair.getExistingEvents().size(), 2);
@@ -644,6 +673,8 @@ public class TestRepairWithAO extends TestApiBaseRepair {
@Test(groups={"slow"})
public void testRepairChangeAOOK() throws Exception {
+ log.info("Starting testRepairChangeAOOK");
+
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
@@ -652,13 +683,14 @@ public class TestRepairWithAO extends TestApiBaseRepair {
SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
- clock.addDeltaFromReality(someTimeLater);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -706,7 +738,9 @@ public class TestRepairWithAO extends TestApiBaseRepair {
// AND NOW COMMIT
dryRun = false;
+ testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
+ assertTrue(testListener.isCompleted(5000));
aoRepair = getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
assertEquals(aoRepair.getExistingEvents().size(), 3);
@@ -734,10 +768,11 @@ public class TestRepairWithAO extends TestApiBaseRepair {
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- someTimeLater = getDurationDay(60);
- clock.addDeltaFromReality(someTimeLater);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(60));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
newAoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
currentPhase = newAoSubscription.getCurrentPhase();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java
index 285b17d..54fda89 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -31,22 +32,17 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.ErrorCode;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.DeletedEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
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.SubscriptionData;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
@@ -61,27 +57,30 @@ public class TestRepairWithError extends TestApiBaseRepair {
return Guice.createInjector(Stage.DEVELOPMENT, new MockEngineModuleMemory());
}
-
- @BeforeMethod(groups={"fast"})
- public void beforeMethod() throws Exception {
+ @BeforeMethod(alwaysRun = true)
+ public void setupTest() throws Exception {
+ super.setupTest();
test = new TestWithException();
startDate = clock.getUTCNow();
baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
- testListener.reset();
- clock.resetDeltaFromReality();
}
@Test(groups={"fast"})
public void testENT_REPAIR_NEW_EVENT_BEFORE_LAST_BP_REMAINING() throws Exception {
+
+ log.info("Starting testENT_REPAIR_NEW_EVENT_BEFORE_LAST_BP_REMAINING");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException {
// MOVE AFTER TRIAL
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- Duration durationShift = getDurationDay(40);
- clock.setDeltaFromReality(durationShift, 0);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(40));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
+ assertTrue(testListener.isCompleted(5000));
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -99,23 +98,26 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"})
public void testENT_REPAIR_INVALID_DELETE_SET() throws Exception {
+
+ log.info("Starting testENT_REPAIR_INVALID_DELETE_SET");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException, EntitlementUserApiException {
- Duration durationShift = getDurationDay(3);
- clock.setDeltaFromReality(durationShift, 0);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
DateTime changeTime = clock.getUTCNow();
baseSubscription.changePlan("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, changeTime, context);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
// MOVE AFTER TRIAL
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- durationShift = getDurationDay(40);
- clock.addDeltaFromReality(durationShift);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(40));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -133,6 +135,9 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"})
public void testENT_REPAIR_NON_EXISTENT_DELETE_EVENT() throws Exception {
+
+ log.info("Starting testENT_REPAIR_NON_EXISTENT_DELETE_EVENT");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException {
@@ -153,15 +158,18 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"})
public void testENT_REPAIR_SUB_RECREATE_NOT_EMPTY() throws Exception {
+
+ log.info("Starting testENT_REPAIR_SUB_RECREATE_NOT_EMPTY");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException {
// MOVE AFTER TRIAL
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- Duration durationShift = getDurationDay(40);
- clock.setDeltaFromReality(durationShift, 0);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(40));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -181,15 +189,19 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"})
public void testENT_REPAIR_SUB_EMPTY() throws Exception {
+
+ log.info("Starting testENT_REPAIR_SUB_EMPTY");
+
test.withException(new TestWithExceptionCallback() {
+
@Override
public void doTest() throws EntitlementRepairException {
// MOVE AFTER TRIAL
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- Duration durationShift = getDurationDay(40);
- clock.setDeltaFromReality(durationShift, 0);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(40));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -209,19 +221,22 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"})
public void testENT_REPAIR_AO_CREATE_BEFORE_BP_START() throws Exception {
+
+ log.info("Starting testENT_REPAIR_AO_CREATE_BEFORE_BP_START");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException, EntitlementUserApiException {
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
-
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
- clock.addDeltaFromReality(someTimeLater);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -254,19 +269,22 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"})
public void testENT_REPAIR_NEW_EVENT_BEFORE_LAST_AO_REMAINING() throws Exception {
+
+ log.info("Starting testENT_REPAIR_NEW_EVENT_BEFORE_LAST_AO_REMAINING");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException, EntitlementUserApiException {
// MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
- Duration someTimeLater = getDurationDay(3);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
-
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
SubscriptionData aoSubscription = createSubscription("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
// MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
- clock.addDeltaFromReality(someTimeLater);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
BundleTimeline bundleRepair = repairApi.getBundleRepair(bundle.getId());
sortEventsOnBundle(bundleRepair);
@@ -298,13 +316,17 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"})
public void testENT_REPAIR_BP_RECREATE_MISSING_AO() throws Exception {
+
+ log.info("Starting testENT_REPAIR_BP_RECREATE_MISSING_AO");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException, EntitlementUserApiException {
//testListener.pushExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(getDurationDay(5), 0);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
//assertTrue(testListener.isCompleted(5000));
SubscriptionData aoSubscription = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
@@ -337,14 +359,18 @@ public class TestRepairWithError extends TestApiBaseRepair {
//
@Test(groups={"fast"}, enabled=false)
public void testENT_REPAIR_BP_RECREATE_MISSING_AO_CREATE() throws Exception {
+
+ log.info("Starting testENT_REPAIR_BP_RECREATE_MISSING_AO_CREATE");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException, EntitlementUserApiException {
/*
//testListener.pushExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(getDurationDay(5), 0);
- //assertTrue(testListener.isCompleted(5000));
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
SubscriptionData aoSubscription = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
@@ -382,6 +408,9 @@ public class TestRepairWithError extends TestApiBaseRepair {
@Test(groups={"fast"}, enabled=false)
public void testENT_REPAIR_MISSING_AO_DELETE_EVENT() throws Exception {
+
+ log.info("Starting testENT_REPAIR_MISSING_AO_DELETE_EVENT");
+
test.withException(new TestWithExceptionCallback() {
@Override
public void doTest() throws EntitlementRepairException, EntitlementUserApiException {
@@ -389,6 +418,10 @@ public class TestRepairWithError extends TestApiBaseRepair {
/*
// MOVE CLOCK -- JUST BEFORE END OF TRIAL
+ *
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(29));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
clock.setDeltaFromReality(getDurationDay(29), 0);
SubscriptionData aoSubscription = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
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 2780fe5..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,15 +21,17 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
-import org.apache.commons.lang.NotImplementedException;
+import java.util.List;
+
import org.joda.time.DateTime;
-import org.joda.time.Period;
+import org.joda.time.Interval;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Duration;
@@ -40,10 +42,9 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PlanSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.catalog.api.TimeUnit;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
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;
@@ -57,6 +58,8 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"slow"})
public void testCreateCancelAddon() {
+ log.info("Starting testCreateCancelAddon");
+
try {
String baseProduct = "Shotgun";
BillingPeriod baseTerm = BillingPeriod.MONTHLY;
@@ -75,11 +78,12 @@ public class TestUserApiAddOn extends TestApiBase {
aoSubscription.cancel(now, false, context);
testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+ assertTrue(testListener.isCompleted(5000));
assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
+ assertListenerStatus();
} catch (Exception e) {
Assert.fail(e.getMessage());
}
@@ -87,6 +91,9 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"slow"})
public void testCancelBPWithAddon() {
+
+ log.info("Starting testCancelBPWithAddon");
+
try {
String baseProduct = "Shotgun";
@@ -103,13 +110,13 @@ public class TestUserApiAddOn extends TestApiBase {
SubscriptionData aoSubscription = createSubscription(aoProduct, aoTerm, aoPriceList);
testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
// MOVE CLOCK AFTER TRIAL + AO DISCOUNT
- Duration twoMonths = getDurationMonth(2);
- clock.setDeltaFromReality(twoMonths, DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(5000));
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(2));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// SET CTD TO CANCEL IN FUTURE
DateTime now = clock.getUTCNow();
@@ -129,15 +136,19 @@ public class TestUserApiAddOn extends TestApiBase {
// MOVE AFTER CANCELLATION
testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
- clock.addDeltaFromReality(ctd);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// REFETCH AO SUBSCRIPTION AND CHECK THIS IS CANCELLED
aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
+ assertListenerStatus();
+
} catch (Exception e) {
Assert.fail(e.getMessage());
}
@@ -145,7 +156,10 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"slow"})
- public void testChangeBPWithAddonNonIncluded() {
+ public void testChangeBPWithAddonIncluded() {
+
+ log.info("Starting testChangeBPWithAddonIncluded");
+
try {
String baseProduct = "Shotgun";
@@ -162,13 +176,13 @@ public class TestUserApiAddOn extends TestApiBase {
SubscriptionData aoSubscription = createSubscription(aoProduct, aoTerm, aoPriceList);
testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
// MOVE CLOCK AFTER TRIAL + AO DISCOUNT
- Duration twoMonths = getDurationMonth(2);
- clock.setDeltaFromReality(twoMonths, DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(5000));
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(2));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// SET CTD TO CHANGE IN FUTURE
DateTime now = clock.getUTCNow();
@@ -182,16 +196,26 @@ 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.pushNextApiExpectedEvent(NextEvent.CHANGE);
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, now, context);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
// REFETCH AO SUBSCRIPTION AND CHECK THIS CANCELLED
aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
+ assertListenerStatus();
} catch (Exception e) {
Assert.fail(e.getMessage());
}
@@ -199,6 +223,9 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"slow"})
public void testChangeBPWithAddonNonAvailable() {
+
+ log.info("Starting testChangeBPWithAddonNonAvailable");
+
try {
String baseProduct = "Shotgun";
@@ -215,13 +242,13 @@ public class TestUserApiAddOn extends TestApiBase {
SubscriptionData aoSubscription = createSubscription(aoProduct, aoTerm, aoPriceList);
testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
// MOVE CLOCK AFTER TRIAL + AO DISCOUNT
- Duration twoMonths = getDurationMonth(2);
- clock.setDeltaFromReality(twoMonths, DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(5000));
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(2));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// SET CTD TO CANCEL IN FUTURE
DateTime now = clock.getUTCNow();
@@ -235,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);
@@ -245,16 +280,18 @@ public class TestUserApiAddOn extends TestApiBase {
// MOVE AFTER CHANGE
testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
- clock.addDeltaFromReality(ctd);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// REFETCH AO SUBSCRIPTION AND CHECK THIS CANCELLED
aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
+ assertListenerStatus();
} catch (Exception e) {
Assert.fail(e.getMessage());
}
@@ -263,6 +300,9 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"slow"})
public void testAddonCreateWithBundleAlign() {
+
+ log.info("Starting testAddonCreateWithBundleAlign");
+
try {
String aoProduct = "Telescopic-Scope";
BillingPeriod aoTerm = BillingPeriod.MONTHLY;
@@ -278,6 +318,7 @@ public class TestUserApiAddOn extends TestApiBase {
testAddonCreateInternal(aoProduct, aoTerm, aoPriceList, alignement);
+ assertListenerStatus();
} catch (CatalogApiException e) {
Assert.fail(e.getMessage());
}
@@ -287,6 +328,8 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"slow"})
public void testAddonCreateWithSubscriptionAlign() {
+ log.info("Starting testAddonCreateWithSubscriptionAlign");
+
try {
String aoProduct = "Laser-Scope";
BillingPeriod aoTerm = BillingPeriod.MONTHLY;
@@ -302,13 +345,15 @@ public class TestUserApiAddOn extends TestApiBase {
testAddonCreateInternal(aoProduct, aoTerm, aoPriceList, alignement);
- } catch (CatalogApiException e) {
- Assert.fail(e.getMessage());
- }
+ assertListenerStatus();
+ } catch (CatalogApiException e) {
+ Assert.fail(e.getMessage());
+ }
}
private void testAddonCreateInternal(String aoProduct, BillingPeriod aoTerm, String aoPriceList, PlanAlignmentCreate expAlignement) {
+
try {
String baseProduct = "Shotgun";
@@ -319,9 +364,9 @@ public class TestUserApiAddOn extends TestApiBase {
SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
// MOVE CLOCK 14 DAYS LATER
- Duration someTimeLater = getDurationDay(13);
- clock.setDeltaFromReality(someTimeLater, DAY_IN_MS);
-
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(14));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
// CREATE ADDON
DateTime beforeAOCreation = clock.getUTCNow();
SubscriptionData aoSubscription = createSubscription(aoProduct, aoTerm, aoPriceList);
@@ -338,73 +383,46 @@ public class TestUserApiAddOn extends TestApiBase {
assertNotNull(aoCurrentPhase);
assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.DISCOUNT);
- assertDateWithin(aoSubscription.getStartDate(), beforeAOCreation, afterAOCreation);
- assertEquals(aoSubscription.getBundleStartDate(), baseSubscription.getBundleStartDate());
-
- // CHECK next AO PHASE EVENT IS INDEED A MONTH AFTER BP STARTED => BUNDLE ALIGNMENT
- SubscriptionEvent aoPendingTranstion = aoSubscription.getPendingTransition();
-
- if (expAlignement == PlanAlignmentCreate.START_OF_BUNDLE) {
- assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), baseSubscription.getStartDate().plusMonths(1));
- } else {
- assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), aoSubscription.getStartDate().plusMonths(1));
- }
-
- // ADD TWO PHASE EVENTS (BP + AO)
- testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
-
- // MOVE THROUGH TIME TO GO INTO EVERGREEN
-
- // Talk with Stephane about this fix. It seemed that the add on phase change was not appearing in the queue
- // hypothesis is that waiting a period that is exactly the duration of the phase might be an instant too short
- // depending how the comparison works
-
- //someTimeLater = aoCurrentPhase.getDuration();
- someTimeLater = new Duration() {
- @Override
- public TimeUnit getUnit() {
- return TimeUnit.DAYS;
- }
-
- @Override
- public int getNumber() {
- return 32;
- }
-
- @Override
- public DateTime addToDateTime(DateTime dateTime) {
- throw new NotImplementedException();
- }
- @Override
- public Period toJodaPeriod() {
- throw new UnsupportedOperationException();
- }
- };
-
- clock.addDeltaFromReality(someTimeLater);
- clock.addDeltaFromReality(getDurationDay(1));
- assertTrue(testListener.isApiCompleted(5000));
-
-
- // CHECK EVERYTHING AGAIN
- aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
-
- aoCurrentPlan = aoSubscription.getCurrentPlan();
- assertNotNull(aoCurrentPlan);
- assertEquals(aoCurrentPlan.getProduct().getName(),aoProduct);
- assertEquals(aoCurrentPlan.getProduct().getCategory(), ProductCategory.ADD_ON);
- assertEquals(aoCurrentPlan.getBillingPeriod(), aoTerm);
-
- aoCurrentPhase = aoSubscription.getCurrentPhase();
- assertNotNull(aoCurrentPhase);
- assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.EVERGREEN);
-
-
- aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
- aoPendingTranstion = aoSubscription.getPendingTransition();
- assertNull(aoPendingTranstion);
+ assertDateWithin(aoSubscription.getStartDate(), beforeAOCreation, afterAOCreation);
+ assertEquals(aoSubscription.getBundleStartDate(), baseSubscription.getBundleStartDate());
+
+ // CHECK next AO PHASE EVENT IS INDEED A MONTH AFTER BP STARTED => BUNDLE ALIGNMENT
+ SubscriptionEvent aoPendingTranstion = aoSubscription.getPendingTransition();
+
+ if (expAlignement == PlanAlignmentCreate.START_OF_BUNDLE) {
+ assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), baseSubscription.getStartDate().plusMonths(1));
+ } else {
+ assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), aoSubscription.getStartDate().plusMonths(1));
+ }
+
+ // ADD TWO PHASE EVENTS (BP + AO)
+ testListener.reset();
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ // MOVE THROUGH TIME TO GO INTO EVERGREEN
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(33));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
+
+
+ // CHECK EVERYTHING AGAIN
+ aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
+
+ aoCurrentPlan = aoSubscription.getCurrentPlan();
+ assertNotNull(aoCurrentPlan);
+ assertEquals(aoCurrentPlan.getProduct().getName(),aoProduct);
+ assertEquals(aoCurrentPlan.getProduct().getCategory(), ProductCategory.ADD_ON);
+ assertEquals(aoCurrentPlan.getBillingPeriod(), aoTerm);
+
+ aoCurrentPhase = aoSubscription.getCurrentPhase();
+ assertNotNull(aoCurrentPhase);
+ assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.EVERGREEN);
+
+
+ aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
+ aoPendingTranstion = aoSubscription.getPendingTransition();
+ assertNull(aoPendingTranstion);
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
index 09046f1..7fb06e0 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
@@ -22,15 +22,16 @@ import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.Assert;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.util.clock.DefaultClock;
@@ -55,20 +56,21 @@ public abstract class TestUserApiCancel extends TestApiBase {
assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL);
// ADVANCE TIME still in trial
- Duration moveALittleInTime = getDurationDay(3);
- clock.setDeltaFromReality(moveALittleInTime, 0);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
DateTime future = clock.getUTCNow();
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
// CANCEL in trial period to get IMM policy
subscription.cancel(clock.getUTCNow(), false, context);
currentPhase = subscription.getCurrentPhase();
- testListener.isApiCompleted(1000);
+ testListener.isCompleted(3000);
assertNull(currentPhase);
checkNextPhaseChange(subscription, 0, null);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -94,9 +96,11 @@ public abstract class TestUserApiCancel extends TestApiBase {
checkNextPhaseChange(subscription, 1, expectedPhaseTrialChange);
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
+ assertTrue(testListener.isCompleted(5000));
trialPhase = subscription.getCurrentPhase();
assertEquals(trialPhase.getPhaseType(), PhaseType.EVERGREEN);
@@ -106,21 +110,25 @@ public abstract class TestUserApiCancel extends TestApiBase {
billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
-
// CANCEL
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
subscription.cancel(clock.getUTCNow(), false, context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
+ testListener.reset();
// MOVE TO EOT + RECHECK
- clock.addDeltaFromReality(ctd);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
DateTime future = clock.getUTCNow();
- assertTrue(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNull(currentPhase);
checkNextPhaseChange(subscription, 0, null);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -147,22 +155,25 @@ public abstract class TestUserApiCancel extends TestApiBase {
checkNextPhaseChange(subscription, 1, expectedPhaseTrialChange);
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
trialPhase = subscription.getCurrentPhase();
assertEquals(trialPhase.getPhaseType(), PhaseType.EVERGREEN);
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
// CANCEL
subscription.cancel(clock.getUTCNow(), false, context);
- assertTrue(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNull(currentPhase);
checkNextPhaseChange(subscription, 0, null);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -191,9 +202,10 @@ public abstract class TestUserApiCancel extends TestApiBase {
checkNextPhaseChange(subscription, 1, expectedPhaseTrialChange);
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
PlanPhase currentPhase = subscription.getCurrentPhase();
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
@@ -203,27 +215,25 @@ public abstract class TestUserApiCancel extends TestApiBase {
billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
-
- // CANCEL
+ // CANCEL EOT
subscription.cancel(clock.getUTCNow(), false, context);
- assertFalse(testListener.isApiCompleted(2000));
subscription.uncancel(context);
-
+
// MOVE TO EOT + RECHECK
- clock.addDeltaFromReality(ctd);
- DateTime future = clock.getUTCNow();
- assertFalse(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.UNCANCEL);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
Plan currentPlan = subscription.getCurrentPlan();
assertEquals(currentPlan.getProduct().getName(), prod);
currentPhase = subscription.getCurrentPhase();
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
}
-
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
index 7eccbdd..625002a 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
@@ -33,25 +33,25 @@ public class TestUserApiCancelMemory extends TestUserApiCancel {
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testCancelSubscriptionIMM() {
super.testCancelSubscriptionIMM();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testCancelSubscriptionEOTWithChargeThroughDate() throws EntitlementBillingApiException {
super.testCancelSubscriptionEOTWithChargeThroughDate();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testCancelSubscriptionEOTWithNoChargeThroughDate() {
super.testCancelSubscriptionEOTWithNoChargeThroughDate();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testUncancel() throws EntitlementBillingApiException {
super.testUncancel();
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
index b5b98e4..b1d2c0b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
@@ -25,8 +25,10 @@ import java.util.ArrayList;
import java.util.List;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.Assert;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
@@ -34,7 +36,6 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.events.EntitlementEvent;
@@ -69,7 +70,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
private void tChangePlanBundleAlignEOTWithNoChargeThroughDate(String fromProd, BillingPeriod fromTerm, String fromPlanSet,
String toProd, BillingPeriod toTerm, String toPlanSet) {
- log.info("Starting testChangePlanBundleAlignEOTWithNoChargeThroughDateReal");
+ log.info("Starting testChangePlanBundleAlignEOTWithNoChargeThroughDate");
try {
@@ -78,22 +79,26 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
// MOVE TO NEXT PHASE
PlanPhase currentPhase = subscription.getCurrentPhase();
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(currentPhase.getDuration(), DAY_IN_MS);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
DateTime futureNow = clock.getUTCNow();
DateTime nextExpectedPhaseChange = DefaultClock.addDuration(subscription.getStartDate(), currentPhase.getDuration());
assertTrue(futureNow.isAfter(nextExpectedPhaseChange));
- assertTrue(testListener.isApiCompleted(3000));
+ assertTrue(testListener.isCompleted(5000));
// CHANGE PLAN
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan(toProd, toTerm, toPlanSet, clock.getUTCNow(), context);
- assertTrue(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
// CHECK CHANGE PLAN
currentPhase = subscription.getCurrentPhase();
checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.EVERGREEN);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -101,13 +106,14 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
protected void testChangePlanBundleAlignEOTWithChargeThroughDate() throws EntitlementBillingApiException {
+ log.info("Starting testChangePlanBundleAlignEOTWithChargeThroughDate");
testChangePlanBundleAlignEOTWithChargeThroughDate("Shotgun", BillingPeriod.ANNUAL, "gunclubDiscount", "Pistol", BillingPeriod.ANNUAL, "gunclubDiscount");
}
private void testChangePlanBundleAlignEOTWithChargeThroughDate(String fromProd, BillingPeriod fromTerm, String fromPlanSet,
String toProd, BillingPeriod toTerm, String toPlanSet) throws EntitlementBillingApiException {
- log.info("Starting testChangeSubscriptionEOTWithChargeThroughDate");
+
try {
// CREATE
@@ -118,9 +124,10 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
PlanPhase currentPhase = subscription.getCurrentPhase();
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
@@ -131,10 +138,11 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
// RE READ SUBSCRIPTION + CHANGE PLAN
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
subscription.changePlan(toProd, toTerm, toPlanSet, clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
testListener.reset();
// CHECK CHANGE PLAN
@@ -151,14 +159,16 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
// MOVE TO EOT
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
- clock.addDeltaFromReality(ctd);
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
currentPhase = subscription.getCurrentPhase();
checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.DISCOUNT);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -179,37 +189,31 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
SubscriptionData subscription = createSubscription(fromProd, fromTerm, fromPlanSet);
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
- Duration moveALittleInTime = getDurationDay(3);
- clock.setDeltaFromReality(moveALittleInTime, 0);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+ clock.addDeltaFromReality(it.toDurationMillis());
// CHANGE PLAN IMM
subscription.changePlan(toProd, toTerm, toPlanSet, clock.getUTCNow(), context);
checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.TRIAL);
- assertTrue(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
PlanPhase currentPhase = subscription.getCurrentPhase();
DateTime nextExpectedPhaseChange = DefaultClock.addDuration(subscription.getStartDate(), currentPhase.getDuration());
checkNextPhaseChange(subscription, 1, nextExpectedPhaseChange);
// NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.addDeltaFromReality(currentPhase.getDuration());
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(30));
+ clock.addDeltaFromReality(it.toDurationMillis());
DateTime futureNow = clock.getUTCNow();
- /*
- try {
- Thread.sleep(1000 * 3000);
- } catch (Exception e) {
-
- }
- */
-
assertTrue(futureNow.isAfter(nextExpectedPhaseChange));
- assertTrue(testListener.isApiCompleted(3000));
+ assertTrue(testListener.isCompleted(5000));
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -217,14 +221,13 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
protected void testChangePlanChangePlanAlignEOTWithChargeThroughDate() throws EntitlementBillingApiException {
+ log.info("Starting testChangePlanChangePlanAlignEOTWithChargeThroughDate");
tChangePlanChangePlanAlignEOTWithChargeThroughDate("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, "Assault-Rifle", BillingPeriod.ANNUAL, "rescue");
}
private void tChangePlanChangePlanAlignEOTWithChargeThroughDate(String fromProd, BillingPeriod fromTerm, String fromPlanSet,
String toProd, BillingPeriod toTerm, String toPlanSet) throws EntitlementBillingApiException {
- log.info("Starting testChangePlanBundleAlignEOTWithChargeThroughDate");
-
try {
DateTime currentTime = clock.getUTCNow();
@@ -235,11 +238,12 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
currentTime = clock.getUTCNow();
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
currentTime = clock.getUTCNow();
- assertTrue(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
// SET CTD
Duration ctd = getDurationMonth(1);
@@ -254,19 +258,22 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
// CHANGE PLAN
currentTime = clock.getUTCNow();
-
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
subscription.changePlan(toProd, toTerm, toPlanSet, clock.getUTCNow(), context);
checkChangePlan(subscription, fromProd, ProductCategory.BASE, fromTerm, PhaseType.EVERGREEN);
// CHECK CHANGE DID NOT KICK IN YET
- assertFalse(testListener.isApiCompleted(2000));
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ assertFalse(testListener.isCompleted(3000));
+ testListener.reset();
// MOVE TO AFTER CTD
- clock.addDeltaFromReality(ctd);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
currentTime = clock.getUTCNow();
- assertTrue(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
// CHECK CORRECT PRODUCT, PHASE, PLAN SET
String currentProduct = subscription.getCurrentPlan().getProduct().getName();
@@ -276,22 +283,27 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
-
// MOVE TIME ABOUT ONE MONTH BEFORE NEXT EXPECTED PHASE CHANGE
- clock.addDeltaFromReality(getDurationMonth(11));
-
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(11));
+ clock.addDeltaFromReality(it.toDurationMillis());
currentTime = clock.getUTCNow();
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
+ testListener.reset();
DateTime nextExpectedPhaseChange = DefaultClock.addDuration(newChargedThroughDate, currentPhase.getDuration());
checkNextPhaseChange(subscription, 1, nextExpectedPhaseChange);
// MOVE TIME RIGHT AFTER NEXT EXPECTED PHASE CHANGE
- clock.addDeltaFromReality(getDurationMonth(1));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
currentTime = clock.getUTCNow();
- assertTrue(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -299,15 +311,18 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
protected void testMultipleChangeLastIMM() throws EntitlementBillingApiException {
+ log.info("Starting testMultipleChangeLastIMM");
try {
SubscriptionData subscription = createSubscription("Assault-Rifle", BillingPeriod.MONTHLY, "gunclubDiscount");
PlanPhase trialPhase = subscription.getCurrentPhase();
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
+ assertTrue(testListener.isCompleted(5000));
// SET CTD
List<Duration> durationList = new ArrayList<Duration>();
@@ -320,14 +335,16 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
// CHANGE EOT
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Pistol", BillingPeriod.MONTHLY, "gunclubDiscount", clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
+ testListener.reset();
// CHANGE
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount", clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertTrue(testListener.isCompleted(5000));
Plan currentPlan = subscription.getCurrentPlan();
assertNotNull(currentPlan);
@@ -338,7 +355,8 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
-
+
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -346,15 +364,17 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
protected void testMultipleChangeLastEOT() throws EntitlementBillingApiException {
+ log.info("Starting testMultipleChangeLastEOT");
try {
SubscriptionData subscription = createSubscription("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount");
PlanPhase trialPhase = subscription.getCurrentPhase();
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// SET CTD
List<Duration> durationList = new ArrayList<Duration>();
@@ -366,15 +386,17 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
// CHANGE EOT
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Shotgun", BillingPeriod.MONTHLY, "gunclubDiscount", clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
testListener.reset();
// CHANGE EOT
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Pistol", BillingPeriod.ANNUAL, "gunclubDiscount", clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
testListener.reset();
// CHECK NO CHANGE OCCURED YET
@@ -389,9 +411,11 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
// ACTIVATE CHNAGE BY MOVING AFTER CTD
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
- clock.addDeltaFromReality(ctd);
- assertTrue(testListener.isApiCompleted(3000));
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
+ assertTrue(testListener.isCompleted(5000));
currentPlan = subscription.getCurrentPlan();
assertNotNull(currentPlan);
@@ -406,9 +430,10 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.addDeltaFromReality(currentPhase.getDuration());
- assertTrue(testListener.isApiCompleted(3000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(6));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
currentPlan = subscription.getCurrentPlan();
@@ -421,7 +446,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
-
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -429,6 +454,9 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
protected void testCorrectPhaseAlignmentOnChange() {
+
+ log.info("Starting testCorrectPhaseAlignmentOnChange");
+
try {
SubscriptionData subscription = createSubscription("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
@@ -436,13 +464,15 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
// MOVE 2 DAYS AHEAD
- clock.setDeltaFromReality(getDurationDay(1), DAY_IN_MS);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(2));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
// CHANGE IMMEDIATE TO A 3 PHASES PLAN
testListener.reset();
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount", clock.getUTCNow(), context);
- assertTrue(testListener.isApiCompleted(3000));
+ assertTrue(testListener.isCompleted(5000));
testListener.reset();
// CHECK EVERYTHING LOOKS CORRECT
@@ -456,9 +486,11 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
// MOVE AFTER TRIAL PERIOD -> DISCOUNT
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.addDeltaFromReality(trialPhase.getDuration());
- assertTrue(testListener.isApiCompleted(3000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(30));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
+ assertTrue(testListener.isCompleted(5000));
trialPhase = subscription.getCurrentPhase();
assertEquals(trialPhase.getPhaseType(), PhaseType.DISCOUNT);
@@ -471,6 +503,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
assertEquals(nextPhaseEffectiveDate, expectedNextPhaseDate);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
index 8bbdd2d..0da1169 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
@@ -33,38 +33,38 @@ public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testChangePlanBundleAlignEOTWithNoChargeThroughDate() {
super.testChangePlanBundleAlignEOTWithNoChargeThroughDate();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testChangePlanBundleAlignEOTWithChargeThroughDate() throws EntitlementBillingApiException {
super.testChangePlanBundleAlignEOTWithChargeThroughDate();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testChangePlanBundleAlignIMM() {
super.testChangePlanBundleAlignIMM();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testMultipleChangeLastIMM() throws EntitlementBillingApiException {
super.testMultipleChangeLastIMM();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testMultipleChangeLastEOT() throws EntitlementBillingApiException {
super.testMultipleChangeLastEOT();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testCorrectPhaseAlignmentOnChange() {
super.testCorrectPhaseAlignmentOnChange();
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
index 509b056..1039b85 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
@@ -33,7 +33,7 @@ public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
return Guice.createInjector(Stage.DEVELOPMENT, new MockEngineModuleSql());
}
- @Test(enabled= true, groups={"stress"})
+ @Test(enabled= false, groups={"stress"})
public void stressTest() throws Exception {
for (int i = 0; i < MAX_STRESS_ITERATIONS; i++) {
cleanupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
index ef4533d..6517044 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
@@ -24,17 +24,18 @@ import static org.testng.Assert.assertTrue;
import java.util.List;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.events.EntitlementEvent;
import com.ning.billing.entitlement.events.phase.PhaseEvent;
@@ -56,8 +57,8 @@ public abstract class TestUserApiCreate extends TestApiBase {
String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
@@ -69,8 +70,10 @@ public abstract class TestUserApiCreate extends TestApiBase {
assertEquals(subscription.getBundleId(), bundle.getId());
assertEquals(subscription.getStartDate(), requestedDate);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
+ assertListenerStatus();
+
} catch (EntitlementUserApiException e) {
log.error("Unexpected exception",e);
Assert.fail(e.getMessage());
@@ -89,7 +92,7 @@ public abstract class TestUserApiCreate extends TestApiBase {
BillingPeriod term = BillingPeriod.MONTHLY;
String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
getProductSpecifier(productName, planSetName, term, PhaseType.EVERGREEN), clock.getUTCNow(), context);
@@ -111,6 +114,8 @@ public abstract class TestUserApiCreate extends TestApiBase {
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
+ assertListenerStatus();
+
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -127,7 +132,7 @@ public abstract class TestUserApiCreate extends TestApiBase {
BillingPeriod term = BillingPeriod.MONTHLY;
String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
getProductSpecifier(productName, planSetName, term, null),
@@ -149,7 +154,7 @@ public abstract class TestUserApiCreate extends TestApiBase {
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
List<EntitlementEvent> events = dao.getPendingEventsForSubscription(subscription.getId());
assertNotNull(events);
@@ -160,15 +165,16 @@ public abstract class TestUserApiCreate extends TestApiBase {
DateTime nextExpectedPhaseChange = DefaultClock.addDuration(subscription.getStartDate(), currentPhase.getDuration());
assertEquals(nextPhaseChange, nextExpectedPhaseChange);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
-
- clock.setDeltaFromReality(currentPhase.getDuration(), DAY_IN_MS);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
DateTime futureNow = clock.getUTCNow();
assertTrue(futureNow.isAfter(nextPhaseChange));
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -184,7 +190,7 @@ public abstract class TestUserApiCreate extends TestApiBase {
BillingPeriod term = BillingPeriod.ANNUAL;
String planSetName = "gunclubDiscount";
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
// CREATE SUBSCRIPTION
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
@@ -194,27 +200,30 @@ public abstract class TestUserApiCreate extends TestApiBase {
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL);
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
// MOVE TO DISCOUNT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(currentPhase.getDuration(), DAY_IN_MS);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
- assertTrue(testListener.isApiCompleted(2000));
+
// MOVE TO EVERGREEN PHASE + RE-READ SUBSCRIPTION
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.addDeltaFromReality(currentPhase.getDuration());
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusYears(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
-
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
@@ -229,17 +238,15 @@ public abstract class TestUserApiCreate extends TestApiBase {
BillingPeriod term = BillingPeriod.ANNUAL;
String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
getProductSpecifier(productName, planSetName, term, null), clock.getUTCNow(), context);
assertNotNull(subscription);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
}
-
-
-
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
index 7987d87..e4969f1 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
@@ -32,31 +32,31 @@ public class TestUserApiCreateMemory extends TestUserApiCreate {
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testCreateWithRequestedDate() {
super.testCreateWithRequestedDate();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testCreateWithInitialPhase() {
super.testSimpleSubscriptionThroughPhases();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
public void testSimpleCreateSubscription() {
super.testSimpleCreateSubscription();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
protected void testSimpleSubscriptionThroughPhases() {
super.testSimpleSubscriptionThroughPhases();
}
@Override
- @Test(enabled=true, groups={"fast-disabled"})
+ @Test(enabled=true, groups={"fast"})
protected void testSubscriptionWithAddOn() {
super.testSubscriptionWithAddOn();
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
index fdd6e66..0973666 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
@@ -26,19 +26,20 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
@@ -69,6 +70,7 @@ public class TestUserApiDemos extends TestApiBase {
@Test(enabled=true, groups="demos")
public void testDemo1() throws EntitlementBillingApiException {
+ log.info("Starting testSubscriptionWithAddOn");
try {
System.out.println("DEMO 1 START");
@@ -80,16 +82,17 @@ public class TestUserApiDemos extends TestApiBase {
displayState(subscription.getId(), "STEP 1. CREATED SUBSCRIPTION");
/* STEP 2. CHANGE PLAN WHILE IN TRIAL */
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount", clock.getUTCNow(), context);
- assertTrue(testListener.isApiCompleted(3000));
+ assertTrue(testListener.isCompleted(5000));
displayState(subscription.getId(), "STEP 2. CHANGED PLAN WHILE IN TRIAL");
/* STEP 3. MOVE TO DISCOUNT PHASE */
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(3000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
displayState(subscription.getId(), "STEP 3. MOVE TO DISCOUNT PHASE");
@@ -103,25 +106,28 @@ public class TestUserApiDemos extends TestApiBase {
billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Shotgun", BillingPeriod.ANNUAL, "gunclubDiscount", clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
testListener.reset();
displayState(subscription.getId(), "STEP 4. SET CTD AND CHANGE PLAN EOT (Shotgun)");
/* STEP 5. CHANGE AGAIN */
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Pistol", BillingPeriod.ANNUAL, "gunclubDiscount", clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(3000));
testListener.reset();
displayState(subscription.getId(), "STEP 5. CHANGE AGAIN EOT (Pistol)");
/* STEP 6. MOVE TO EOT AND CHECK CHANGE OCCURED */
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
- clock.addDeltaFromReality(ctd);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
Plan currentPlan = subscription.getCurrentPlan();
assertNotNull(currentPlan);
@@ -136,9 +142,10 @@ public class TestUserApiDemos extends TestApiBase {
displayState(subscription.getId(), "STEP 6. MOVE TO EOT");
/* STEP 7. MOVE TO NEXT PHASE */
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.addDeltaFromReality(currentPhase.getDuration());
- assertTrue(testListener.isApiCompleted(5000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(6));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
currentPlan = subscription.getCurrentPlan();
@@ -154,11 +161,12 @@ public class TestUserApiDemos extends TestApiBase {
displayState(subscription.getId(), "STEP 7. MOVE TO NEXT PHASE");
/* STEP 8. CANCEL IMM (NO CTD) */
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
subscription.cancel(clock.getUTCNow(), false, context);
displayState(subscription.getId(), "STEP 8. CANCELLATION");
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
index c3f6061..c56e0e0 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
@@ -25,6 +25,7 @@ import java.util.UUID;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -32,11 +33,11 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.ning.billing.ErrorCode;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
import com.ning.billing.util.clock.DefaultClock;
@@ -52,6 +53,9 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=true, groups={"fast"})
public void testCreateSubscriptionBadCatalog() {
+
+ log.info("Starting testCreateSubscriptionBadCatalog");
+
// WRONG PRODUCTS
tCreateSubscriptionInternal(bundle.getId(), null, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.CAT_NULL_PRODUCT_NAME);
tCreateSubscriptionInternal(bundle.getId(), "Whatever", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.CAT_NO_SUCH_PRODUCT);
@@ -68,16 +72,19 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=true, groups={"fast"})
public void testCreateSubscriptionNoBundle() {
+ log.info("Starting testCreateSubscriptionNoBundle");
tCreateSubscriptionInternal(null, "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_NO_BUNDLE);
}
@Test(enabled=true, groups={"fast"})
public void testCreateSubscriptionNoBP() {
+ log.info("Starting testCreateSubscriptionNoBP");
tCreateSubscriptionInternal(bundle.getId(), "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_NO_BP);
}
@Test(enabled=true, groups={"fast"})
public void testCreateSubscriptionBPExists() {
+ log.info("Starting testCreateSubscriptionBPExists");
try {
createSubscription("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME);
tCreateSubscriptionInternal(bundle.getId(), "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_BP_EXISTS);
@@ -89,6 +96,7 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=true, groups={"fast"})
public void testRecreateSubscriptionBPNotCancelled() {
+ log.info("Starting testRecreateSubscriptionBPNotCancelled");
try {
SubscriptionData subscription = createSubscription("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME);
try {
@@ -105,6 +113,7 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=true, groups={"fast"})
public void testCreateSubscriptionAddOnNotAvailable() {
+ log.info("Starting testCreateSubscriptionAddOnNotAvailable");
try {
UUID accountId = UUID.randomUUID();
SubscriptionBundle aoBundle = entitlementApi.createBundleForAccount(accountId, "myAOBundle", context);
@@ -118,6 +127,7 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=true, groups={"fast"})
public void testCreateSubscriptionAddOnIncluded() {
+ log.info("Starting testCreateSubscriptionAddOnIncluded");
try {
UUID accountId = UUID.randomUUID();
SubscriptionBundle aoBundle = entitlementApi.createBundleForAccount(accountId, "myAOBundle", context);
@@ -150,10 +160,11 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=true, groups={"fast"})
public void testChangeSubscriptionNonActive() {
+ log.info("Starting testChangeSubscriptionNonActive");
try {
Subscription subscription = createSubscription("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME);
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
subscription.cancel(clock.getUTCNow(), false, context);
try {
subscription.changePlan("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, clock.getUTCNow(), context);
@@ -174,15 +185,17 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=true, groups={"fast"})
public void testChangeSubscriptionFutureCancelled() {
+ log.info("Starting testChangeSubscriptionFutureCancelled");
try {
Subscription subscription = createSubscription("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
PlanPhase trialPhase = subscription.getCurrentPhase();
// MOVE TO NEXT PHASE
PlanPhase currentPhase = subscription.getCurrentPhase();
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(currentPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(3000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// SET CTD TO CANCEL IN FUTURE
@@ -204,6 +217,8 @@ public class TestUserApiError extends TestApiBase {
assertFalse(true);
}
}
+
+ assertListenerStatus();
} catch (Exception e) {
e.printStackTrace();
Assert.assertFalse(true);
@@ -213,10 +228,12 @@ public class TestUserApiError extends TestApiBase {
@Test(enabled=false, groups={"fast"})
public void testCancelBadState() {
+ log.info("Starting testCancelBadState");
}
@Test(enabled=true, groups={"fast"})
public void testUncancelBadState() {
+ log.info("Starting testUncancelBadState");
try {
Subscription subscription = createSubscription("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
@@ -230,7 +247,7 @@ public class TestUserApiError extends TestApiBase {
assertFalse(true);
}
}
-
+ assertListenerStatus();
} catch (Exception e) {
e.printStackTrace();
Assert.assertFalse(true);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
index b7506dd..389ac5f 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
@@ -25,9 +25,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
public abstract class TestUserApiRecreate extends TestApiBase {
@@ -36,9 +36,10 @@ public abstract class TestUserApiRecreate extends TestApiBase {
protected void testRecreateWithBPCanceledThroughSubscription() {
- log.info("Starting testRecreateWithBPCanceled");
+ log.info("Starting testRecreateWithBPCanceledThroughSubscription");
try {
testCreateAndRecreate(false);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
log.error("Unexpected exception",e);
Assert.fail(e.getMessage());
@@ -46,9 +47,10 @@ public abstract class TestUserApiRecreate extends TestApiBase {
}
protected void testCreateWithBPCanceledFromUserApi() {
- log.info("Starting testCreateWithBPCanceled");
+ log.info("Starting testCreateWithBPCanceledFromUserApi");
try {
testCreateAndRecreate(true);
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
log.error("Unexpected exception",e);
Assert.fail(e.getMessage());
@@ -65,8 +67,8 @@ public abstract class TestUserApiRecreate extends TestApiBase {
BillingPeriod term = BillingPeriod.MONTHLY;
String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
getProductSpecifier(productName, planSetName, term, null), requestedDate, context);
assertNotNull(subscription);
@@ -75,7 +77,7 @@ public abstract class TestUserApiRecreate extends TestApiBase {
assertEquals(subscription.getStartDate(), requestedDate);
assertEquals(productName, subscription.getCurrentPlan().getProduct().getName());
- assertTrue(testListener.isApiCompleted(5000));
+ assertTrue(testListener.isCompleted(5000));
// CREATE (AGAIN) WITH NEW PRODUCT
productName = "Pistol";
@@ -95,11 +97,11 @@ public abstract class TestUserApiRecreate extends TestApiBase {
}
// NOW CANCEL ADN THIS SHOULD WORK
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
subscription.cancel(null, false, context);
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.RE_CREATE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.RE_CREATE);
// Avoid ordering issue for events at exact same date; this is actually a real good test, we
// we test it at Beatrix level. At this level that would work for sql tests but not for in memory.
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
index 92ac1b0..7f874de 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
@@ -21,17 +21,18 @@ import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import org.joda.time.DateTime;
+import org.joda.time.Interval;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.PlanPhase;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
@@ -44,7 +45,7 @@ public class TestUserApiScenarios extends TestApiBase {
return Guice.createInjector(Stage.DEVELOPMENT, new MockEngineModuleSql());
}
- @Test(enabled=true)
+ @Test(groups={"slow"}, enabled=true)
public void testChangeIMMCancelUncancelChangeEOT() throws EntitlementBillingApiException {
log.info("Starting testChangeIMMCancelUncancelChangeEOT");
@@ -54,14 +55,15 @@ public class TestUserApiScenarios extends TestApiBase {
PlanPhase trialPhase = subscription.getCurrentPhase();
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Pistol", BillingPeriod.ANNUAL, "gunclubDiscount", clock.getUTCNow(), context);
- testListener.isApiCompleted(3000);
+ testListener.isCompleted(5000);
// MOVE TO NEXT PHASE
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
- assertTrue(testListener.isApiCompleted(2000));
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
// SET CTD
Duration ctd = getDurationMonth(1);
@@ -71,22 +73,28 @@ public class TestUserApiScenarios extends TestApiBase {
subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
// CANCEL EOT
- testListener.pushNextApiExpectedEvent(NextEvent.CANCEL);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CANCEL);
subscription.cancel(clock.getUTCNow(), false, context);
- assertFalse(testListener.isApiCompleted(2000));
+ assertFalse(testListener.isCompleted(5000));
testListener.reset();
// UNCANCEL
subscription.uncancel(context);
// CHANGE EOT
- testListener.pushNextApiExpectedEvent(NextEvent.CHANGE);
+ testListener.setNonExpectedMode();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
subscription.changePlan("Pistol", BillingPeriod.MONTHLY, "gunclubDiscount", clock.getUTCNow(), context);
- assertFalse(testListener.isApiCompleted(2000));
-
- clock.addDeltaFromReality(ctd);
- assertTrue(testListener.isApiCompleted(3000));
+ assertFalse(testListener.isCompleted(5000));
+ testListener.reset();
+
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+ assertTrue(testListener.isCompleted(5000));
+ assertListenerStatus();
} catch (EntitlementUserApiException e) {
Assert.fail(e.getMessage());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
index 90966d8..c208521 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
@@ -28,9 +28,9 @@ import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
import com.ning.billing.entitlement.api.TestApiBase;
import com.ning.billing.entitlement.glue.MockEngineModuleSql;
import com.ning.billing.util.callcontext.CallContext;
@@ -66,7 +66,7 @@ public class TestUserCustomFieldsSql extends TestApiBase {
@Test(enabled=true, groups={"slow"})
public void testOverwriteCustomFields() {
- log.info("Starting testCreateWithRequestedDate");
+ log.info("Starting testOverwriteCustomFields");
try {
DateTime init = clock.getUTCNow();
@@ -76,8 +76,8 @@ public class TestUserCustomFieldsSql extends TestApiBase {
BillingPeriod term = BillingPeriod.MONTHLY;
String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
getProductSpecifier(productName, planSetName, term, null), requestedDate, context);
assertNotNull(subscription);
@@ -122,7 +122,7 @@ public class TestUserCustomFieldsSql extends TestApiBase {
@Test(enabled=true, groups={"slow"})
public void testBasicCustomFields() {
- log.info("Starting testCreateWithRequestedDate");
+ log.info("Starting testBasicCustomFields");
try {
DateTime init = clock.getUTCNow();
@@ -132,8 +132,8 @@ public class TestUserCustomFieldsSql extends TestApiBase {
BillingPeriod term = BillingPeriod.MONTHLY;
String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
- testListener.pushNextApiExpectedEvent(NextEvent.PHASE);
- testListener.pushNextApiExpectedEvent(NextEvent.CREATE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.CREATE);
SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
getProductSpecifier(productName, planSetName, term, null), requestedDate, context);
assertNotNull(subscription);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index 9b75099..5eb760c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -158,7 +158,6 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
@Override
public void createSubscription(final SubscriptionData subscription, final List<EntitlementEvent> initialEvents,
final CallContext context) {
-
synchronized(events) {
events.addAll(initialEvents);
for (final EntitlementEvent cur : initialEvents) {
@@ -285,7 +284,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
@Override
public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent,
final CallContext context, final int seqId) {
- synchronized (cancelEvent) {
+ synchronized(events) {
cancelNextPhaseEvent(subscriptionId);
insertEvent(cancelEvent);
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index c795ca5..31e0da3 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
@@ -23,13 +23,12 @@ import com.ning.billing.util.clock.MockClockModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.CallContextModule;
-public class MockEngineModule extends EntitlementModule {
+public class MockEngineModule extends DefaultEntitlementModule {
@Override
protected void configure() {
super.configure();
- install(new BusModule());
install(new CatalogModule());
bind(AccountUserApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class));
install(new MockClockModule());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java
index e46e4bc..148b62d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleMemory.java
@@ -22,6 +22,8 @@ import com.ning.billing.entitlement.api.timeline.RepairEntitlementLifecycleDao;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.engine.dao.MockEntitlementDaoMemory;
import com.ning.billing.entitlement.engine.dao.RepairEntitlementDao;
+import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.BusModule.BusType;
import com.ning.billing.util.notificationq.MockNotificationQueueService;
import com.ning.billing.util.notificationq.NotificationQueueService;
@@ -42,6 +44,7 @@ public class MockEngineModuleMemory extends MockEngineModule {
@Override
protected void configure() {
super.configure();
+ install(new BusModule(BusType.MEMORY));
installNotificationQueue();
}
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
index 9195c91..e1b3742 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
@@ -32,8 +32,10 @@ import com.ning.billing.entitlement.engine.dao.MockEntitlementDaoSql;
import com.ning.billing.entitlement.engine.dao.RepairEntitlementDao;
+import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.FieldStoreModule;
import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.BusModule.BusType;
public class MockEngineModuleSql extends MockEngineModule {
@@ -65,6 +67,7 @@ public class MockEngineModuleSql extends MockEngineModule {
installDBI();
install(new NotificationQueueModule());
install(new FieldStoreModule());
+ install(new BusModule(BusType.PERSISTENT));
super.configure();
}
}
invoice/pom.xml 45(+12 -33)
diff --git a/invoice/pom.xml b/invoice/pom.xml
index 1762bc0..7d1911b 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -33,26 +33,25 @@
<groupId>com.ning.billing</groupId>
<artifactId>killbill-util</artifactId>
</dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-util</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
+ <dependency>
+ <groupId>org.jdbi</groupId>
+ <artifactId>jdbi</artifactId>
</dependency>
<dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-entitlement</artifactId>
- <scope>test</scope>
+ <groupId>org.antlr</groupId>
+ <artifactId>stringtemplate</artifactId>
+ <scope>runtime</scope>
</dependency>
<dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-entitlement</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <scope>provided</scope>
</dependency>
+ <!-- TEST SCOPE -->
<dependency>
<groupId>com.ning.billing</groupId>
- <artifactId>killbill-junction</artifactId>
+ <artifactId>killbill-util</artifactId>
+ <type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
@@ -67,12 +66,6 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-account</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
@@ -83,20 +76,6 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>org.jdbi</groupId>
- <artifactId>jdbi</artifactId>
- </dependency>
- <dependency>
- <groupId>org.antlr</groupId>
- <artifactId>stringtemplate</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>com.google.inject</groupId>
- <artifactId>guice</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>com.jayway.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
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 31294c0..5178a29 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
@@ -18,63 +18,46 @@ package com.ning.billing.invoice.dao;
import java.math.BigDecimal;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
-import com.ning.billing.util.dao.EntityAudit;
-import com.ning.billing.util.dao.ObjectType;
-import com.ning.billing.util.dao.TableName;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.Transaction;
import org.skife.jdbi.v2.TransactionStatus;
import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.InvoicePayment;
-import com.ning.billing.invoice.api.user.DefaultInvoiceCreationEvent;
import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
import com.ning.billing.invoice.notification.NextBillingDatePoster;
-import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.customfield.CustomField;
import com.ning.billing.util.customfield.dao.CustomFieldSqlDao;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.TableName;
import com.ning.billing.util.tag.ControlTagType;
import com.ning.billing.util.tag.Tag;
import com.ning.billing.util.tag.dao.TagDao;
public class DefaultInvoiceDao implements InvoiceDao {
- private final static Logger log = LoggerFactory.getLogger(DefaultInvoiceDao.class);
-
private final InvoiceSqlDao invoiceSqlDao;
private final InvoicePaymentSqlDao invoicePaymentSqlDao;
- private final BillingApi billingApi;
private final TagDao tagDao;
- private final Bus eventBus;
-
private final NextBillingDatePoster nextBillingDatePoster;
@Inject
- public DefaultInvoiceDao(final IDBI dbi, final Bus eventBus,
- final BillingApi entitlementBillingApi,
+ public DefaultInvoiceDao(final IDBI dbi,
final NextBillingDatePoster nextBillingDatePoster,
final TagDao tagDao) {
this.invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
- this.eventBus = eventBus;
- this.billingApi = entitlementBillingApi;
this.nextBillingDatePoster = nextBillingDatePoster;
this.tagDao = tagDao;
}
@@ -140,7 +123,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
return invoiceSqlDao.inTransaction(new Transaction<Invoice, InvoiceSqlDao>() {
@Override
public Invoice inTransaction(final InvoiceSqlDao invoiceDao, final TransactionStatus status) throws Exception {
- Invoice invoice = invoiceDao.getById(invoiceId);
+ Invoice invoice = invoiceDao.getById(invoiceId.toString());
if (invoice != null) {
populateChildren(invoice, invoiceDao);
@@ -153,62 +136,58 @@ public class DefaultInvoiceDao implements InvoiceDao {
@Override
public void create(final Invoice invoice, final CallContext context) {
+
invoiceSqlDao.inTransaction(new Transaction<Void, InvoiceSqlDao>() {
@Override
- public Void inTransaction(final InvoiceSqlDao invoiceDao, final TransactionStatus status) throws Exception {
+ public Void inTransaction(final InvoiceSqlDao transactional, final TransactionStatus status) throws Exception {
// STEPH this seems useless
- Invoice currentInvoice = invoiceDao.getById(invoice.getId());
+ Invoice currentInvoice = transactional.getById(invoice.getId().toString());
if (currentInvoice == null) {
- invoiceDao.create(invoice, context);
+ List<EntityAudit> audits = new ArrayList<EntityAudit>();
+
+ transactional.create(invoice, context);
+ Long recordId = transactional.getRecordId(invoice.getId().toString());
+ audits.add(new EntityAudit(TableName.INVOICES, recordId, ChangeType.INSERT));
+
+ List<Long> recordIdList;
List<InvoiceItem> recurringInvoiceItems = invoice.getInvoiceItems(RecurringInvoiceItem.class);
- RecurringInvoiceItemSqlDao recurringInvoiceItemDao = invoiceDao.become(RecurringInvoiceItemSqlDao.class);
+ RecurringInvoiceItemSqlDao recurringInvoiceItemDao = transactional.become(RecurringInvoiceItemSqlDao.class);
recurringInvoiceItemDao.batchCreateFromTransaction(recurringInvoiceItems, context);
+ recordIdList = recurringInvoiceItemDao.getRecordIds(invoice.getId().toString());
+ audits.addAll(createAudits(TableName.RECURRING_INVOICE_ITEMS, recordIdList));
- notifyOfFutureBillingEvents(invoiceDao, recurringInvoiceItems);
+ notifyOfFutureBillingEvents(transactional, recurringInvoiceItems);
List<InvoiceItem> fixedPriceInvoiceItems = invoice.getInvoiceItems(FixedPriceInvoiceItem.class);
- FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = invoiceDao.become(FixedPriceInvoiceItemSqlDao.class);
+ FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = transactional.become(FixedPriceInvoiceItemSqlDao.class);
fixedPriceInvoiceItemDao.batchCreateFromTransaction(fixedPriceInvoiceItems, context);
+ recordIdList = fixedPriceInvoiceItemDao.getRecordIds(invoice.getId().toString());
+ audits.addAll(createAudits(TableName.FIXED_INVOICE_ITEMS, recordIdList));
- setChargedThroughDates(invoiceDao, 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 = invoiceDao.become(InvoicePaymentSqlDao.class);
-
-// TODO: add auditing and move to collections
-// Long maxRecordId = invoicePaymentSqlDao.getMaxRecordId(TableName.INVOICE_PAYMENTS);
-// invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
-// Map<UUID, Long> recordIdMap = invoicePaymentSqlDao.getRecordIdMap(maxRecordId);
-//
-//
-//
-//
-// auditSqlDao.insertAuditFromTransaction("invoices", invoice.getId().toString(), ChangeType.INSERT, context);
-// 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);
+ InvoicePaymentSqlDao invoicePaymentSqlDao = transactional.become(InvoicePaymentSqlDao.class);
+ invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
+ recordIdList = invoicePaymentSqlDao.getRecordIds(invoice.getId().toString());
+ audits.addAll(createAudits(TableName.INVOICE_PAYMENTS, recordIdList));
+ transactional.insertAuditFromTransaction(audits, context);
}
return null;
}
});
+ }
- // TODO: move this inside the transaction once the bus is persistent
- InvoiceCreationEvent event;
- event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
- invoice.getBalance(), invoice.getCurrency(),
- invoice.getInvoiceDate(),
- context.getUserToken());
- try {
- eventBus.post(event);
- } catch (Bus.EventBusException e) {
- throw new RuntimeException(e);
+ private List<EntityAudit> createAudits(TableName tableName, List<Long> recordIdList) {
+ List<EntityAudit> entityAuditList = new ArrayList<EntityAudit>();
+ for (Long recordId : recordIdList) {
+ entityAuditList.add(new EntityAudit(tableName, recordId, ChangeType.INSERT));
}
+
+ return entityAuditList;
}
@Override
@@ -238,9 +217,9 @@ public class DefaultInvoiceDao implements InvoiceDao {
transactional.notifyOfPaymentAttempt(invoicePayment, context);
String invoicePaymentId = invoicePayment.getId().toString();
- Long recordId = transactional.getRecordId(TableName.INVOICE_PAYMENTS, invoicePaymentId);
- EntityAudit audit = new EntityAudit(recordId, ChangeType.INSERT);
- transactional.insertAuditFromTransaction(TableName.INVOICE_PAYMENTS, audit, context);
+ Long recordId = transactional.getRecordId(invoicePaymentId);
+ EntityAudit audit = new EntityAudit(TableName.INVOICE_PAYMENTS, recordId, ChangeType.INSERT);
+ transactional.insertAuditFromTransaction(audit, context);
return null;
}
@@ -365,34 +344,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/dao/FixedPriceInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
index 175cab6..d4fa5ee 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
@@ -27,6 +27,7 @@ import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
@@ -46,11 +47,13 @@ import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.dao.EntityDao;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(FixedPriceInvoiceItemSqlDao.FixedPriceInvoiceItemMapper.class)
-public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
+public interface FixedPriceInvoiceItemSqlDao extends EntitySqlDao<InvoiceItem> {
+ @SqlQuery
+ List<Long> getRecordIds(@Bind("invoiceId") final String invoiceId);
+
@SqlQuery
List<InvoiceItem> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
index 879f58d..a11c8e0 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
@@ -32,6 +32,7 @@ import com.ning.billing.util.dao.AuditSqlDao;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextBinder;
import com.ning.billing.util.dao.MapperBase;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
@@ -52,7 +53,10 @@ import com.ning.billing.invoice.api.InvoicePayment;
@ExternalizedSqlViaStringTemplate3
@RegisterMapper(InvoicePaymentSqlDao.InvoicePaymentMapper.class)
-public interface InvoicePaymentSqlDao extends Transactional<InvoicePaymentSqlDao>, AuditSqlDao, Transmogrifier {
+public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Transactional<InvoicePaymentSqlDao>, AuditSqlDao, Transmogrifier {
+ @SqlQuery
+ List<Long> getRecordIds(@Bind("invoiceId") final String invoiceId);
+
@SqlQuery
public InvoicePayment getByPaymentAttemptId(@Bind("paymentAttempt") final String paymentAttemptId);
@@ -82,9 +86,9 @@ public interface InvoicePaymentSqlDao extends Transactional<InvoicePaymentSqlDao
public static class InvoicePaymentMapper extends MapperBase implements ResultSetMapper<InvoicePayment> {
@Override
public InvoicePayment map(int index, ResultSet result, StatementContext context) throws SQLException {
- final UUID id = UUID.fromString(result.getString("id"));
- final UUID paymentAttemptId = UUID.fromString(result.getString("payment_attempt_id"));
- final UUID invoiceId = UUID.fromString(result.getString("invoice_id"));
+ final UUID id = getUUID(result, "id");
+ final UUID paymentAttemptId = getUUID(result, "payment_attempt_id");
+ final UUID invoiceId = getUUID(result, "invoice_id");
final DateTime paymentAttemptDate = getDate(result, "payment_attempt_date");
final BigDecimal amount = result.getBigDecimal("amount");
final String currencyString = result.getString("currency");
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
index 39e1016..af611bc 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
@@ -20,9 +20,10 @@ import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.model.DefaultInvoice;
import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.dao.AuditSqlDao;
import com.ning.billing.util.dao.UuidMapper;
import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.dao.EntityDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
@@ -53,7 +54,7 @@ import java.util.UUID;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(InvoiceSqlDao.InvoiceMapper.class)
-public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<InvoiceSqlDao>, Transmogrifier, CloseMe {
+public interface InvoiceSqlDao extends EntitySqlDao<Invoice>, AuditSqlDao, Transactional<InvoiceSqlDao>, Transmogrifier, CloseMe {
@Override
@SqlUpdate
void create(@InvoiceBinder Invoice invoice, @CallContextBinder final CallContext context);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
index 3fc76ee..4daa560 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
@@ -27,7 +27,7 @@ import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
-import com.ning.billing.util.entity.dao.EntityDao;
+import com.ning.billing.util.dao.MapperBase;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
@@ -47,10 +47,14 @@ import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(RecurringInvoiceItemSqlDao.RecurringInvoiceItemMapper.class)
-public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
+public interface RecurringInvoiceItemSqlDao extends EntitySqlDao<InvoiceItem> {
+ @SqlQuery
+ List<Long> getRecordIds(@Bind("invoiceId") final String invoiceId);
+
@SqlQuery
List<InvoiceItem> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId);
@@ -96,23 +100,22 @@ public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
}
}
- public static class RecurringInvoiceItemMapper implements ResultSetMapper<InvoiceItem> {
+ public static class RecurringInvoiceItemMapper extends MapperBase implements ResultSetMapper<InvoiceItem> {
@Override
public InvoiceItem map(int index, ResultSet result, StatementContext context) throws SQLException {
- UUID id = UUID.fromString(result.getString("id"));
- UUID invoiceId = UUID.fromString(result.getString("invoice_id"));
- UUID accountId = UUID.fromString(result.getString("account_id"));
- UUID subscriptionId = result.getString("subscription_id") == null ? null : UUID.fromString(result.getString("subscription_id"));
- UUID bundleId = result.getString("bundle_id") == null ? null : UUID.fromString(result.getString("bundle_id"));
+ UUID id = getUUID(result, "id");
+ UUID invoiceId = getUUID(result, "invoice_id");
+ UUID accountId = getUUID(result, "account_id");
+ UUID subscriptionId = getUUID(result, "subscription_id");
+ UUID bundleId = getUUID(result, "bundle_id");
String planName = result.getString("plan_name");
String phaseName = result.getString("phase_name");
- DateTime startDate = new DateTime(result.getTimestamp("start_date"));
- DateTime endDate = new DateTime(result.getTimestamp("end_date"));
+ DateTime startDate = getDate(result, "start_date");
+ DateTime endDate = getDate(result, "end_date");
BigDecimal amount = result.getBigDecimal("amount");
BigDecimal rate = result.getBigDecimal("rate");
Currency currency = Currency.valueOf(result.getString("currency"));
- String reversedItemString = result.getString("reversed_item_id");
- UUID reversedItemId = (reversedItemString == null) ? null : UUID.fromString(reversedItemString);
+ UUID reversedItemId = getUUID(result, "reversed_item_id");
return new RecurringInvoiceItem(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate,
amount, rate, currency, reversedItemId);
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/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
index 659d876..d7aed8c 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
@@ -53,6 +53,28 @@ batchCreateFromTransaction() ::= <<
:startDate, :endDate, :amount, :currency, :userName, :createdDate);
>>
+getRecordIds() ::= <<
+ SELECT record_id, id
+ FROM fixed_invoice_items
+ WHERE invoice_id = :invoiceId;
+>>
+
+auditFields(prefix) ::= <<
+ <prefix>table_name,
+ <prefix>record_id,
+ <prefix>change_type,
+ <prefix>change_date,
+ <prefix>changed_by,
+ <prefix>reason_code,
+ <prefix>comments,
+ <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+ INSERT INTO audit_log(<auditFields()>)
+ VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
test() ::= <<
SELECT 1
FROM fixed_invoice_items;
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
index a673b81..c6989bb 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
@@ -49,6 +49,28 @@ getInvoicePayment() ::= <<
WHERE payment_id = :payment_id;
>>
+getRecordIds() ::= <<
+ SELECT record_id, id
+ FROM invoice_payments
+ WHERE invoice_id = :invoiceId;
+>>
+
+auditFields(prefix) ::= <<
+ <prefix>table_name,
+ <prefix>record_id,
+ <prefix>change_type,
+ <prefix>change_date,
+ <prefix>changed_by,
+ <prefix>reason_code,
+ <prefix>comments,
+ <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+ INSERT INTO audit_log(<auditFields()>)
+ VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
test() ::= <<
SELECT 1 FROM invoice_payments;
>>
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index b83dc82..f8efa27 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -1,18 +1,6 @@
group InvoiceDao;
-invoiceFetchFields(prefix) ::= <<
- <prefix>invoice_number,
- <prefix>id,
- <prefix>account_id,
- <prefix>invoice_date,
- <prefix>target_date,
- <prefix>currency,
- <prefix>migrated,
- <prefix>created_by,
- <prefix>created_date
->>
-
-invoiceSetFields(prefix) ::= <<
+invoiceFields(prefix) ::= <<
<prefix>id,
<prefix>account_id,
<prefix>invoice_date,
@@ -24,42 +12,42 @@ invoiceSetFields(prefix) ::= <<
>>
get() ::= <<
- SELECT <invoiceFetchFields()>
+ SELECT record_id as invoice_number, <invoiceFields()>
FROM invoices
ORDER BY target_date ASC;
>>
getInvoicesByAccount() ::= <<
- SELECT <invoiceFetchFields()>
+ SELECT record_id as invoice_number, <invoiceFields()>
FROM invoices
WHERE account_id = :accountId AND migrated = 'FALSE'
ORDER BY target_date ASC;
>>
getAllInvoicesByAccount() ::= <<
- SELECT <invoiceFetchFields()>
+ SELECT record_id as invoice_number, <invoiceFields()>
FROM invoices
WHERE account_id = :accountId
ORDER BY target_date ASC;
>>
getInvoicesByAccountAfterDate() ::= <<
- SELECT <invoiceFetchFields()>
+ SELECT record_id as invoice_number, <invoiceFields()>
FROM invoices
WHERE account_id = :accountId AND target_date >= :fromDate AND migrated = 'FALSE'
ORDER BY target_date ASC;
>>
getInvoicesBySubscription() ::= <<
- SELECT <invoiceFetchFields("i.")>
+ SELECT record_id as invoice_number, <invoiceFields("i.")>
FROM invoices i
LEFT JOIN recurring_invoice_items rii ON i.id = rii.invoice_id
WHERE rii.subscription_id = :subscriptionId AND migrated = 'FALSE'
- GROUP BY <invoiceFetchFields("i.")>;
+ GROUP BY record_id as invoice_number, <invoiceFields("i.")>;
>>
getById() ::= <<
- SELECT <invoiceFetchFields()>
+ SELECT record_id as invoice_number, <invoiceFields()>
FROM invoices
WHERE id = :id;
>>
@@ -75,7 +63,7 @@ getAccountBalance() ::= <<
>>
create() ::= <<
- INSERT INTO invoices(<invoiceSetFields()>)
+ INSERT INTO invoices(<invoiceFields()>)
VALUES (:id, :accountId, :invoiceDate, :targetDate, :currency, :migrated, :userName, :createdDate);
>>
@@ -87,7 +75,7 @@ getInvoiceIdByPaymentAttemptId() ::= <<
>>
getUnpaidInvoicesByAccountId() ::= <<
- SELECT <invoiceFetchFields("i.")>
+ SELECT record_id as invoice_number, <invoiceFields("i.")>
FROM invoices i
LEFT JOIN invoice_payment_summary ips ON i.id = ips.invoice_id
LEFT JOIN invoice_item_summary iis ON i.id = iis.invoice_id
@@ -97,6 +85,28 @@ getUnpaidInvoicesByAccountId() ::= <<
ORDER BY i.target_date ASC;
>>
+getRecordId() ::= <<
+ SELECT record_id
+ FROM invoices
+ WHERE id = :id;
+>>
+
+auditFields(prefix) ::= <<
+ <prefix>table_name,
+ <prefix>record_id,
+ <prefix>change_type,
+ <prefix>change_date,
+ <prefix>changed_by,
+ <prefix>reason_code,
+ <prefix>comments,
+ <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+ INSERT INTO audit_log(<auditFields()>)
+ VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
test() ::= <<
SELECT 1
FROM invoices;
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
index 7573ef3..8afb199 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
@@ -55,6 +55,28 @@ batchCreateFromTransaction() ::= <<
:amount, :rate, :currency, :reversedItemId, :userName, :createdDate);
>>
+getRecordIds() ::= <<
+ SELECT record_id, id
+ FROM recurring_invoice_items
+ WHERE invoice_id = :invoiceId;
+>>
+
+auditFields(prefix) ::= <<
+ <prefix>table_name,
+ <prefix>record_id,
+ <prefix>change_type,
+ <prefix>change_date,
+ <prefix>changed_by,
+ <prefix>reason_code,
+ <prefix>comments,
+ <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+ INSERT INTO audit_log(<auditFields()>)
+ VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
test() ::= <<
SELECT 1
FROM recurring_invoice_items;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
index e2d52e3..fe5d886 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
@@ -16,16 +16,15 @@
package com.ning.billing.invoice.api.migration;
-import com.ning.billing.entitlement.api.billing.ChargeThruApi;
import com.ning.billing.invoice.MockModule;
import com.ning.billing.invoice.api.InvoiceNotifier;
-import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.invoice.glue.DefaultInvoiceModule;
import com.ning.billing.invoice.notification.NextBillingDateNotifier;
import com.ning.billing.invoice.notification.NextBillingDatePoster;
import com.ning.billing.invoice.notification.NullInvoiceNotifier;
-import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.email.templates.TemplateModule;
public class MockModuleNoEntitlement extends MockModule {
// @Override
@@ -42,7 +41,7 @@ public class MockModuleNoEntitlement extends MockModule {
@Override
protected void installInvoiceModule() {
- install(new InvoiceModule(){
+ install(new DefaultInvoiceModule(){
@Override
protected void installNotifiers() {
@@ -55,7 +54,8 @@ public class MockModuleNoEntitlement extends MockModule {
});
-
+ install(new TemplateModule());
+
}
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 1926c72..efedbaf 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/dao/InvoiceItemDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
index 6da2581..9acde8e 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
@@ -47,7 +47,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
rate, rate, Currency.USD);
recurringInvoiceItemDao.create(item, context);
- RecurringInvoiceItem thisItem = (RecurringInvoiceItem) recurringInvoiceItemDao.getById(item.getId());
+ RecurringInvoiceItem thisItem = (RecurringInvoiceItem) recurringInvoiceItemDao.getById(item.getId().toString());
assertNotNull(thisItem);
assertEquals(thisItem.getId(), item.getId());
assertEquals(thisItem.getInvoiceId(), item.getInvoiceId());
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
index b35062d..081b21f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
@@ -21,14 +21,12 @@ import static org.testng.Assert.assertNotNull;
import java.io.IOException;
import java.net.URL;
-import com.ning.billing.entitlement.api.user.EntitlementUserApi;
-import com.ning.billing.invoice.api.InvoiceNotifier;
-import com.ning.billing.invoice.notification.NullInvoiceNotifier;
import org.skife.jdbi.v2.IDBI;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.catalog.glue.CatalogModule;
import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.invoice.api.InvoiceNotifier;
import com.ning.billing.invoice.api.test.DefaultInvoiceTestApi;
import com.ning.billing.invoice.api.test.InvoiceTestApi;
import com.ning.billing.invoice.dao.InvoicePaymentSqlDao;
@@ -37,13 +35,16 @@ import com.ning.billing.invoice.notification.MockNextBillingDateNotifier;
import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
import com.ning.billing.invoice.notification.NextBillingDateNotifier;
import com.ning.billing.invoice.notification.NextBillingDatePoster;
+import com.ning.billing.invoice.notification.NullInvoiceNotifier;
import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.glue.MockEntitlementModule;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.DefaultCallContextFactory;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.DefaultClock;
+import com.ning.billing.util.email.templates.TemplateModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.FieldStoreModule;
import com.ning.billing.util.glue.GlobalLockerModule;
@@ -51,7 +52,7 @@ import com.ning.billing.util.glue.TagStoreModule;
import com.ning.billing.util.notificationq.MockNotificationQueueService;
import com.ning.billing.util.notificationq.NotificationQueueService;
-public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
+public class InvoiceModuleWithEmbeddedDb extends DefaultInvoiceModule {
private final MysqlTestingHelper helper = new MysqlTestingHelper();
private IDBI dbi;
@@ -111,13 +112,15 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
bind(BillingApi.class).toInstance(billingApi);
install(new CatalogModule());
-
+ install(new MockEntitlementModule());
install(new GlobalLockerModule());
super.configure();
bind(InvoiceTestApi.class).to(DefaultInvoiceTestApi.class).asEagerSingleton();
install(new BusModule());
+ install(new TemplateModule());
+
}
private static void loadSystemPropertiesFromClasspath(final String resource) {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
index 17e732b..bd43d0a 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
@@ -25,8 +25,8 @@ import com.ning.billing.util.globallocker.MockGlobalLocker;
import com.ning.billing.util.glue.FieldStoreModule;
-public class InvoiceModuleWithMocks extends InvoiceModule {
- @Override
+public class InvoiceModuleWithMocks extends DefaultInvoiceModule {
+ @Override
protected void installInvoiceDao() {
bind(MockInvoiceDao.class).asEagerSingleton();
bind(InvoiceDao.class).to(MockInvoiceDao.class);
@@ -49,7 +49,7 @@ public class InvoiceModuleWithMocks extends InvoiceModule {
}
@Override
- protected void installInvoiceMigrationApi() {
+ public void installInvoiceMigrationApi() {
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
index 521069c..c756020 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
@@ -16,9 +16,6 @@
package com.ning.billing.invoice;
-import com.ning.billing.invoice.api.formatters.InvoiceFormatterFactory;
-import com.ning.billing.invoice.template.formatters.DefaultInvoiceFormatterFactory;
-import com.ning.billing.util.email.EmailModule;
import org.skife.config.ConfigurationObjectFactory;
import org.skife.jdbi.v2.IDBI;
@@ -27,12 +24,16 @@ import com.ning.billing.catalog.glue.CatalogModule;
import com.ning.billing.dbi.DBIProvider;
import com.ning.billing.dbi.DbiConfig;
import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.invoice.api.formatters.InvoiceFormatterFactory;
+import com.ning.billing.invoice.glue.DefaultInvoiceModule;
+import com.ning.billing.invoice.template.formatters.DefaultInvoiceFormatterFactory;
import com.ning.billing.mock.glue.MockJunctionModule;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.DefaultCallContextFactory;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.email.EmailModule;
+import com.ning.billing.util.email.templates.TemplateModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.FieldStoreModule;
import com.ning.billing.util.glue.GlobalLockerModule;
@@ -68,9 +69,11 @@ public class MockModule extends AbstractModule {
install(new BusModule());
installInvoiceModule();
install(new MockJunctionModule());
+ install(new TemplateModule());
+
}
protected void installInvoiceModule() {
- install(new InvoiceModule());
+ install(new DefaultInvoiceModule());
}
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
index 1242aee..a0eb6d5 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
@@ -40,54 +40,32 @@ import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
-import com.google.inject.name.Names;
-import com.ning.billing.catalog.DefaultCatalogService;
-import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.config.CatalogConfig;
+import com.ning.billing.catalog.MockCatalogModule;
import com.ning.billing.config.InvoiceConfig;
import com.ning.billing.dbi.DBIProvider;
import com.ning.billing.dbi.DbiConfig;
import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.entitlement.api.SubscriptionApiService;
-import com.ning.billing.entitlement.api.SubscriptionFactory;
-import com.ning.billing.entitlement.api.timeline.RepairEntitlementLifecycleDao;
-import com.ning.billing.entitlement.api.timeline.RepairSubscriptionApiService;
-import com.ning.billing.entitlement.api.timeline.RepairSubscriptionFactory;
-import com.ning.billing.entitlement.api.user.DefaultSubscriptionApiService;
-import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.engine.dao.EntitlementDao;
-import com.ning.billing.entitlement.engine.dao.AuditedEntitlementDao;
-import com.ning.billing.entitlement.engine.dao.RepairEntitlementDao;
-import com.ning.billing.entitlement.glue.EntitlementModule;
import com.ning.billing.invoice.InvoiceDispatcher;
import com.ning.billing.invoice.InvoiceListener;
-import com.ning.billing.invoice.api.InvoiceNotifier;
-import com.ning.billing.invoice.dao.DefaultInvoiceDao;
-import com.ning.billing.invoice.dao.InvoiceDao;
-import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
-import com.ning.billing.invoice.model.InvoiceGenerator;
+import com.ning.billing.invoice.glue.InvoiceModuleWithMocks;
import com.ning.billing.lifecycle.KillbillService;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
import com.ning.billing.mock.glue.MockJunctionModule;
import com.ning.billing.util.bus.Bus;
-import com.ning.billing.util.bus.InMemoryBus;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.DefaultCallContextFactory;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
-import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
-import com.ning.billing.util.customfield.dao.CustomFieldDao;
-import com.ning.billing.util.globallocker.GlobalLocker;
-import com.ning.billing.util.globallocker.MySqlGlobalLocker;
-import com.ning.billing.util.notificationq.DefaultNotificationQueueService;
+import com.ning.billing.util.clock.MockClockModule;
+import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.BusModule.BusType;
+import com.ning.billing.util.glue.NotificationQueueModule;
import com.ning.billing.util.notificationq.DummySqlTest;
import com.ning.billing.util.notificationq.NotificationQueueService;
import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
-import com.ning.billing.util.tag.dao.AuditedTagDao;
-import com.ning.billing.util.tag.dao.TagDao;
public class TestNextBillingDateNotifier {
private Clock clock;
@@ -135,16 +113,12 @@ public class TestNextBillingDateNotifier {
final Injector g = Guice.createInjector(Stage.PRODUCTION, new AbstractModule() {
protected void configure() {
- bind(Clock.class).to(ClockMock.class).asEagerSingleton();
- bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
- bind(Bus.class).to(InMemoryBus.class).asEagerSingleton();
- bind(NotificationQueueService.class).to(DefaultNotificationQueueService.class).asEagerSingleton();
- bind(InvoiceNotifier.class).to(NullInvoiceNotifier.class).asEagerSingleton();
- final InvoiceConfig invoiceConfig = new ConfigurationObjectFactory(System.getProperties()).build(InvoiceConfig.class);
- bind(InvoiceConfig.class).toInstance(invoiceConfig);
- final CatalogConfig catalogConfig = new ConfigurationObjectFactory(System.getProperties()).build(CatalogConfig.class);
- bind(CatalogConfig.class).toInstance(catalogConfig);
- bind(CatalogService.class).to(DefaultCatalogService.class).asEagerSingleton();
+ install(new MockClockModule());
+ install(new BusModule(BusType.MEMORY));
+ install(new InvoiceModuleWithMocks());
+ install(new MockJunctionModule());
+ install(new MockCatalogModule());
+ install(new NotificationQueueModule());
final MysqlTestingHelper helper = new MysqlTestingHelper();
bind(MysqlTestingHelper.class).toInstance(helper);
@@ -157,22 +131,7 @@ public class TestNextBillingDateNotifier {
bind(IDBI.class).toInstance(dbi);
}
- bind(TagDao.class).to(AuditedTagDao.class).asEagerSingleton();
- bind(EntitlementDao.class).to(AuditedEntitlementDao.class).asEagerSingleton();
- bind(EntitlementDao.class).annotatedWith(Names.named(EntitlementModule.REPAIR_NAMED)).to(RepairEntitlementDao.class);
- bind(RepairEntitlementLifecycleDao.class).annotatedWith(Names.named(EntitlementModule.REPAIR_NAMED)).to(RepairEntitlementDao.class);
- bind(RepairEntitlementDao.class).asEagerSingleton();
- bind(CustomFieldDao.class).to(AuditedCustomFieldDao.class).asEagerSingleton();
- bind(GlobalLocker.class).to(MySqlGlobalLocker.class).asEagerSingleton();
- bind(InvoiceGenerator.class).to(DefaultInvoiceGenerator.class).asEagerSingleton();
- bind(InvoiceDao.class).to(DefaultInvoiceDao.class).asEagerSingleton();
- bind(NextBillingDatePoster.class).to(DefaultNextBillingDatePoster.class).asEagerSingleton();
- bind(SubscriptionApiService.class).annotatedWith(Names.named(EntitlementModule.REPAIR_NAMED)).to(RepairSubscriptionApiService.class).asEagerSingleton();
- bind(SubscriptionApiService.class).to(DefaultSubscriptionApiService.class).asEagerSingleton();
- bind(SubscriptionFactory.class).annotatedWith(Names.named(EntitlementModule.REPAIR_NAMED)).to(RepairSubscriptionFactory.class).asEagerSingleton();
- bind(SubscriptionFactory.class).to(DefaultSubscriptionFactory.class).asEagerSingleton();
- install(new MockJunctionModule());
}
});
@@ -204,7 +163,7 @@ public class TestNextBillingDateNotifier {
@Test(enabled=true, groups="slow")
- public void test() throws Exception {
+ public void testInvoiceNotifier() throws Exception {
final UUID subscriptionId = new UUID(0L,1L);
final DateTime now = new DateTime();
final DateTime readyTime = now.plusMillis(2000);
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/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index 49fca25..1aaab2d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -22,13 +22,11 @@ import static org.testng.Assert.assertNull;
import java.math.BigDecimal;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable;
-import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.model.DefaultInvoicePayment;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
index 1241b7d..8c242d0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
@@ -15,6 +15,7 @@
*/
package com.ning.billing.jaxrs.json;
+import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;
@@ -25,7 +26,7 @@ import org.codehaus.jackson.map.annotate.JsonView;
import com.ning.billing.account.api.Account;
import com.ning.billing.entitlement.api.timeline.BundleTimeline;
import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.payment.api.PaymentInfoEvent;
+import com.ning.billing.payment.api.PaymentAttempt;
public class AccountTimelineJson {
@@ -52,7 +53,7 @@ public class AccountTimelineJson {
this.payments = payments;
}
- public AccountTimelineJson(Account account, List<Invoice> invoices, List<PaymentInfoEvent> payments, List<BundleTimeline> bundles) {
+ public AccountTimelineJson(Account account, List<Invoice> invoices, List<PaymentAttempt> payments, List<BundleTimeline> bundles) {
this.account = new AccountJsonSimple(account.getId().toString(), account.getExternalKey());
this.bundles = new LinkedList<BundleJsonWithSubscriptions>();
for (BundleTimeline cur : bundles) {
@@ -63,10 +64,13 @@ public class AccountTimelineJson {
this.invoices.add(new InvoiceJson(cur.getTotalAmount(), cur.getId().toString(), cur.getInvoiceDate(), Integer.toString(cur.getInvoiceNumber()), cur.getBalance()));
}
this.payments = new LinkedList<PaymentJson>();
- for (PaymentInfoEvent cur : payments) {
- // STEPH how to link that payment with the invoice ??
- this.payments.add(new PaymentJson(cur.getAmount(), null , cur.getPaymentNumber(), null, cur.getEffectiveDate(), cur.getStatus()));
- }
+ for (PaymentAttempt cur : payments) {
+ String status = cur.getPaymentId() != null ? "Success" : "Failed";
+ BigDecimal paidAmount = cur.getPaymentId() != null ? cur.getAmount() : BigDecimal.ZERO;
+
+ this.payments.add(new PaymentJson(cur.getAmount(), paidAmount, cur.getInvoiceId(), cur.getPaymentId(), cur.getCreatedDate(), cur.getUpdatedDate(),
+ cur.getRetryCount(), cur.getCurrency().toString(), status));
+ }
}
public AccountTimelineJson() {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java
index 9f8f7b6..753688b 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java
@@ -16,16 +16,12 @@
package com.ning.billing.jaxrs.json;
-import java.util.LinkedList;
import java.util.List;
-import java.util.UUID;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonView;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
public class BundleJsonNoSubsciptions extends BundleJsonSimple {
@@ -49,7 +45,7 @@ public class BundleJsonNoSubsciptions extends BundleJsonSimple {
public BundleJsonNoSubsciptions(SubscriptionBundle bundle) {
- super(bundle.getId().toString(), bundle.getKey());
+ super(bundle.getId().toString(), bundle.getKey());
this.accountId = bundle.getAccountId().toString();
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
index dd2c788..a51e09e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
@@ -53,7 +53,7 @@ public class BundleJsonWithSubscriptions extends BundleJsonSimple {
}
public BundleJsonWithSubscriptions(SubscriptionBundle bundle) {
- super(bundle.getId().toString(), bundle.getKey());
+ super(bundle.getId().toString(), bundle.getKey());
this.subscriptions = null;
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CustomFieldJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CustomFieldJson.java
new file mode 100644
index 0000000..cb9e36b
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CustomFieldJson.java
@@ -0,0 +1,51 @@
+/*
+ * 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.jaxrs.json;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+
+import com.ning.billing.util.customfield.CustomField;
+
+public class CustomFieldJson {
+
+ private final String name;
+ private final String value;
+
+ public CustomFieldJson() {
+ this.name = null;
+ this.value = null;
+ }
+
+ @JsonCreator
+ public CustomFieldJson(String name, String value) {
+ super();
+ this.name = name;
+ this.value = value;
+ }
+
+ public CustomFieldJson(CustomField input) {
+ this.name = input.getName();
+ this.value = input.getValue();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getValue() {
+ return value;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java
index 30264d7..1a33a04 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java
@@ -23,6 +23,8 @@ import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonView;
import org.joda.time.DateTime;
+import com.ning.billing.invoice.api.Invoice;
+
public class InvoiceJson {
@JsonView(BundleTimelineViews.Base.class)
@@ -40,6 +42,15 @@ public class InvoiceJson {
@JsonView(BundleTimelineViews.Base.class)
private final BigDecimal balance;
+
+ public InvoiceJson() {
+ this.amount = null;
+ this.invoiceId = null;
+ this.invoiceDate = null;
+ this.invoiceNumber = null;
+ this.balance = null;
+ }
+
@JsonCreator
public InvoiceJson(@JsonProperty("amount") BigDecimal amount,
@JsonProperty("invoice_id") String invoiceId,
@@ -54,6 +65,14 @@ public class InvoiceJson {
this.balance = balance;
}
+ public InvoiceJson(Invoice input) {
+ this.amount = input.getTotalAmount();
+ this.invoiceId = input.getId().toString();
+ this.invoiceDate = input.getInvoiceDate();
+ this.invoiceNumber = String.valueOf(input.getInvoiceNumber());
+ this.balance = input.getBalance();
+ }
+
public BigDecimal getAmount() {
return amount;
}
@@ -73,4 +92,56 @@ public class InvoiceJson {
public BigDecimal getBalance() {
return balance;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((amount == null) ? 0 : amount.hashCode());
+ result = prime * result + ((balance == null) ? 0 : balance.hashCode());
+ result = prime * result
+ + ((invoiceDate == null) ? 0 : invoiceDate.hashCode());
+ result = prime * result
+ + ((invoiceId == null) ? 0 : invoiceId.hashCode());
+ result = prime * result
+ + ((invoiceNumber == null) ? 0 : invoiceNumber.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ InvoiceJson other = (InvoiceJson) obj;
+ if (amount == null) {
+ if (other.amount != null)
+ return false;
+ } else if (!amount.equals(other.amount))
+ return false;
+ if (balance == null) {
+ if (other.balance != null)
+ return false;
+ } else if (!balance.equals(other.balance))
+ return false;
+ if (invoiceDate == null) {
+ if (other.invoiceDate != null)
+ return false;
+ } else if (!invoiceDate.equals(other.invoiceDate))
+ return false;
+ if (invoiceId == null) {
+ if (other.invoiceId != null)
+ return false;
+ } else if (!invoiceId.equals(other.invoiceId))
+ return false;
+ if (invoiceNumber == null) {
+ if (other.invoiceNumber != null)
+ return false;
+ } else if (!invoiceNumber.equals(other.invoiceNumber))
+ return false;
+ return true;
+ }
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java
index 3a9fd4d..5d2a3a0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java
@@ -17,6 +17,7 @@
package com.ning.billing.jaxrs.json;
import java.math.BigDecimal;
+import java.util.UUID;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
@@ -27,37 +28,55 @@ import com.ning.billing.util.clock.DefaultClock;
public class PaymentJson {
- @JsonView(BundleTimelineViews.Base.class)
private final BigDecimal paidAmount;
+
+ private final BigDecimal amount;
+
+ private final UUID invoiceId;
- @JsonView(BundleTimelineViews.Base.class)
- private final String invoiceId;
-
- @JsonView(BundleTimelineViews.Base.class)
- private final String paymentId;
+ private final UUID paymentId;
- @JsonView(BundleTimelineViews.Base.class)
private final DateTime requestedDate;
- @JsonView(BundleTimelineViews.Base.class)
private final DateTime effectiveDate;
- @JsonView(BundleTimelineViews.Base.class)
+ private final Integer retryCount;
+
+ private final String currency;
+
private final String status;
+
+ public PaymentJson() {
+ this.amount = null;
+ this.paidAmount = null;
+ this.invoiceId = null;
+ this.paymentId = null;
+ this.requestedDate = null;
+ this.effectiveDate = null;
+ this.currency = null;
+ this.retryCount = null;
+ this.status = null;
+ }
@JsonCreator
- public PaymentJson(@JsonProperty("paid_amount") BigDecimal paidAmount,
- @JsonProperty("invoice_id") String invoiceId,
- @JsonProperty("payment_id") String paymentId,
+ public PaymentJson(@JsonProperty("amount") BigDecimal amount,
+ @JsonProperty("paid_amount") BigDecimal paidAmount,
+ @JsonProperty("invoice_id") UUID invoiceId,
+ @JsonProperty("payment_id") UUID paymentId,
@JsonProperty("requested_dt") DateTime requestedDate,
@JsonProperty("effective_dt") DateTime effectiveDate,
+ @JsonProperty("retry_count") Integer retryCount,
+ @JsonProperty("currency") String currency,
@JsonProperty("status") String status) {
super();
+ this.amount = amount;
this.paidAmount = paidAmount;
this.invoiceId = invoiceId;
this.paymentId = paymentId;
this.requestedDate = DefaultClock.toUTCDateTime(requestedDate);
this.effectiveDate = DefaultClock.toUTCDateTime(effectiveDate);
+ this.currency = currency;
+ this.retryCount = retryCount;
this.status = status;
}
@@ -65,11 +84,11 @@ public class PaymentJson {
return paidAmount;
}
- public String getInvoiceId() {
+ public UUID getInvoiceId() {
return invoiceId;
}
- public String getPaymentId() {
+ public UUID getPaymentId() {
return paymentId;
}
@@ -84,4 +103,16 @@ public class PaymentJson {
public String getStatus() {
return status;
}
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public Integer getRetryCount() {
+ return retryCount;
+ }
+
+ public String getCurrency() {
+ return currency;
+ }
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
index fea22e6..2f798df 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
@@ -51,6 +51,12 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
@JsonView(BundleTimelineViews.Timeline.class)
private final DateTime effectiveDate;
+ public SubscriptionReadEventJson() {
+ super();
+ this.eventId = null;
+ this.effectiveDate = null;
+ }
+
@JsonCreator
public SubscriptionReadEventJson(@JsonProperty("event_id") String eventId,
@JsonProperty("billing_period") String billingPeriod,
@@ -148,6 +154,15 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
@JsonView(BundleTimelineViews.Timeline.class)
private final String phase;
+ public SubscriptionBaseEventJson() {
+ this.billingPeriod = null;
+ this.requestedDate = null;
+ this.product = null;
+ this.priceList = null;
+ this.eventType = null;
+ this.phase = null;
+ }
+
@JsonCreator
public SubscriptionBaseEventJson(@JsonProperty("billing_period") String billingPeriod,
@JsonProperty("requested_dt") DateTime requestedDate,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/TagDefinitionJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/TagDefinitionJson.java
new file mode 100644
index 0000000..25ef04c
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/TagDefinitionJson.java
@@ -0,0 +1,77 @@
+/*
+ * 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.jaxrs.json;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class TagDefinitionJson {
+
+ private final String name;
+ private final String description;
+
+ public TagDefinitionJson() {
+ this.name = null;
+ this.description = null;
+ }
+
+ @JsonCreator
+ public TagDefinitionJson(@JsonProperty("name") String name,
+ @JsonProperty("description") String description) {
+ super();
+ this.name = name;
+ this.description = description;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((description == null) ? 0 : description.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TagDefinitionJson other = (TagDefinitionJson) obj;
+ if (description == null) {
+ if (other.description != null)
+ return false;
+ } else if (!description.equals(other.description))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+}
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 ed0a116..92aafb3 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
@@ -18,7 +18,7 @@ package com.ning.billing.jaxrs.resources;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import java.net.URI;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -29,6 +29,7 @@ import java.util.UUID;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
@@ -37,12 +38,12 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.core.UriBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -61,10 +62,19 @@ import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.jaxrs.json.AccountJson;
import com.ning.billing.jaxrs.json.AccountTimelineJson;
import com.ning.billing.jaxrs.json.BundleJsonNoSubsciptions;
+import com.ning.billing.jaxrs.json.CustomFieldJson;
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.PaymentInfoEvent;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.PaymentAttempt;
+import com.ning.billing.util.api.TagDefinitionApiException;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.customfield.StringCustomField;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
@Singleton
@@ -79,8 +89,10 @@ public class AccountResource implements BaseJaxrsResource {
private final InvoiceUserApi invoiceApi;
private final PaymentApi paymentApi;
private final Context context;
+ private final TagUserApi tagUserApi;
private final JaxrsUriBuilder uriBuilder;
-
+ private final TagHelper tagHelper;
+
@Inject
public AccountResource(final JaxrsUriBuilder uriBuilder,
final AccountUserApi accountApi,
@@ -88,14 +100,18 @@ public class AccountResource implements BaseJaxrsResource {
final InvoiceUserApi invoiceApi,
final PaymentApi paymentApi,
final EntitlementTimelineApi timelineApi,
+ final TagUserApi tagUserApi,
+ final TagHelper tagHelper,
final Context context) {
this.uriBuilder = uriBuilder;
this.accountApi = accountApi;
+ this.tagUserApi = tagUserApi;
this.entitlementApi = entitlementApi;
this.invoiceApi = invoiceApi;
this.paymentApi = paymentApi;
this.timelineApi = timelineApi;
this.context = context;
+ this.tagHelper = tagHelper;
}
@GET
@@ -108,7 +124,6 @@ public class AccountResource implements BaseJaxrsResource {
AccountJson json = new AccountJson(account);
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
- log.warn("Failed to find account.", e);
return Response.status(Status.NO_CONTENT).build();
}
@@ -131,7 +146,6 @@ public class AccountResource implements BaseJaxrsResource {
});
return Response.status(Status.OK).entity(result).build();
} catch (AccountApiException e) {
- log.warn("Failed to find account.", e);
return Response.status(Status.NO_CONTENT).build();
}
}
@@ -151,7 +165,6 @@ public class AccountResource implements BaseJaxrsResource {
AccountJson json = new AccountJson(account);
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
- log.warn("Failed to find account.", e);
return Response.status(Status.NO_CONTENT).build();
}
}
@@ -160,17 +173,22 @@ public class AccountResource implements BaseJaxrsResource {
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
- public Response createAccount(AccountJson json) {
+ public Response createAccount(final AccountJson json,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
try {
-
AccountData data = json.toAccountData();
- final Account account = accountApi.createAccount(data, null, null, context.createContext());
- URI uri = UriBuilder.fromPath(account.getId().toString()).build();
- return uriBuilder.buildResponse(AccountResource.class, "getAccount", account.getId());
+ final Account account = accountApi.createAccount(data, null, null, context.createContext(createdBy, reason, comment));
+ Response response = uriBuilder.buildResponse(AccountResource.class, "getAccount", account.getId());
+ return response;
} catch (AccountApiException e) {
- log.info(String.format("Failed to create account %s", json), e);
- return Response.status(Status.BAD_REQUEST).build();
+ final String error = String.format("Failed to create account %s", json);
+ log.info(error, e);
+ return Response.status(Status.BAD_REQUEST).entity(error).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
}
}
@@ -178,11 +196,15 @@ public class AccountResource implements BaseJaxrsResource {
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@Path("/{accountId:" + UUID_PATTERN + "}")
- public Response updateAccount(AccountJson json, @PathParam("accountId") String accountId) {
+ public Response updateAccount(final AccountJson json,
+ @PathParam("accountId") final String accountId,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
try {
AccountData data = json.toAccountData();
UUID uuid = UUID.fromString(accountId);
- accountApi.updateAccount(uuid, data, context.createContext());
+ accountApi.updateAccount(uuid, data, context.createContext(createdBy, reason, comment));
return getAccount(accountId);
} catch (AccountApiException e) {
if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
@@ -191,6 +213,8 @@ public class AccountResource implements BaseJaxrsResource {
log.info(String.format("Failed to update account %s with %s", accountId, json), e);
return Response.status(Status.BAD_REQUEST).build();
}
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
}
}
@@ -219,7 +243,7 @@ public class AccountResource implements BaseJaxrsResource {
Account account = accountApi.getAccountById(UUID.fromString(accountId));
List<Invoice> invoices = invoiceApi.getInvoicesByAccount(account.getId());
- List<PaymentInfoEvent> payments = Collections.emptyList();
+ List<PaymentAttempt> payments = new LinkedList<PaymentAttempt>();
if (invoices.size() > 0) {
Collection<String> tmp = Collections2.transform(invoices, new Function<Invoice, String>() {
@@ -230,8 +254,9 @@ public class AccountResource implements BaseJaxrsResource {
});
List<String> invoicesId = new ArrayList<String>();
invoicesId.addAll(tmp);
-
- payments = paymentApi.getPaymentInfoList(invoicesId);
+ for (String curId : invoicesId) {
+ payments.addAll(paymentApi.getPaymentAttemptsForInvoiceId(curId));
+ }
}
List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(account.getId());
@@ -242,11 +267,183 @@ public class AccountResource implements BaseJaxrsResource {
AccountTimelineJson json = new AccountTimelineJson(account, invoices, payments, bundlesTimeline);
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
- log.warn("Failed to find account.", 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();
}
}
+
+
+ /**************************** TAGS ******************************/
+
+ @GET
+ @Path(BaseJaxrsResource.TAGS + "/{accountId:" + UUID_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getAccountTags(@PathParam("accountId") String accountId) {
+ try {
+ Account account = accountApi.getAccountById(UUID.fromString(accountId));
+ List<Tag> tags = account.getTagList();
+ Collection<String> tagNameList = (tags.size() == 0) ?
+ Collections.<String>emptyList() :
+ Collections2.transform(tags, new Function<Tag, String>() {
+ @Override
+ public String apply(Tag input) {
+ return input.getTagDefinitionName();
+ }
+ });
+ return Response.status(Status.OK).entity(tagNameList).build();
+ } catch (AccountApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ }
+ }
+
+
+ @POST
+ @Path(BaseJaxrsResource.TAGS + "/{accountId:" + UUID_PATTERN + "}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createAccountTag(@PathParam("accountId") final String accountId,
+ @QueryParam(QUERY_TAGS) final String tagList,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+
+ try {
+ Preconditions.checkNotNull(tagList, "Query % list cannot be null", QUERY_TAGS);
+
+ Account account = accountApi.getAccountById(UUID.fromString(accountId));
+
+ List<TagDefinition> input = tagHelper.getTagDifinitionFromTagList(tagList);
+ account.addTagsFromDefinitions(input);
+ Response response = uriBuilder.buildResponse(AccountResource.class, "getAccountTags", account.getId());
+ return response;
+ } catch (AccountApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (NullPointerException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (TagDefinitionApiException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
+
+ @DELETE
+ @Path(BaseJaxrsResource.TAGS + "/{accountId:" + UUID_PATTERN + "}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response deleteAccountTag(@PathParam("accountId") final String accountId,
+ @QueryParam(QUERY_TAGS) final String tagList,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+
+ try {
+ Account account = accountApi.getAccountById(UUID.fromString(accountId));
+
+ // Tag APIs needs tome rework...
+ String inputTagList = tagList;
+ if (inputTagList == null) {
+ List<Tag> existingTags = account.getTagList();
+ StringBuilder tmp = new StringBuilder();
+ for (Tag cur : existingTags) {
+ tmp.append(cur.getTagDefinitionName());
+ tmp.append(",");
+ }
+ inputTagList = tmp.toString();
+ }
+
+ List<TagDefinition> input = tagHelper.getTagDifinitionFromTagList(tagList);
+ for (TagDefinition cur : input) {
+ account.removeTag(cur);
+ }
+
+ return Response.status(Status.OK).build();
+ } catch (AccountApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (NullPointerException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (TagDefinitionApiException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
+
+ /************************ CUSTOM FIELDS ******************************/
+
+ @GET
+ @Path(BaseJaxrsResource.CUSTOM_FIELDS + "/{accountId:" + UUID_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getAccountCustomFields(@PathParam("accountId") String accountId) {
+ try {
+ Account account = accountApi.getAccountById(UUID.fromString(accountId));
+ List<CustomField> fields = account.getFieldList();
+ List<CustomFieldJson> result = new LinkedList<CustomFieldJson>();
+ for (CustomField cur : fields) {
+ result.add(new CustomFieldJson(cur));
+ }
+ return Response.status(Status.OK).entity(result).build();
+ } catch (AccountApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ }
+ }
+
+
+ @POST
+ @Path(BaseJaxrsResource.CUSTOM_FIELDS + "/{accountId:" + UUID_PATTERN + "}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createCustomField(@PathParam("accountId") final String accountId,
+ List<CustomFieldJson> customFields,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+
+ try {
+
+ Account account = accountApi.getAccountById(UUID.fromString(accountId));
+ LinkedList<CustomField> input = new LinkedList<CustomField>();
+ for (CustomFieldJson cur : customFields) {
+ input.add(new StringCustomField(cur.getName(), cur.getValue()));
+ }
+ account.saveFields(input, context.createContext(createdBy, reason, comment));
+ Response response = uriBuilder.buildResponse(AccountResource.class, "getAccountCustomFields", account.getId());
+ return response;
+ } catch (AccountApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (NullPointerException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
+
+ @DELETE
+ @Path(BaseJaxrsResource.CUSTOM_FIELDS + "/{accountId:" + UUID_PATTERN + "}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response deleteCustomFields(@PathParam("accountId") final String accountId,
+ @QueryParam(QUERY_CUSTOM_FIELDS) final String cutomFieldList,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+
+ try {
+ Account account = accountApi.getAccountById(UUID.fromString(accountId));
+ // STEPH missing API to delete custom fields
+ return Response.status(Status.OK).build();
+ } catch (AccountApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (NullPointerException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
+
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BaseJaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BaseJaxrsResource.java
index 79f4b04..2a9e2ee 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BaseJaxrsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BaseJaxrsResource.java
@@ -17,14 +17,25 @@ package com.ning.billing.jaxrs.resources;
public interface BaseJaxrsResource {
- public static final String API_PREFIX = "";
- public static final String API_VERSION = "/1.0";
+ public static final String API_PREFIX = "";
+ public static final String API_VERSION = "/1.0";
+ public static final String API_POSTFIX = "/kb";
+
+ public static final String PREFIX = API_PREFIX + API_VERSION + API_POSTFIX;
public static final String TIMELINE = "timeline";
/*
+ * Metadata Additional headers
+ */
+ public static String HDR_CREATED_BY = "X-Killbill-CreatedBy";
+ public static String HDR_REASON = "X-Killbill-Reason";
+ public static String HDR_COMMENT = "X-Killbill-Comment";
+
+ /*
* Patterns
*/
+ public static String STRING_PATTERN = "\\w+";
public static String UUID_PATTERN = "\\w+-\\w+-\\w+-\\w+-\\w+";
/*
@@ -33,15 +44,30 @@ public interface BaseJaxrsResource {
public static final String QUERY_EXTERNAL_KEY = "external_key";
public static final String QUERY_REQUESTED_DT = "requested_date";
public static final String QUERY_CALL_COMPLETION = "call_completion";
- public static final String QUERY_CALL_TIMEOUT = "call_timeout_sec";
+ public static final String QUERY_CALL_TIMEOUT = "call_timeout_sec";
+ public static final String QUERY_DRY_RUN = "dry_run";
+ public static final String QUERY_TARGET_DATE = "target_date";
+ public static final String QUERY_ACCOUNT_ID = "account_id";
- public static final String ACCOUNTS = "accounts";
- public static final String ACCOUNTS_PATH = API_PREFIX + API_VERSION + "/" + ACCOUNTS;
+ public static final String QUERY_TAGS = "tag_list";
+ public static final String QUERY_CUSTOM_FIELDS = "custom_field_list";
+
+ public static final String ACCOUNTS = "accounts";
+ public static final String ACCOUNTS_PATH = PREFIX + "/" + ACCOUNTS;
public static final String BUNDLES = "bundles";
- public static final String BUNDLES_PATH = API_PREFIX + API_VERSION + "/" + BUNDLES;
+ public static final String BUNDLES_PATH = PREFIX + "/" + BUNDLES;
+
+ public static final String SUBSCRIPTIONS = "subscriptions";
+ public static final String SUBSCRIPTIONS_PATH = PREFIX + "/" + SUBSCRIPTIONS;
+
+ public static final String TAG_DEFINITIONS = "tag_definitions";
+ public static final String TAG_DEFINITIONS_PATH = PREFIX + "/" + TAG_DEFINITIONS;
- public static final String SUBSCRIPTIONS = "subscriptions";
- public static final String SUBSCRIPTIONS_PATH = API_PREFIX + API_VERSION + "/" + SUBSCRIPTIONS;
+ public static final String INVOICES = "invoices";
+ public static final String INVOICES_PATH = PREFIX + "/" + INVOICES;
+
+ public static final String TAGS = "tags";
+ public static final String CUSTOM_FIELDS = "custom_fields";
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
index d3bb1a2..e62d48e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -24,6 +24,7 @@ import java.util.UUID;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@@ -102,14 +103,20 @@ public class BundleResource implements BaseJaxrsResource {
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
- public Response createBundle(final BundleJsonNoSubsciptions json) {
+ public Response createBundle(final BundleJsonNoSubsciptions json,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
try {
UUID accountId = UUID.fromString(json.getAccountId());
- final SubscriptionBundle bundle = entitlementApi.createBundleForAccount(accountId, json.getExternalKey(), context.createContext());
+ final SubscriptionBundle bundle = entitlementApi.createBundleForAccount(accountId, json.getExternalKey(),
+ context.createContext(createdBy, reason, comment));
return uriBuilder.buildResponse(BundleResource.class, "getBundle", bundle.getId());
} catch (EntitlementUserApiException e) {
log.info(String.format("Failed to create bundle %s", json), e);
return Response.status(Status.BAD_REQUEST).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index e5a1c97..27b7817 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -18,8 +18,14 @@ package com.ning.billing.jaxrs.resources;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@@ -29,34 +35,109 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.jaxrs.json.InvoiceJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+@Path(BaseJaxrsResource.INVOICES_PATH)
+public class InvoiceResource implements BaseJaxrsResource {
-@Path("/1.0/invoice")
-public class InvoiceResource {
+ private static final Logger log = LoggerFactory.getLogger(AccountResource.class);
+ private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTime();
+
+ private final AccountUserApi accountApi;
+ private final InvoiceUserApi invoiceApi;
+ private final Context context;
+ private final JaxrsUriBuilder uriBuilder;
+
+ @Inject
+ public InvoiceResource(final AccountUserApi accountApi,
+ final InvoiceUserApi invoiceApi,
+ final Context context,
+ final JaxrsUriBuilder uriBuilder) {
+ this.accountApi = accountApi;
+ this.invoiceApi = invoiceApi;
+ this.context = context;
+ this.uriBuilder = uriBuilder;
+ }
+
@GET
@Produces(APPLICATION_JSON)
- public Response getInvoices(@QueryParam("accountId") String accountId) {
- return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ public Response getInvoices(@QueryParam(QUERY_ACCOUNT_ID) final String accountId) {
+ try {
+
+ Preconditions.checkNotNull(accountId, "% query parameter must be specified", QUERY_ACCOUNT_ID);
+ accountApi.getAccountById(UUID.fromString(accountId));
+ List<Invoice> invoices = invoiceApi.getInvoicesByAccount(UUID.fromString(accountId));
+ List<InvoiceJson> result = new LinkedList<InvoiceJson>();
+ for (Invoice cur : invoices) {
+ result.add(new InvoiceJson(cur));
+ }
+ return Response.status(Status.OK).entity(result).build();
+ } catch (AccountApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (NullPointerException e) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
@GET
@Path("/{invoiceId:\\w+-\\w+-\\w+-\\w+-\\w+}")
@Produces(APPLICATION_JSON)
- public Response getInvoice(@PathParam("invoiceId") String accountId) {
- return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ public Response getInvoice(@PathParam("invoiceId") String invoiceId) {
+ Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId));
+ InvoiceJson json = new InvoiceJson(invoice);
+ return Response.status(Status.OK).entity(json).build();
}
@POST
- @Path("/{accountId:\\w+-\\w+-\\w+-\\w+-\\w+}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
- public Response createFutureInvoice(InvoiceJson invoice,
- @PathParam("accountId") String accountId,
- @QueryParam("targetDate") String targetDate) {
- return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ public Response createFutureInvoice(final InvoiceJson invoice,
+ @QueryParam(QUERY_ACCOUNT_ID) final String accountId,
+ @QueryParam(QUERY_TARGET_DATE) final String targetDate,
+ @QueryParam(QUERY_DRY_RUN) @DefaultValue("false") final Boolean dryRun,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+
+ try {
+
+ Preconditions.checkNotNull(accountId, "% needs to be specified", QUERY_ACCOUNT_ID);
+ Preconditions.checkNotNull(targetDate, "% needs to be specified", QUERY_TARGET_DATE);
+
+ DateTime inputDate = (targetDate != null) ? DATE_TIME_FORMATTER.parseDateTime(targetDate) : null;
+
+ accountApi.getAccountById(UUID.fromString(accountId));
+ Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRun.booleanValue(),
+ context.createContext(createdBy, reason, comment));
+ if (dryRun) {
+ return Response.status(Status.OK).entity(new InvoiceJson(generatedInvoice)).build();
+ } else {
+ return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", generatedInvoice.getId());
+ }
+ } catch (AccountApiException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (InvoiceApiException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (NullPointerException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).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 09db7f9..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
@@ -26,6 +26,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
@@ -74,8 +75,6 @@ public class SubscriptionResource implements BaseJaxrsResource {
private final JaxrsUriBuilder uriBuilder;
private final KillbillEventHandler killbillHandler;
-
-
@Inject
public SubscriptionResource(final JaxrsUriBuilder uriBuilder, final EntitlementUserApi entitlementApi,
final Clock clock, final Context context, final KillbillEventHandler killbillHandler) {
@@ -93,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) {
@@ -102,50 +100,20 @@ public class SubscriptionResource implements BaseJaxrsResource {
} else {
throw e;
}
-
}
}
-
- /*
- @GET
- @Path("/{subscriptionId:" + UUID_PATTERN + "}")
- @Produces(APPLICATION_JSON)
- public StreamingOutput getSubscription(@PathParam("subscriptionId") final String subscriptionId) {
-
- UUID uuid = UUID.fromString(subscriptionId);
- final Subscription subscription = entitlementApi.getSubscriptionFromId(uuid);
- if (subscription == null) {
- throw new WebApplicationException(Response.Status.NO_CONTENT);
- }
- final SubscriptionJson json = new SubscriptionJson(subscription, null, null, null);
- return new StreamingOutput() {
-
- final SubscriptionJson json = new SubscriptionJson(subscription, null, null, null);
-
- @Override
- public void write(OutputStream output) throws IOException,
- WebApplicationException {
-
- final ObjectWriter objWriter = objectMapper.writerWithView(BundleTimelineViews.Base.class);
-
- Writer writer = new StringWriter();
- objWriter.writeValue(writer, json);
- String baseJson = writer.toString();
- output.write(baseJson.getBytes());
- output.flush();
- }
- };
- }
- */
-
+
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response createSubscription(final SubscriptionJsonNoEvents subscription,
- final @QueryParam(QUERY_REQUESTED_DT) String requestedDate,
- final @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") Boolean callCompletion,
- final @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") long timeoutSec) {
+ @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+ @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+ @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
SubscriptionCallCompletionCallback<Subscription> callback = new SubscriptionCallCompletionCallback<Subscription>() {
@@ -170,7 +138,7 @@ public class SubscriptionResource implements BaseJaxrsResource {
}
};
SubscriptionCallCompletion<Subscription> callCompletionCreation = new SubscriptionCallCompletion<Subscription>();
- return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion);
+ return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, createdBy, reason, comment);
}
@PUT
@@ -178,10 +146,13 @@ public class SubscriptionResource implements BaseJaxrsResource {
@Consumes(APPLICATION_JSON)
@Path("/{subscriptionId:" + UUID_PATTERN + "}")
public Response changeSubscriptionPlan(final SubscriptionJsonNoEvents subscription,
- final @PathParam("subscriptionId") String subscriptionId,
- final @QueryParam(QUERY_REQUESTED_DT) String requestedDate,
- final @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") Boolean callCompletion,
- final @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") long timeoutSec) {
+ @PathParam("subscriptionId") final String subscriptionId,
+ @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+ @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+ @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
SubscriptionCallCompletionCallback<Response> callback = new SubscriptionCallCompletionCallback<Response>() {
@@ -212,34 +183,35 @@ 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();
}
-
}
}
};
SubscriptionCallCompletion<Response> callCompletionCreation = new SubscriptionCallCompletion<Response>();
- return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion);
+ return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, createdBy, reason, comment);
}
@PUT
@Path("/{subscriptionId:" + UUID_PATTERN + "}/uncancel")
@Produces(APPLICATION_JSON)
- public Response uncancelSubscriptionPlan(@PathParam("subscriptionId") String subscriptionId) {
+ public Response uncancelSubscriptionPlan(@PathParam("subscriptionId") final String subscriptionId,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
try {
UUID uuid = UUID.fromString(subscriptionId);
Subscription current = entitlementApi.getSubscriptionFromId(uuid);
- current.uncancel(context.createContext());
+ current.uncancel(context.createContext(createdBy, reason, comment));
return Response.status(Status.OK).build();
} catch (EntitlementUserApiException e) {
if(e.getCode() == ErrorCode.ENT_INVALID_SUBSCRIPTION_ID.getCode()) {
- log.info(String.format("Failed to find subscription %s", subscriptionId), e);
return Response.status(Status.NO_CONTENT).build();
} else {
log.info(String.format("Failed to uncancel plan for subscription %s", subscriptionId), e);
@@ -252,9 +224,12 @@ public class SubscriptionResource implements BaseJaxrsResource {
@Path("/{subscriptionId:" + UUID_PATTERN + "}")
@Produces(APPLICATION_JSON)
public Response cancelSubscriptionPlan(final @PathParam("subscriptionId") String subscriptionId,
- final @QueryParam(QUERY_REQUESTED_DT) String requestedDate,
- final @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") Boolean callCompletion,
- final @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") long timeoutSec) {
+ @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+ @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+ @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
SubscriptionCallCompletionCallback<Response> callback = new SubscriptionCallCompletionCallback<Response>() {
@@ -274,7 +249,6 @@ public class SubscriptionResource implements BaseJaxrsResource {
return Response.status(Status.OK).build();
} catch (EntitlementUserApiException e) {
if(e.getCode() == ErrorCode.ENT_INVALID_SUBSCRIPTION_ID.getCode()) {
- log.info(String.format("Failed to find subscription %s", subscriptionId), e);
return Response.status(Status.NO_CONTENT).build();
} else {
throw e;
@@ -291,7 +265,7 @@ public class SubscriptionResource implements BaseJaxrsResource {
}
};
SubscriptionCallCompletion<Response> callCompletionCreation = new SubscriptionCallCompletion<Response>();
- return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion);
+ return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, createdBy, reason, comment);
}
private final static class CompletionUserRequestSubscription extends CompletionUserRequestBase {
@@ -336,9 +310,14 @@ public class SubscriptionResource implements BaseJaxrsResource {
private class SubscriptionCallCompletion<T> {
- public Response withSynchronization(final SubscriptionCallCompletionCallback<T> callback, final long timeoutSec, final boolean callCompletion) {
+ public Response withSynchronization(final SubscriptionCallCompletionCallback<T> callback,
+ final long timeoutSec,
+ final boolean callCompletion,
+ final String createdBy,
+ final String reason,
+ final String comment) {
- CallContext ctx = context.createContext();
+ CallContext ctx = context.createContext(createdBy, reason, comment);
CompletionUserRequestSubscription waiter = callCompletion ? new CompletionUserRequestSubscription(ctx.getUserToken()) : null;
try {
if (waiter != null) {
@@ -351,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/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java
index cc19095..3111240 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java
@@ -16,6 +16,104 @@
package com.ning.billing.jaxrs.resources;
-public class TagResource {
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.ning.billing.jaxrs.json.TagDefinitionJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+import com.ning.billing.util.api.TagDefinitionApiException;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.tag.TagDefinition;
+
+@Singleton
+@Path(BaseJaxrsResource.TAG_DEFINITIONS_PATH)
+public class TagResource implements BaseJaxrsResource {
+
+ private final TagUserApi tagUserApi;
+ private final Context context;
+ private final JaxrsUriBuilder uriBuilder;
+
+ @Inject
+ public TagResource(TagUserApi tagUserApi, final JaxrsUriBuilder uriBuilder, final Context context) {
+ this.tagUserApi = tagUserApi;
+ this.context = context;
+ this.uriBuilder = uriBuilder;
+ }
+
+ @GET
+ @Produces(APPLICATION_JSON)
+ public Response getTagDefinitions() {
+
+ List<TagDefinitionJson> result = new LinkedList<TagDefinitionJson>();
+ List<TagDefinition> tagDefinitions = tagUserApi.getTagDefinitions();
+ for (TagDefinition cur : tagDefinitions) {
+ result.add(new TagDefinitionJson(cur.getName(), cur.getDescription()));
+ }
+ return Response.status(Status.OK).entity(result).build();
+ }
+
+ @GET
+ @Path("/{tagDefinitionName:" + STRING_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getTagDefinition(@PathParam("tagDefinitionName") final String tagDefName) {
+ try {
+ TagDefinition tagDef = tagUserApi.getTagDefinition(tagDefName);
+ TagDefinitionJson json = new TagDefinitionJson(tagDef.getName(), tagDef.getDescription());
+ return Response.status(Status.OK).entity(json).build();
+ } catch (TagDefinitionApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ }
+ }
+
+
+
+ @POST
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createTagDefinition(final TagDefinitionJson json,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+ try {
+ TagDefinition createdTagDef = tagUserApi.create(json.getName(), json.getDescription(), context.createContext(createdBy, reason, comment));
+ return uriBuilder.buildResponse(TagResource.class, "getTagDefinition", createdTagDef.getName());
+ } catch (TagDefinitionApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
+
+ @DELETE
+ @Path("/{tagDefinitionName:" + STRING_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response deleteTagDefinition(@PathParam("tagDefinitionName") String tagDefName,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+ try {
+ tagUserApi.deleteTagDefinition(tagDefName, context.createContext(createdBy, reason, comment));
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (TagDefinitionApiException e) {
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
index 004a468..729f166 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
@@ -17,7 +17,9 @@ package com.ning.billing.jaxrs.util;
import java.util.UUID;
+import com.google.common.base.Preconditions;
import com.google.inject.Inject;
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.CallOrigin;
@@ -37,8 +39,13 @@ public class Context {
this.contextFactory = factory;
}
- // Simplistic until we decide how to populate that
- public CallContext createContext() {
- return contextFactory.createCallContext("Unknown", origin, userType, UUID.randomUUID());
+ public CallContext createContext(final String createdBy, final String reason, final String comment)
+ throws IllegalArgumentException {
+ try {
+ Preconditions.checkNotNull(createdBy, String.format("Header %s needs to be set", BaseJaxrsResource.HDR_CREATED_BY));
+ return contextFactory.createCallContext(createdBy, origin, userType, UUID.randomUUID());
+ } catch (NullPointerException e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
index a38a9fe..b351b4c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -26,7 +26,7 @@ import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
public class JaxrsUriBuilder {
- public Response buildResponse(final Class<? extends BaseJaxrsResource> theClass, final String getMethodName, final UUID objectId) {
+ public Response buildResponse(final Class<? extends BaseJaxrsResource> theClass, final String getMethodName, final Object objectId) {
URI uri = UriBuilder.fromPath(objectId.toString()).build();
Response.ResponseBuilder ri = Response.created(uri);
return ri.entity(new Object() {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/TagHelper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/TagHelper.java
new file mode 100644
index 0000000..e965deb
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/TagHelper.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.jaxrs.util;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.util.api.TagDefinitionApiException;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.tag.TagDefinition;
+
+public class TagHelper {
+
+ private final TagUserApi tagUserApi;
+
+ @Inject
+ public TagHelper(final TagUserApi tagUserApi) {
+ this.tagUserApi = tagUserApi;
+ }
+
+ public List<TagDefinition> getTagDifinitionFromTagList(final String tagList) throws TagDefinitionApiException {
+ List<TagDefinition> result = new LinkedList<TagDefinition>();
+ String [] tagParts = tagList.split(",\\s*");
+ for (String cur : tagParts) {
+ TagDefinition curDef = tagUserApi.getTagDefinition(cur);
+ // Yack should throw excption
+ if (curDef == null) {
+ throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_DOES_NOT_EXIST, cur);
+ }
+ result.add(curDef);
+ }
+ return result;
+ }
+}
diff --git a/jaxrs/src/main/resources/.dont-let-git-remove-this-directory b/jaxrs/src/main/resources/.dont-let-git-remove-this-directory
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/jaxrs/src/main/resources/.dont-let-git-remove-this-directory
junction/pom.xml 14(+2 -12)
diff --git a/junction/pom.xml b/junction/pom.xml
index a33d843..0375b37 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -55,6 +55,7 @@
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
+ <!-- TEST SCOPE -->
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-util</artifactId>
@@ -72,18 +73,7 @@
<artifactId>killbill-catalog</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-entitlement</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-entitlement</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
+ <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
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 d2c06b9..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();
@@ -84,7 +86,8 @@ public class BillCycleDayCalculator {
break;
case BUNDLE :
Subscription baseSub = entitlementApi.getBaseSubscription(bundle.getId());
- result = calculateBcdFromSubscription(baseSub, plan, account);
+ Plan basePlan = baseSub.getCurrentPlan();
+ result = calculateBcdFromSubscription(baseSub, basePlan, account);
break;
case SUBSCRIPTION :
result = calculateBcdFromSubscription(subscription, plan, account);
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..8f88049 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
@@ -22,11 +22,11 @@ import java.util.TreeSet;
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;
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 +35,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 +109,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);
- }
-
}
diff --git a/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java b/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java
index 1d814b8..db1d1e0 100644
--- a/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java
@@ -27,12 +27,10 @@ import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.BeforeTest;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import com.google.inject.Inject;
-import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.junction.MockModule;
diff --git a/junction/src/test/java/com/ning/billing/junction/MockModule.java b/junction/src/test/java/com/ning/billing/junction/MockModule.java
index 5651c8b..23e18d7 100644
--- a/junction/src/test/java/com/ning/billing/junction/MockModule.java
+++ b/junction/src/test/java/com/ning/billing/junction/MockModule.java
@@ -16,24 +16,14 @@
package com.ning.billing.junction;
-import org.skife.config.ConfigurationObjectFactory;
-import org.skife.jdbi.v2.IDBI;
-
import com.ning.billing.catalog.glue.CatalogModule;
-import com.ning.billing.dbi.DBIProvider;
-import com.ning.billing.dbi.DbiConfig;
-import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.junction.glue.JunctionModule;
+import com.ning.billing.junction.glue.DefaultJunctionModule;
import com.ning.billing.mock.glue.MockDbHelperModule;
-import com.ning.billing.util.callcontext.CallContextFactory;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.clock.MockClockModule;
import com.ning.billing.util.glue.CallContextModule;
-public class MockModule extends JunctionModule {
+public class MockModule extends DefaultJunctionModule {
public static final String PLUGIN_NAME = "Booboo";
@Override
@@ -47,12 +37,12 @@ public class MockModule extends JunctionModule {
}
@Override
- protected void installBillingApi() {
+ public void installBillingApi() {
// no billinggApi
}
@Override
- protected void installAccountUserApi() {
+ public void installAccountUserApi() {
}
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
new file mode 100644
index 0000000..8c85596
--- /dev/null
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
@@ -0,0 +1,202 @@
+/*
+ * 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.junction.plumbing.billing;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.ning.billing.util.dao.ObjectType;
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionEvent;
+import com.ning.billing.junction.api.BlockingState;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
+
+
+public class MockSubscription implements Subscription {
+ Subscription sub = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+
+ public List<Tag> getTagList() {
+ return sub.getTagList();
+ }
+
+ public UUID getId() {
+ return sub.getId();
+ }
+
+ public boolean hasTag(TagDefinition tagDefinition) {
+ return sub.hasTag(tagDefinition);
+ }
+
+ public String getFieldValue(String fieldName) {
+ return sub.getFieldValue(fieldName);
+ }
+
+ public boolean hasTag(ControlTagType controlTagType) {
+ return sub.hasTag(controlTagType);
+ }
+
+ public void setFieldValue(String fieldName, String fieldValue) {
+ sub.setFieldValue(fieldName, fieldValue);
+ }
+
+ public void addTag(TagDefinition definition) {
+ sub.addTag(definition);
+ }
+
+ public void addTags(List<Tag> tags) {
+ sub.addTags(tags);
+ }
+
+ public void saveFieldValue(String fieldName, String fieldValue, CallContext context) {
+ sub.saveFieldValue(fieldName, fieldValue, context);
+ }
+
+ public void addTagsFromDefinitions(List<TagDefinition> tagDefinitions) {
+ sub.addTagsFromDefinitions(tagDefinitions);
+ }
+
+ public List<CustomField> getFieldList() {
+ return sub.getFieldList();
+ }
+
+ public void clearTags() {
+ sub.clearTags();
+ }
+
+ public void setFields(List<CustomField> fields) {
+ sub.setFields(fields);
+ }
+
+ public void removeTag(TagDefinition definition) {
+ sub.removeTag(definition);
+ }
+
+ public void saveFields(List<CustomField> fields, CallContext context) {
+ sub.saveFields(fields, context);
+ }
+
+ public boolean generateInvoice() {
+ return sub.generateInvoice();
+ }
+
+ public boolean processPayment() {
+ return sub.processPayment();
+ }
+
+ public void clearFields() {
+ sub.clearFields();
+ }
+
+ public void clearPersistedFields(CallContext context) {
+ sub.clearPersistedFields(context);
+ }
+
+ @Override
+ public ObjectType getObjectType() {
+ return sub.getObjectType();
+ }
+
+ public boolean cancel(DateTime requestedDate, boolean eot, CallContext context) throws EntitlementUserApiException {
+ return sub.cancel(requestedDate, eot, context);
+ }
+
+ public boolean uncancel(CallContext context) throws EntitlementUserApiException {
+ return sub.uncancel(context);
+ }
+
+ public boolean changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate,
+ CallContext context) throws EntitlementUserApiException {
+ return sub.changePlan(productName, term, planSet, requestedDate, context);
+ }
+
+ public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
+ throws EntitlementUserApiException {
+ return sub.recreate(spec, requestedDate, context);
+ }
+
+ public UUID getBundleId() {
+ return sub.getBundleId();
+ }
+
+ public SubscriptionState getState() {
+ return sub.getState();
+ }
+
+ public DateTime getStartDate() {
+ return sub.getStartDate();
+ }
+
+ public DateTime getEndDate() {
+ return sub.getEndDate();
+ }
+
+ public Plan getCurrentPlan() {
+ return sub.getCurrentPlan();
+ }
+
+ public BlockingState getBlockingState() {
+ return sub.getBlockingState();
+ }
+
+ public PriceList getCurrentPriceList() {
+ return sub.getCurrentPriceList();
+ }
+
+ public PlanPhase getCurrentPhase() {
+ return sub.getCurrentPhase();
+ }
+
+ public DateTime getChargedThroughDate() {
+ return sub.getChargedThroughDate();
+ }
+
+ public DateTime getPaidThroughDate() {
+ return sub.getPaidThroughDate();
+ }
+
+ public ProductCategory getCategory() {
+ return sub.getCategory();
+ }
+
+ public SubscriptionEvent getPendingTransition() {
+ return sub.getPendingTransition();
+ }
+
+ public SubscriptionEvent getPreviousTransition() {
+ return sub.getPreviousTransition();
+ }
+
+ public List<SubscriptionEvent> getBillingTransitions() {
+ return sub.getBillingTransitions();
+ }
+
+
+}
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscriptionEvent.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscriptionEvent.java
new file mode 100644
index 0000000..cbba255
--- /dev/null
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscriptionEvent.java
@@ -0,0 +1,333 @@
+/*
+ * 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.junction.plumbing.billing;
+
+import java.util.UUID;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+import com.ning.billing.entitlement.api.user.SubscriptionEvent;
+import com.ning.billing.util.bus.BusEvent.BusEventType;
+
+public class MockSubscriptionEvent implements SubscriptionEvent {
+
+ private final Long totalOrdering;
+ private final UUID subscriptionId;
+ private final UUID bundleId;
+ private final UUID eventId;
+ private final DateTime requestedTransitionTime;
+ private final DateTime effectiveTransitionTime;
+ private final SubscriptionState previousState;
+ private final String previousPriceList;
+ private final String previousPlan;
+ private final String previousPhase;
+ private final SubscriptionState nextState;
+ private final String nextPriceList;
+ private final String nextPlan;
+ private final String nextPhase;
+ private final Integer remainingEventsForUserOperation;
+ private final UUID userToken;
+ private final SubscriptionTransitionType transitionType;
+
+ private final DateTime startDate;
+
+ @JsonCreator
+ public MockSubscriptionEvent(@JsonProperty("eventId") UUID eventId,
+ @JsonProperty("subscriptionId") UUID subscriptionId,
+ @JsonProperty("bundleId") UUID bundleId,
+ @JsonProperty("requestedTransitionTime") DateTime requestedTransitionTime,
+ @JsonProperty("effectiveTransitionTime") DateTime effectiveTransitionTime,
+ @JsonProperty("previousState") SubscriptionState previousState,
+ @JsonProperty("previousPlan") String previousPlan,
+ @JsonProperty("previousPhase") String previousPhase,
+ @JsonProperty("previousPriceList") String previousPriceList,
+ @JsonProperty("nextState") SubscriptionState nextState,
+ @JsonProperty("nextPlan") String nextPlan,
+ @JsonProperty("nextPhase") String nextPhase,
+ @JsonProperty("nextPriceList") String nextPriceList,
+ @JsonProperty("totalOrdering") Long totalOrdering,
+ @JsonProperty("userToken") UUID userToken,
+ @JsonProperty("transitionType") SubscriptionTransitionType transitionType,
+ @JsonProperty("remainingEventsForUserOperation") Integer remainingEventsForUserOperation,
+ @JsonProperty("startDate") DateTime startDate) {
+ super();
+ this.eventId = eventId;
+ this.subscriptionId = subscriptionId;
+ this.bundleId = bundleId;
+ this.requestedTransitionTime = requestedTransitionTime;
+ this.effectiveTransitionTime = effectiveTransitionTime;
+ this.previousState = previousState;
+ this.previousPriceList = previousPriceList;
+ this.previousPlan = previousPlan;
+ this.previousPhase = previousPhase;
+ this.nextState = nextState;
+ this.nextPlan = nextPlan;
+ this.nextPriceList = nextPriceList;
+ this.nextPhase = nextPhase;
+ this.totalOrdering = totalOrdering;
+ this.userToken = userToken;
+ this.transitionType = transitionType;
+ this.remainingEventsForUserOperation = remainingEventsForUserOperation;
+ this.startDate = startDate;
+ }
+
+ @JsonIgnore
+ @Override
+ public BusEventType getBusEventType() {
+ return BusEventType.SUBSCRIPTION_TRANSITION;
+ }
+
+ @JsonProperty("eventId")
+ @Override
+ public UUID getId() {
+ return eventId;
+ }
+
+ @Override
+ public UUID getSubscriptionId() {
+ return subscriptionId;
+ }
+
+ @Override
+ public UUID getBundleId() {
+ return bundleId;
+ }
+
+
+ @Override
+ public SubscriptionState getPreviousState() {
+ return previousState;
+ }
+
+ @Override
+ public String getPreviousPlan() {
+ return previousPlan;
+ }
+
+ @Override
+ public String getPreviousPhase() {
+ return previousPhase;
+ }
+
+ @Override
+ public String getNextPlan() {
+ return nextPlan;
+ }
+
+ @Override
+ public String getNextPhase() {
+ return nextPhase;
+ }
+
+ @Override
+ public SubscriptionState getNextState() {
+ return nextState;
+ }
+
+
+ @Override
+ public String getPreviousPriceList() {
+ return previousPriceList;
+ }
+
+ @Override
+ public String getNextPriceList() {
+ return nextPriceList;
+ }
+
+ @Override
+ public UUID getUserToken() {
+ return userToken;
+ }
+
+ @Override
+ public Integer getRemainingEventsForUserOperation() {
+ return remainingEventsForUserOperation;
+ }
+
+
+ @Override
+ public DateTime getRequestedTransitionTime() {
+ return requestedTransitionTime;
+ }
+
+ @Override
+ public DateTime getEffectiveTransitionTime() {
+ return effectiveTransitionTime;
+ }
+
+ @Override
+ public Long getTotalOrdering() {
+ return totalOrdering;
+ }
+
+ @Override
+ public SubscriptionTransitionType getTransitionType() {
+ return transitionType;
+ }
+
+ @JsonProperty("startDate")
+ @Override
+ public DateTime getSubscriptionStartDate() {
+ return startDate;
+ }
+
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((bundleId == null) ? 0 : bundleId.hashCode());
+ result = prime
+ * result
+ + ((effectiveTransitionTime == null) ? 0
+ : effectiveTransitionTime.hashCode());
+ result = prime * result + ((eventId == null) ? 0 : eventId.hashCode());
+ result = prime * result
+ + ((nextPhase == null) ? 0 : nextPhase.hashCode());
+ result = prime * result
+ + ((nextPlan == null) ? 0 : nextPlan.hashCode());
+ result = prime * result
+ + ((nextPriceList == null) ? 0 : nextPriceList.hashCode());
+ result = prime * result
+ + ((nextState == null) ? 0 : nextState.hashCode());
+ result = prime * result
+ + ((previousPhase == null) ? 0 : previousPhase.hashCode());
+ result = prime * result
+ + ((previousPlan == null) ? 0 : previousPlan.hashCode());
+ result = prime
+ * result
+ + ((previousPriceList == null) ? 0 : previousPriceList
+ .hashCode());
+ result = prime * result
+ + ((previousState == null) ? 0 : previousState.hashCode());
+ result = prime
+ * result
+ + ((remainingEventsForUserOperation == null) ? 0
+ : remainingEventsForUserOperation.hashCode());
+ result = prime
+ * result
+ + ((requestedTransitionTime == null) ? 0
+ : requestedTransitionTime.hashCode());
+ result = prime * result
+ + ((subscriptionId == null) ? 0 : subscriptionId.hashCode());
+ result = prime * result
+ + ((totalOrdering == null) ? 0 : totalOrdering.hashCode());
+ result = prime * result
+ + ((transitionType == null) ? 0 : transitionType.hashCode());
+ result = prime * result
+ + ((userToken == null) ? 0 : userToken.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ MockSubscriptionEvent other = (MockSubscriptionEvent) obj;
+ if (bundleId == null) {
+ if (other.bundleId != null)
+ return false;
+ } else if (!bundleId.equals(other.bundleId))
+ return false;
+ if (effectiveTransitionTime == null) {
+ if (other.effectiveTransitionTime != null)
+ return false;
+ } else if (effectiveTransitionTime
+ .compareTo(other.effectiveTransitionTime) != 0)
+ return false;
+ if (eventId == null) {
+ if (other.eventId != null)
+ return false;
+ } else if (!eventId.equals(other.eventId))
+ return false;
+ if (nextPhase == null) {
+ if (other.nextPhase != null)
+ return false;
+ } else if (!nextPhase.equals(other.nextPhase))
+ return false;
+ if (nextPlan == null) {
+ if (other.nextPlan != null)
+ return false;
+ } else if (!nextPlan.equals(other.nextPlan))
+ return false;
+ if (nextPriceList == null) {
+ if (other.nextPriceList != null)
+ return false;
+ } else if (!nextPriceList.equals(other.nextPriceList))
+ return false;
+ if (nextState != other.nextState)
+ return false;
+ if (previousPhase == null) {
+ if (other.previousPhase != null)
+ return false;
+ } else if (!previousPhase.equals(other.previousPhase))
+ return false;
+ if (previousPlan == null) {
+ if (other.previousPlan != null)
+ return false;
+ } else if (!previousPlan.equals(other.previousPlan))
+ return false;
+ if (previousPriceList == null) {
+ if (other.previousPriceList != null)
+ return false;
+ } else if (!previousPriceList.equals(other.previousPriceList))
+ return false;
+ if (previousState != other.previousState)
+ return false;
+ if (remainingEventsForUserOperation == null) {
+ if (other.remainingEventsForUserOperation != null)
+ return false;
+ } else if (!remainingEventsForUserOperation
+ .equals(other.remainingEventsForUserOperation))
+ return false;
+ if (requestedTransitionTime == null) {
+ if (other.requestedTransitionTime != null)
+ return false;
+ } else if (requestedTransitionTime
+ .compareTo(other.requestedTransitionTime) != 0)
+ return false;
+ if (subscriptionId == null) {
+ if (other.subscriptionId != null)
+ return false;
+ } else if (!subscriptionId.equals(other.subscriptionId))
+ return false;
+ if (totalOrdering == null) {
+ if (other.totalOrdering != null)
+ return false;
+ } else if (!totalOrdering.equals(other.totalOrdering))
+ return false;
+ if (transitionType != other.transitionType)
+ return false;
+ if (userToken == null) {
+ if (other.userToken != null)
+ return false;
+ } else if (!userToken.equals(other.userToken))
+ return false;
+ return true;
+ }
+
+}
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java
index c30e906..0d0d14b 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java
@@ -51,22 +51,14 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Price;
import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.BillingModeType;
-import com.ning.billing.entitlement.api.user.DefaultSubscriptionEvent;
-
-import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
-import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.entitlement.api.user.SubscriptionEvent;
-
-import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
-import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
-import com.ning.billing.entitlement.events.user.ApiEventType;
import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.junction.api.Blockable;
import com.ning.billing.junction.api.Blockable.Type;
@@ -147,6 +139,7 @@ public class TestDefaultEntitlementBillingApi {
private Clock clock;
private Subscription subscription;
private DateTime subscriptionStartDate;
+ private Plan subscriptionPlan;
@BeforeSuite(groups={"fast", "slow"})
public void setup() throws ServiceException {
@@ -157,21 +150,44 @@ public class TestDefaultEntitlementBillingApi {
@BeforeMethod(groups={"fast", "slow"})
public void setupEveryTime() {
bundles = new ArrayList<SubscriptionBundle>();
- final SubscriptionBundle bundle = new SubscriptionBundleData( eventId,"TestKey", subId, clock.getUTCNow().minusDays(4), null);
+ final SubscriptionBundle bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+ ((ZombieControl)bundle).addResult("getId", eventId);
+
+ //new SubscriptionBundleData( eventId,"TestKey", subId, clock.getUTCNow().minusDays(4), null);
bundles.add(bundle);
subscriptionTransitions = new LinkedList<SubscriptionEvent>();
subscriptions = new LinkedList<Subscription>();
- SubscriptionBuilder builder = new SubscriptionBuilder();
subscriptionStartDate = clock.getUTCNow().minusDays(3);
- builder.setStartDate(subscriptionStartDate).setId(subId).setBundleId(bunId);
- subscription = new SubscriptionData(builder) {
+ subscription = new MockSubscription() {
@Override
public List<SubscriptionEvent> getBillingTransitions() {
return subscriptionTransitions;
}
+
+ @Override
+ public Plan getCurrentPlan() {
+ return subscriptionPlan;
+ }
+
+ @Override
+ public UUID getId() {
+ return subId;
+ }
+
+ @Override
+ public UUID getBundleId() {
+ return bunId;
+ }
+
+ @Override
+ public DateTime getStartDate() {
+ return subscriptionStartDate;
+ }
+
+
};
subscriptions.add(subscription);
@@ -212,9 +228,12 @@ public class TestDefaultEntitlementBillingApi {
PlanPhase nextPhase = nextPlan.getAllPhases()[0]; // The trial has no billing period
PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
- SubscriptionEvent t = new DefaultSubscriptionEvent(new SubscriptionTransitionData(
- eventId, subId, bunId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null,
- SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1L, null, true), then);
+ SubscriptionEvent t = new MockSubscriptionEvent(
+ eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
+ nextPlan.getName(), nextPhase.getName(),
+ nextPriceList.getName(), 1L,null,
+ SubscriptionTransitionType.CREATE, 0, null);
+
subscriptionTransitions.add(t);
AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -228,7 +247,7 @@ public class TestDefaultEntitlementBillingApi {
BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService);
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
- checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, ApiEventType.CREATE.toString());
+ checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
}
@Test(enabled=false, groups="fast")
@@ -238,9 +257,12 @@ public class TestDefaultEntitlementBillingApi {
Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
PlanPhase nextPhase = nextPlan.getAllPhases()[1];
PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
- SubscriptionEvent t = new DefaultSubscriptionEvent(new SubscriptionTransitionData(
- eventId, subId, bunId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE,
- nextPlan, nextPhase, nextPriceList, 1L, null, true), then);
+ SubscriptionEvent t = new MockSubscriptionEvent(
+ eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
+ nextPlan.getName(), nextPhase.getName(),
+ nextPriceList.getName(), 1L,null,
+ SubscriptionTransitionType.CREATE, 0, null);
+
subscriptionTransitions.add(t);
Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
@@ -258,7 +280,7 @@ public class TestDefaultEntitlementBillingApi {
BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService);
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
- checkFirstEvent(events, nextPlan, subscription.getStartDate().getDayOfMonth(), subId, now, nextPhase, ApiEventType.CREATE.toString());
+ checkFirstEvent(events, nextPlan, subscription.getStartDate().plusDays(30).getDayOfMonth(), subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
}
@Test(enabled=true, groups="fast")
@@ -269,9 +291,13 @@ public class TestDefaultEntitlementBillingApi {
PlanPhase nextPhase = nextPlan.getAllPhases()[1];
PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
- SubscriptionEvent t = new DefaultSubscriptionEvent(new SubscriptionTransitionData(
- eventId, subId, bunId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList,
- 1L, null, true), then);
+ SubscriptionEvent t = new MockSubscriptionEvent(
+ eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
+ nextPlan.getName(), nextPhase.getName(),
+ nextPriceList.getName(), 1L,null,
+ SubscriptionTransitionType.CREATE, 0, null);
+
+
subscriptionTransitions.add(t);
AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -288,7 +314,7 @@ public class TestDefaultEntitlementBillingApi {
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
- checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, ApiEventType.CREATE.toString());
+ checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
}
@Test(enabled=false, groups="fast")
@@ -299,9 +325,12 @@ public class TestDefaultEntitlementBillingApi {
PlanPhase nextPhase = nextPlan.getAllPhases()[0];
PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
- SubscriptionEvent t = new DefaultSubscriptionEvent(new SubscriptionTransitionData(
- eventId, subId, bunId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1L,
- null, true), then);
+ SubscriptionEvent t = new MockSubscriptionEvent(
+ eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
+ nextPlan.getName(), nextPhase.getName(),
+ nextPriceList.getName(), 1L,null,
+ SubscriptionTransitionType.CREATE, 0, null);
+
subscriptionTransitions.add(t);
Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
@@ -315,11 +344,13 @@ public class TestDefaultEntitlementBillingApi {
BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
CallContextFactory factory = new DefaultCallContextFactory(clock);
-
+
BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService);
+ subscriptionPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+
SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
- checkFirstEvent(events, nextPlan, subscription.getStartDate().plusDays(30).getDayOfMonth(), subId, now, nextPhase, ApiEventType.CREATE.toString());
+ checkFirstEvent(events, nextPlan, subscription.getStartDate().plusDays(30).getDayOfMonth(), subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
}
@Test(enabled=true, groups="fast")
@@ -329,8 +360,14 @@ public class TestDefaultEntitlementBillingApi {
Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
PlanPhase nextPhase = nextPlan.getAllPhases()[1];
PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
- SubscriptionEvent t = new DefaultSubscriptionEvent(new SubscriptionTransitionData(
- eventId, subId, bunId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1L, null, true), then);
+
+
+ SubscriptionEvent t = new MockSubscriptionEvent(
+ eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
+ nextPlan.getName(), nextPhase.getName(),
+ nextPriceList.getName(), 1L,null,
+ SubscriptionTransitionType.CREATE, 0, null);
+
subscriptionTransitions.add(t);
AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -383,9 +420,9 @@ public class TestDefaultEntitlementBillingApi {
Assert.assertEquals(events.size(), 3);
Iterator<BillingEvent> it = events.iterator();
- checkEvent(it.next(), nextPlan, 32, subId, now, nextPhase, ApiEventType.CREATE.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
- checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(1), nextPhase, ApiEventType.CANCEL.toString(), new MockPrice("0"), new MockPrice("0"));
- checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(2), nextPhase, ApiEventType.RE_CREATE.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
+ checkEvent(it.next(), nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
+ checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(1), nextPhase, SubscriptionTransitionType.CANCEL.toString(), new MockPrice("0"), new MockPrice("0"));
+ checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(2), nextPhase, SubscriptionTransitionType.RE_CREATE.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
}
overdue/pom.xml 21(+1 -20)
diff --git a/overdue/pom.xml b/overdue/pom.xml
index b6f64a0..2182ffc 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -55,19 +55,7 @@
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
- <!-- Check if we need this one -->
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-junction</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-junction</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
+
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-util</artifactId>
@@ -117,13 +105,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 092911d..8a9ea68 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
@@ -22,6 +22,7 @@ import com.google.inject.Inject;
import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.CatalogApiException;
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;
@@ -62,7 +63,7 @@ public class DefaultOverdueUserApi implements OverdueUserApi{
}
@Override
- public <T extends Blockable> OverdueState<T> refreshOverdueStateFor(T overdueable) throws OverdueError, CatalogApiException {
+ public <T extends Blockable> OverdueState<T> refreshOverdueStateFor(T overdueable) throws OverdueError, CatalogApiException, EntitlementUserApiException {
OverdueWrapper<T> wrapper = factory.createOverdueWrapperFor(overdueable);
return wrapper.refresh();
}
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/config/DefaultOverdueState.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
index 7d84e7c..9a448c2 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
@@ -42,12 +42,12 @@ public class DefaultOverdueState<T extends Blockable> extends ValidatingConfig<O
@XmlElement(required=false, name="externalMessage")
private String externalMessage = "";
-
- @XmlElement(required=false, name="disableEntitlementAndChangesBlocked")
- private Boolean disableEntitlement = false;
@XmlElement(required=false, name="blockChanges")
private Boolean blockChanges = false;
+
+ @XmlElement(required=false, name="disableEntitlementAndChangesBlocked")
+ private Boolean disableEntitlement = false;
@XmlElement(required=false, name="daysBetweenPaymentRetries")
private Integer daysBetweenPaymentRetries = 8;
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 892ad05..0223803 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
@@ -17,6 +17,7 @@
package com.ning.billing.overdue.wrapper;
import com.ning.billing.catalog.api.CatalogApiException;
+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.OverdueState;
@@ -48,12 +49,12 @@ public class OverdueWrapper<T extends Blockable> {
this.overdueStateApplicator = overdueStateApplicator;
}
- public OverdueState<T> refresh() throws OverdueError, CatalogApiException {
+ public OverdueState<T> refresh() throws OverdueError, CatalogApiException, EntitlementUserApiException {
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())) {
+ if (!previousOverdueStateName.equals(nextOverdueState.getName())) {
overdueStateApplicator.apply(overdueable, nextOverdueState, nextOverdueState, overdueStateSet.dateOfNextCheck(billingState, clock.getUTCNow()));
}
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/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueRules.java b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueRules.java
index 3095296..514c85f 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueRules.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueRules.java
@@ -18,15 +18,15 @@ package com.ning.billing.overdue.config;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.junction.MockBlockingModule;
public class MockOverdueRules extends OverdueConfig {
+ public static final String CLEAR_STATE="Clear";
@SuppressWarnings("unchecked")
public MockOverdueRules() {
OverdueStatesBundle bundleODS = new OverdueStatesBundle();
- bundleODS.setBundleOverdueStates(new DefaultOverdueState[] { new DefaultOverdueState<SubscriptionBundle>().setName(MockBlockingModule.CLEAR_STATE) });
+ bundleODS.setBundleOverdueStates(new DefaultOverdueState[] { new DefaultOverdueState<SubscriptionBundle>().setName(CLEAR_STATE) });
setOverdueStatesBundle(bundleODS);
}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueState.java b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueState.java
index 606556f..d1b9ab1 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueState.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueState.java
@@ -16,13 +16,12 @@
package com.ning.billing.overdue.config;
-import com.ning.billing.junction.MockBlockingModule;
import com.ning.billing.junction.api.Blockable;
public class MockOverdueState<T extends Blockable> extends DefaultOverdueState<T> {
public MockOverdueState() {
- setName(MockBlockingModule.CLEAR_STATE);
+ setName(MockOverdueRules.CLEAR_STATE);
}
public MockOverdueState(String name, boolean blockChanges, boolean disableEntitlementAndBlockChanges) {
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdueConfig.java b/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdueConfig.java
new file mode 100644
index 0000000..df4f4c3
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdueConfig.java
@@ -0,0 +1,60 @@
+/*
+ * 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.overdue.config;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.config.XMLLoader;
+
+public class TestOverdueConfig {
+ private String xml =
+ "<overdueConfig>" +
+ " <bundleOverdueStates>" +
+ " <state name=\"OD1\">" +
+ " <condition>" +
+ " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " <unit>MONTHS</unit><number>1</number>" +
+ " </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " </condition>" +
+ " <externalMessage>Reached OD1</externalMessage>" +
+ " <blockChanges>true</blockChanges>" +
+ " <disableEntitlementAndChangesBlocked>false</disableEntitlementAndChangesBlocked>" +
+ " </state>" +
+ " <state name=\"OD2\">" +
+ " <condition>" +
+ " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " <unit>MONTHS</unit><number>2</number>" +
+ " </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " </condition>" +
+ " <externalMessage>Reached OD1</externalMessage>" +
+ " <blockChanges>true</blockChanges>" +
+ " <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>" +
+ " </state>" +
+ " </bundleOverdueStates>" +
+ "</overdueConfig>";
+
+ @Test
+ public void testParseConfig() throws Exception {
+ InputStream is = new ByteArrayInputStream(xml.getBytes());
+ OverdueConfig c = XMLLoader.getObjectFromStreamNoValidation(is, OverdueConfig.class);
+
+ }
+
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
index 3086274..dca8cb7 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
@@ -38,7 +38,6 @@ import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
-import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.catalog.DefaultCatalogService;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.config.CatalogConfig;
@@ -47,9 +46,7 @@ import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.api.billing.ChargeThruApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.junction.api.Blockable;
-import com.ning.billing.junction.plumbing.billing.DefaultBillingApi;
import com.ning.billing.lifecycle.KillbillService.ServiceException;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
@@ -141,7 +138,7 @@ public class TestOverdueCheckNotifier {
clock = g.getInstance(Clock.class);
IDBI dbi = g.getInstance(IDBI.class);
- dao = dbi.onDemand(DummySqlTest.class);
+
eventBus = g.getInstance(Bus.class);
helper = g.getInstance(MysqlTestingHelper.class);
notificationQueueService = g.getInstance(NotificationQueueService.class);
@@ -161,7 +158,7 @@ public class TestOverdueCheckNotifier {
eventBus.start();
notifier.initialize();
notifier.start();
-
+ dao = dbi.onDemand(DummySqlTest.class);
}
private void startMysql() throws IOException, ClassNotFoundException, SQLException {
payment/pom.xml 28(+11 -17)
diff --git a/payment/pom.xml b/payment/pom.xml
index cb39ebf..e4933be 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -26,19 +26,23 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
- <artifactId>killbill-invoice</artifactId>
+ <artifactId>killbill-util</artifactId>
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
- <artifactId>killbill-account</artifactId>
+ <artifactId>killbill-junction</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
- <artifactId>killbill-util</artifactId>
+ <artifactId>killbill-account</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
- <artifactId>killbill-junction</artifactId>
+ <artifactId>killbill-invoice</artifactId>
+ <type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
@@ -78,12 +82,13 @@
<artifactId>slf4j-api</artifactId>
</dependency>
+ <!-- TEST SCOPE -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
+ <dependency>
<groupId>com.jayway.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
@@ -94,18 +99,7 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-account</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-invoice</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
+
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-mxj</artifactId>
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 552fc3e..46b43e0 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,24 +18,23 @@ 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;
-import javax.annotation.Nullable;
-
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
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;
import com.ning.billing.config.PaymentConfig;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoicePaymentApi;
-import com.ning.billing.invoice.model.DefaultInvoicePayment;
import com.ning.billing.payment.RetryService;
import com.ning.billing.payment.dao.PaymentDao;
import com.ning.billing.payment.provider.PaymentProviderPlugin;
@@ -69,9 +68,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) {
@@ -101,60 +105,87 @@ 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) {
try {
@@ -165,40 +196,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 DefaultPaymentAttempt.Builder(paymentAttempt)
- .setRetryCount(paymentAttempt.getRetryCount() + 1)
- .setPaymentAttemptId(UUID.randomUUID())
- .build();
+ .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 +251,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,
@@ -252,28 +286,29 @@ public class DefaultPaymentApi implements PaymentApi {
if (paymentMethodInfo instanceof CreditCardPaymentMethodInfo) {
CreditCardPaymentMethodInfo ccPaymentMethod = (CreditCardPaymentMethodInfo)paymentMethodInfo;
- paymentDao.updatePaymentInfo(ccPaymentMethod.getType(), paymentInfo.getPaymentId(), ccPaymentMethod.getCardType(), ccPaymentMethod.getCardCountry(), context);
+ paymentDao.updatePaymentInfo(ccPaymentMethod.getType(), paymentInfo.getId(), ccPaymentMethod.getCardType(), ccPaymentMethod.getCardCountry(), context);
}
else if (paymentMethodInfo instanceof PaypalPaymentMethodInfo) {
PaypalPaymentMethodInfo paypalPaymentMethodInfo = (PaypalPaymentMethodInfo)paymentMethodInfo;
- paymentDao.updatePaymentInfo(paypalPaymentMethodInfo.getType(), paymentInfo.getPaymentId(), null, null, context);
+ paymentDao.updatePaymentInfo(paypalPaymentMethodInfo.getType(), paymentInfo.getId(), null, null, context);
}
} else {
log.info(paymentMethodInfoOrError.getLeft().getMessage());
}
- if (paymentInfo.getPaymentId() != null) {
- paymentDao.updatePaymentAttemptWithPaymentId(paymentAttempt.getId(), paymentInfo.getPaymentId(), context);
+ if (paymentInfo.getId() != null) {
+ paymentDao.updatePaymentAttemptWithPaymentId(paymentAttempt.getId(), paymentInfo.getId(), context);
}
}
- invoicePaymentApi.notifyOfPaymentAttempt(new DefaultInvoicePayment(paymentAttempt.getId(),
+ invoicePaymentApi.notifyOfPaymentAttempt(
invoice.getId(),
- paymentAttempt.getPaymentAttemptDate(),
paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : paymentInfo.getAmount(),
// paymentInfo.getRefundAmount(), TODO
- paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency()),
- context);
+ paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
+ paymentAttempt.getId(),
+ paymentAttempt.getPaymentAttemptDate(),
+ context);
return paymentOrError;
}
@@ -310,38 +345,51 @@ 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);
}
}
@Override
- public PaymentAttempt getPaymentAttemptForPaymentId(String id) {
+ public PaymentAttempt getPaymentAttemptForPaymentId(UUID id) {
return paymentDao.getPaymentAttemptForPaymentId(id);
}
@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/api/DefaultPaymentAttempt.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentAttempt.java
index b523af2..681f0ca 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentAttempt.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentAttempt.java
@@ -32,10 +32,12 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
private final UUID accountId;
private final BigDecimal amount;
private final Currency currency;
- private final String paymentId;
+ private final UUID paymentId;
private final DateTime invoiceDate;
private final DateTime paymentAttemptDate;
private final Integer retryCount;
+ private final DateTime createdDate;
+ private final DateTime updatedDate;
public DefaultPaymentAttempt(UUID id,
UUID invoiceId,
@@ -44,8 +46,9 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
Currency currency,
DateTime invoiceDate,
DateTime paymentAttemptDate,
- String paymentId,
- Integer retryCount) {
+ UUID paymentId,
+ Integer retryCount,
+ DateTime createdDate, DateTime updatedDate) {
super(id);
this.invoiceId = invoiceId;
this.accountId = accountId;
@@ -55,18 +58,20 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
this.paymentAttemptDate = paymentAttemptDate == null ? new DateTime(DateTimeZone.UTC) : paymentAttemptDate;
this.paymentId = paymentId;
this.retryCount = retryCount == null ? 0 : retryCount;
+ this.createdDate = createdDate;
+ this.updatedDate = updatedDate;
}
public DefaultPaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, BigDecimal amount, Currency currency, DateTime invoiceDate, DateTime paymentAttemptDate) {
- this(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, null, null);
+ this(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, null, null, null, null);
}
public DefaultPaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, DateTime invoiceDate, DateTime paymentAttemptDate) {
- this(paymentAttemptId, invoiceId, accountId, null, null, invoiceDate, paymentAttemptDate, null, null);
+ this(paymentAttemptId, invoiceId, accountId, null, null, invoiceDate, paymentAttemptDate, null, null, null, null);
}
public DefaultPaymentAttempt(UUID paymentAttemptId, Invoice invoice) {
- this(paymentAttemptId, invoice.getId(), invoice.getAccountId(), invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(), null, null, null);
+ this(paymentAttemptId, invoice.getId(), invoice.getAccountId(), invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(), null, null, null, null, null);
}
@Override public DateTime getInvoiceDate() {
@@ -77,7 +82,7 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
return id;
}
- @Override public String getPaymentId() {
+ @Override public UUID getPaymentId() {
return paymentId;
}
@@ -105,6 +110,14 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
return retryCount;
}
+ @Override public DateTime getCreatedDate() {
+ return createdDate;
+ }
+
+ @Override public DateTime getUpdatedDate() {
+ return updatedDate;
+ }
+
@Override
public String toString() {
return "PaymentAttempt [paymentAttemptId=" + id + ", invoiceId=" + invoiceId + ", accountId=" + accountId + ", amount=" + amount + ", currency=" + currency + ", paymentId=" + paymentId + ", invoiceDate=" + invoiceDate + ", paymentAttemptDate=" + paymentAttemptDate + ", retryCount=" + retryCount + "]";
@@ -124,7 +137,8 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
invoiceDate,
paymentAttemptDate,
paymentId,
- retryCount);
+ retryCount,
+ createdDate, updatedDate);
}
@Override
@@ -144,11 +158,13 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
return false;
if (paymentId != null ? !paymentId.equals(that.getPaymentId()) : that.getPaymentId() != null) return false;
if (retryCount != null ? !retryCount.equals(that.getRetryCount()) : that.getRetryCount() != null) return false;
+ if (createdDate.compareTo(that.getCreatedDate()) != 0) return false;
+ if (updatedDate.compareTo(that.getUpdatedDate()) != 0) return false;
return true;
}
- public static class Builder {
+ public static class Builder {
private UUID id;
private UUID invoiceId;
private UUID accountId;
@@ -156,8 +172,10 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
private Currency currency;
private DateTime invoiceDate;
private DateTime paymentAttemptDate;
- private String paymentId;
+ private UUID paymentId;
private Integer retryCount;
+ private DateTime createdDate;
+ private DateTime updatedDate;
public Builder() {
}
@@ -172,6 +190,8 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
this.paymentAttemptDate = src.getPaymentAttemptDate();
this.paymentId = src.getPaymentId();
this.retryCount = src.getRetryCount();
+ this.createdDate = src.getCreatedDate();
+ this.updatedDate = src.getUpdatedDate();
}
public Builder setPaymentAttemptId(UUID paymentAttemptId) {
@@ -209,7 +229,7 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
return this;
}
- public Builder setPaymentId(String paymentId) {
+ public Builder setPaymentId(UUID paymentId) {
this.paymentId = paymentId;
return this;
}
@@ -219,6 +239,16 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
return this;
}
+ public Builder setCreatedDate(DateTime createdDate) {
+ this.createdDate = createdDate;
+ return this;
+ }
+
+ public Builder setUpdateDate(DateTime updateDate) {
+ this.updatedDate = updateDate;
+ return this;
+ }
+
public PaymentAttempt build() {
return new DefaultPaymentAttempt(id,
invoiceId,
@@ -228,8 +258,8 @@ public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt
invoiceDate,
paymentAttemptDate,
paymentId,
- retryCount);
+ retryCount,
+ createdDate, updatedDate);
}
-
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java
index 00eedd7..02b7299 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java
@@ -19,6 +19,7 @@ package com.ning.billing.payment.api;
import java.math.BigDecimal;
import java.util.UUID;
+import com.ning.billing.util.entity.EntityBase;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
@@ -26,8 +27,7 @@ import org.joda.time.DateTime;
import com.google.common.base.Objects;
-public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
- private final String paymentId;
+public class DefaultPaymentInfoEvent extends EntityBase implements PaymentInfoEvent {
private final BigDecimal amount;
private final BigDecimal refundAmount;
private final String paymentNumber;
@@ -43,7 +43,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
private final DateTime effectiveDate;
@JsonCreator
- public DefaultPaymentInfoEvent(@JsonProperty("paymentId") String paymentId,
+ public DefaultPaymentInfoEvent(@JsonProperty("id") UUID id,
@JsonProperty("amount") BigDecimal amount,
@JsonProperty("refundAmount") BigDecimal refundAmount,
@JsonProperty("bankIdentificationNumber") String bankIdentificationNumber,
@@ -57,7 +57,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
@JsonProperty("cardCountry") String cardCountry,
@JsonProperty("userToken") UUID userToken,
@JsonProperty("effectiveDate") DateTime effectiveDate) {
- this.paymentId = paymentId;
+ super(id);
this.amount = amount;
this.refundAmount = refundAmount;
this.bankIdentificationNumber = bankIdentificationNumber;
@@ -74,7 +74,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
}
public DefaultPaymentInfoEvent(DefaultPaymentInfoEvent src) {
- this(src.paymentId,
+ this(src.id,
src.amount,
src.refundAmount,
src.bankIdentificationNumber,
@@ -106,11 +106,6 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
}
@Override
- public String getPaymentId() {
- return paymentId;
- }
-
- @Override
public BigDecimal getAmount() {
return amount;
}
@@ -170,13 +165,8 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
return type;
}
- @Override
- public UUID getId() {
- return UUID.fromString(paymentId);
- }
-
public static class Builder {
- private String paymentId;
+ private UUID id;
private BigDecimal amount;
private BigDecimal refundAmount;
private String paymentNumber;
@@ -195,7 +185,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
}
public Builder(DefaultPaymentInfoEvent src) {
- this.paymentId = src.paymentId;
+ this.id = src.id;
this.amount = src.amount;
this.refundAmount = src.refundAmount;
this.paymentNumber = src.paymentNumber;
@@ -211,8 +201,8 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
this.userToken = src.userToken;
}
- public Builder setPaymentId(String paymentId) {
- this.paymentId = paymentId;
+ public Builder setId(UUID id) {
+ this.id = id;
return this;
}
@@ -282,7 +272,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
}
public PaymentInfoEvent build() {
- return new DefaultPaymentInfoEvent(paymentId,
+ return new DefaultPaymentInfoEvent(id,
amount,
refundAmount,
bankIdentificationNumber,
@@ -301,7 +291,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
@Override
public int hashCode() {
- return Objects.hashCode(paymentId,
+ return Objects.hashCode(id,
amount,
refundAmount,
bankIdentificationNumber,
@@ -329,7 +319,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
if (cardCountry != null ? !cardCountry.equals(that.cardCountry) : that.cardCountry != null) return false;
if (cardType != null ? !cardType.equals(that.cardType) : that.cardType != null) return false;
if (effectiveDate == null ? that.effectiveDate != null : effectiveDate.compareTo(that.effectiveDate) != 0) return false;
- if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) return false;
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (paymentMethod != null ? !paymentMethod.equals(that.paymentMethod) : that.paymentMethod != null)
return false;
if (paymentMethodId != null ? !paymentMethodId.equals(that.paymentMethodId) : that.paymentMethodId != null)
@@ -346,6 +336,6 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
@Override
public String toString() {
- return "PaymentInfo [paymentId=" + paymentId + ", amount=" + amount + ", refundAmount=" + refundAmount + ", paymentNumber=" + paymentNumber + ", bankIdentificationNumber=" + bankIdentificationNumber + ", status=" + status + ", type=" + type + ", referenceId=" + referenceId + ", paymentMethodId=" + paymentMethodId + ", paymentMethod=" + paymentMethod + ", cardType=" + cardType + ", cardCountry=" + cardCountry + ", effectiveDate=" + effectiveDate + "]";
+ return "PaymentInfo [id=" + id + ", amount=" + amount + ", refundAmount=" + refundAmount + ", paymentNumber=" + paymentNumber + ", bankIdentificationNumber=" + bankIdentificationNumber + ", status=" + status + ", type=" + type + ", referenceId=" + referenceId + ", paymentMethodId=" + paymentMethodId + ", paymentMethod=" + paymentMethod + ", cardType=" + cardType + ", cardCountry=" + cardCountry + ", effectiveDate=" + effectiveDate + "]";
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
index cf39283..39201ac 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
@@ -46,8 +46,8 @@ public class AuditedPaymentDao implements PaymentDao {
}
@Override
- public PaymentAttempt getPaymentAttemptForPaymentId(String paymentId) {
- return paymentAttemptSqlDao.getPaymentAttemptForPaymentId(paymentId);
+ public PaymentAttempt getPaymentAttemptForPaymentId(UUID paymentId) {
+ return paymentAttemptSqlDao.getPaymentAttemptForPaymentId(paymentId.toString());
}
@Override
@@ -65,11 +65,11 @@ public class AuditedPaymentDao implements PaymentDao {
Long recordId = transactional.getRecordId(paymentAttempt.getId().toString());
EntityHistory<PaymentAttempt> history = new EntityHistory<PaymentAttempt>(paymentAttempt.getId(), recordId, paymentAttempt, ChangeType.INSERT);
- transactional.addHistoryFromTransaction(history, context);
+ transactional.insertHistoryFromTransaction(history, context);
Long historyRecordId = transactional.getHistoryRecordId(recordId);
- EntityAudit audit = new EntityAudit(historyRecordId, ChangeType.INSERT);
- transactional.insertAuditFromTransaction(TableName.PAYMENT_ATTEMPTS, audit, context);
+ EntityAudit audit = new EntityAudit(TableName.PAYMENT_ATTEMPTS, historyRecordId, ChangeType.INSERT);
+ transactional.insertAuditFromTransaction(audit, context);
return savedPaymentAttempt;
}
});
@@ -85,11 +85,11 @@ public class AuditedPaymentDao implements PaymentDao {
Long recordId = transactional.getRecordId(paymentAttempt.getId().toString());
EntityHistory<PaymentAttempt> history = new EntityHistory<PaymentAttempt>(paymentAttempt.getId(), recordId, paymentAttempt, ChangeType.INSERT);
- transactional.addHistoryFromTransaction(history, context);
+ transactional.insertHistoryFromTransaction(history, context);
Long historyRecordId = transactional.getHistoryRecordId(recordId);
- EntityAudit audit = new EntityAudit(historyRecordId, ChangeType.INSERT);
- transactional.insertAuditFromTransaction(TableName.PAYMENT_ATTEMPTS, audit, context);
+ EntityAudit audit = new EntityAudit(TableName.PAYMENT_ATTEMPTS, historyRecordId, ChangeType.INSERT);
+ transactional.insertAuditFromTransaction(audit, context);
return paymentAttempt;
}
@@ -102,13 +102,13 @@ public class AuditedPaymentDao implements PaymentDao {
@Override
public Void inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
transactional.insertPaymentInfo(info, context);
- Long recordId = transactional.getRecordId(info.getPaymentId());
+ Long recordId = transactional.getRecordId(info.getId().toString());
EntityHistory<PaymentInfoEvent> history = new EntityHistory<PaymentInfoEvent>(info.getId(), recordId, info, ChangeType.INSERT);
- transactional.addHistoryFromTransaction(history, context);
+ transactional.insertHistoryFromTransaction(history, context);
Long historyRecordId = transactional.getHistoryRecordId(recordId);
- EntityAudit audit = new EntityAudit(historyRecordId, ChangeType.INSERT);
- transactional.insertAuditFromTransaction(TableName.PAYMENTS, audit, context);
+ EntityAudit audit = new EntityAudit(TableName.PAYMENTS, historyRecordId, ChangeType.INSERT);
+ transactional.insertAuditFromTransaction(audit, context);
return null;
}
@@ -116,19 +116,19 @@ public class AuditedPaymentDao implements PaymentDao {
}
@Override
- public void updatePaymentAttemptWithPaymentId(final UUID paymentAttemptId, final String paymentId, final CallContext context) {
+ public void updatePaymentAttemptWithPaymentId(final UUID paymentAttemptId, final UUID id, final CallContext context) {
paymentAttemptSqlDao.inTransaction(new Transaction<Void, PaymentAttemptSqlDao>() {
@Override
public Void inTransaction(PaymentAttemptSqlDao transactional, TransactionStatus status) throws Exception {
- transactional.updatePaymentAttemptWithPaymentId(paymentAttemptId.toString(), paymentId, context);
+ transactional.updatePaymentAttemptWithPaymentId(paymentAttemptId.toString(), id.toString(), context);
PaymentAttempt paymentAttempt = transactional.getPaymentAttemptById(paymentAttemptId.toString());
Long recordId = transactional.getRecordId(paymentAttemptId.toString());
EntityHistory<PaymentAttempt> history = new EntityHistory<PaymentAttempt>(paymentAttemptId, recordId, paymentAttempt, ChangeType.UPDATE);
- transactional.addHistoryFromTransaction(history, context);
+ transactional.insertHistoryFromTransaction(history, context);
Long historyRecordId = transactional.getHistoryRecordId(recordId);
- EntityAudit audit = new EntityAudit(historyRecordId, ChangeType.UPDATE);
- transactional.insertAuditFromTransaction(TableName.PAYMENT_ATTEMPTS, audit, context);
+ EntityAudit audit = new EntityAudit(TableName.PAYMENT_ATTEMPTS, historyRecordId, ChangeType.UPDATE);
+ transactional.insertAuditFromTransaction(audit, context);
return null;
}
@@ -136,21 +136,21 @@ public class AuditedPaymentDao implements PaymentDao {
}
@Override
- public void updatePaymentInfo(final String type, final String paymentId, final String cardType,
+ public void updatePaymentInfo(final String type, final UUID paymentId, final String cardType,
final String cardCountry, final CallContext context) {
paymentSqlDao.inTransaction(new Transaction<Void, PaymentSqlDao>() {
@Override
public Void inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
- transactional.updatePaymentInfo(type, paymentId, cardType, cardCountry, context);
- PaymentInfoEvent paymentInfo = transactional.getPaymentInfo(paymentId);
+ transactional.updatePaymentInfo(type, paymentId.toString(), cardType, cardCountry, context);
+ PaymentInfoEvent paymentInfo = transactional.getPaymentInfo(paymentId.toString());
- Long recordId = transactional.getRecordId(paymentId);
+ Long recordId = transactional.getRecordId(paymentId.toString());
EntityHistory<PaymentInfoEvent> history = new EntityHistory<PaymentInfoEvent>(paymentInfo.getId(), recordId, paymentInfo, ChangeType.UPDATE);
- transactional.addHistoryFromTransaction(history, context);
+ transactional.insertHistoryFromTransaction(history, context);
Long historyRecordId = transactional.getHistoryRecordId(recordId);
- EntityAudit audit = new EntityAudit(historyRecordId, ChangeType.UPDATE);
- transactional.insertAuditFromTransaction(TableName.PAYMENT_HISTORY, audit, context);
+ EntityAudit audit = new EntityAudit(TableName.PAYMENT_HISTORY, historyRecordId, ChangeType.UPDATE);
+ transactional.insertAuditFromTransaction(audit, context);
return null;
}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java
new file mode 100644
index 0000000..e063655
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java
@@ -0,0 +1,60 @@
+/*
+ * 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.dao;
+
+import com.ning.billing.payment.api.PaymentAttempt;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.EntityHistory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(PaymentAttemptHistoryBinder.PaymentAttemptHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface PaymentAttemptHistoryBinder {
+ public static class PaymentAttemptHistoryBinderFactory extends BinderBase implements BinderFactory {
+ @Override
+ public Binder<PaymentAttemptHistoryBinder, EntityHistory<PaymentAttempt>> build(Annotation annotation) {
+ return new Binder<PaymentAttemptHistoryBinder, EntityHistory<PaymentAttempt>>() {
+ @Override
+ public void bind(SQLStatement q, PaymentAttemptHistoryBinder bind, EntityHistory<PaymentAttempt> history) {
+ q.bind("recordId", history.getValue());
+ q.bind("changeType", history.getChangeType().toString());
+
+ PaymentAttempt paymentAttempt = history.getEntity();
+ q.bind("id", paymentAttempt.getId().toString());
+ q.bind("invoice_id", paymentAttempt.getInvoiceId().toString());
+ q.bind("account_id", paymentAttempt.getAccountId().toString());
+ q.bind("amount", paymentAttempt.getAmount());
+ q.bind("currency", paymentAttempt.getCurrency().toString());
+ q.bind("invoice_date", getDate(paymentAttempt.getInvoiceDate()));
+ q.bind("payment_attempt_date", getDate(paymentAttempt.getPaymentAttemptDate()));
+ q.bind("payment_id", paymentAttempt.getPaymentId().toString());
+ q.bind("retry_count", paymentAttempt.getRetryCount());
+ }
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
index 1a5e220..747d513 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
@@ -21,12 +21,10 @@ import com.ning.billing.payment.api.DefaultPaymentAttempt;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.dao.AuditSqlDao;
import com.ning.billing.util.dao.BinderBase;
-import com.ning.billing.util.dao.HistorySqlDao;
+import com.ning.billing.util.dao.EntityHistory;
import com.ning.billing.util.dao.MapperBase;
-import com.ning.billing.util.entity.dao.EntityDao;
-import com.ning.billing.util.entity.dao.EntitySqlDao;
+import com.ning.billing.util.entity.dao.UpdatableEntitySqlDao;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
@@ -49,7 +47,7 @@ import java.util.UUID;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(PaymentAttemptSqlDao.PaymentAttemptMapper.class)
-public interface PaymentAttemptSqlDao extends Transactional<PaymentAttemptSqlDao>, EntitySqlDao, HistorySqlDao<PaymentAttempt>, AuditSqlDao, CloseMe {
+public interface PaymentAttemptSqlDao extends Transactional<PaymentAttemptSqlDao>, UpdatableEntitySqlDao<PaymentAttempt>, CloseMe {
@SqlUpdate
void insertPaymentAttempt(@Bind(binder = PaymentAttemptBinder.class) PaymentAttempt paymentAttempt,
@CallContextBinder CallContext context);
@@ -58,7 +56,7 @@ public interface PaymentAttemptSqlDao extends Transactional<PaymentAttemptSqlDao
PaymentAttempt getPaymentAttemptForPaymentId(@Bind("payment_id") String paymentId);
@SqlQuery
- PaymentAttempt getPaymentAttemptById(@Bind("payment_attempt_id") String paymentAttemptId);
+ PaymentAttempt getPaymentAttemptById(@Bind("id") String paymentAttemptId);
@SqlQuery
List<PaymentAttempt> getPaymentAttemptsForInvoiceId(@Bind("invoice_id") String invoiceId);
@@ -68,28 +66,35 @@ public interface PaymentAttemptSqlDao extends Transactional<PaymentAttemptSqlDao
@SqlUpdate
- void updatePaymentAttemptWithPaymentId(@Bind("payment_attempt_id") String paymentAttemptId,
+ void updatePaymentAttemptWithPaymentId(@Bind("id") String paymentAttemptId,
@Bind("payment_id") String paymentId,
@CallContextBinder CallContext context);
@SqlUpdate
- void updatePaymentAttemptWithRetryInfo(@Bind("payment_attempt_id") String paymentAttemptId,
+ void updatePaymentAttemptWithRetryInfo(@Bind("id") String paymentAttemptId,
@Bind("retry_count") int retryCount,
@CallContextBinder CallContext context);
+
+ @Override
+ @SqlUpdate
+ public void insertHistoryFromTransaction(@PaymentAttemptHistoryBinder final EntityHistory<PaymentAttempt> account,
+ @CallContextBinder final CallContext context);
public static class PaymentAttemptMapper extends MapperBase implements ResultSetMapper<PaymentAttempt> {
@Override
public PaymentAttempt map(int index, ResultSet rs, StatementContext ctx) throws SQLException {
- UUID paymentAttemptId = UUID.fromString(rs.getString("id"));
- UUID invoiceId = UUID.fromString(rs.getString("invoice_id"));
- UUID accountId = UUID.fromString(rs.getString("account_id"));
+ UUID paymentAttemptId = getUUID(rs, "id");
+ UUID invoiceId = getUUID(rs, "invoice_id");
+ UUID accountId = getUUID(rs, "account_id");
BigDecimal amount = rs.getBigDecimal("amount");
Currency currency = Currency.valueOf(rs.getString("currency"));
DateTime invoiceDate = getDate(rs, "invoice_date");
DateTime paymentAttemptDate = getDate(rs, "payment_attempt_date");
- String paymentId = rs.getString("payment_id");
+ UUID paymentId = getUUID(rs, "payment_id");
Integer retryCount = rs.getInt("retry_count");
+ DateTime createdDate = getDate(rs, "created_date");
+ DateTime updatedDate = getDate(rs, "updated_date");
return new DefaultPaymentAttempt(paymentAttemptId,
invoiceId,
@@ -99,21 +104,22 @@ public interface PaymentAttemptSqlDao extends Transactional<PaymentAttemptSqlDao
invoiceDate,
paymentAttemptDate,
paymentId,
- retryCount);
+ retryCount,
+ createdDate, updatedDate);
}
}
public static final class PaymentAttemptBinder extends BinderBase implements Binder<Bind, PaymentAttempt> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentAttempt paymentAttempt) {
- stmt.bind("id", paymentAttempt.getId() == null ? null : paymentAttempt.getId().toString());
+ stmt.bind("id", paymentAttempt.getId().toString());
stmt.bind("invoice_id", paymentAttempt.getInvoiceId().toString());
stmt.bind("account_id", paymentAttempt.getAccountId().toString());
stmt.bind("amount", paymentAttempt.getAmount());
stmt.bind("currency", paymentAttempt.getCurrency().toString());
stmt.bind("invoice_date", getDate(paymentAttempt.getInvoiceDate()));
stmt.bind("payment_attempt_date", getDate(paymentAttempt.getPaymentAttemptDate()));
- stmt.bind("payment_id", paymentAttempt.getPaymentId());
+ stmt.bind("payment_id", paymentAttempt.getPaymentId().toString());
stmt.bind("retry_count", paymentAttempt.getRetryCount());
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
index 67c9027..581ed71 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
@@ -31,14 +31,14 @@ public interface PaymentDao {
void savePaymentInfo(PaymentInfoEvent right, CallContext context);
- PaymentAttempt getPaymentAttemptForPaymentId(String paymentId);
+ PaymentAttempt getPaymentAttemptForPaymentId(UUID paymentId);
List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds);
- void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId, CallContext context);
+ void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, UUID paymentId, CallContext context);
List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
- void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context);
+ void updatePaymentInfo(String paymentMethodType, UUID paymentId, String cardType, String cardCountry, CallContext context);
List<PaymentInfoEvent> getPaymentInfoList(List<String> invoiceIds);
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java
new file mode 100644
index 0000000..2ec9fc7
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java
@@ -0,0 +1,64 @@
+/*
+ * 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.dao;
+
+import com.ning.billing.payment.api.PaymentInfoEvent;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.EntityHistory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(PaymentHistoryBinder.PaymentHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface PaymentHistoryBinder {
+ public static class PaymentHistoryBinderFactory extends BinderBase implements BinderFactory {
+ @Override
+ public Binder<PaymentHistoryBinder, EntityHistory<PaymentInfoEvent>> build(Annotation annotation) {
+ return new Binder<PaymentHistoryBinder, EntityHistory<PaymentInfoEvent>>() {
+ @Override
+ public void bind(SQLStatement q, PaymentHistoryBinder bind, EntityHistory<PaymentInfoEvent> history) {
+ q.bind("recordId", history.getValue());
+ q.bind("changeType", history.getChangeType().toString());
+
+ PaymentInfoEvent paymentInfo = history.getEntity();
+ q.bind("id", paymentInfo.getId().toString());
+ q.bind("amount", paymentInfo.getAmount());
+ q.bind("refund_amount", paymentInfo.getRefundAmount());
+ q.bind("payment_number", paymentInfo.getPaymentNumber());
+ q.bind("bank_identification_number", paymentInfo.getBankIdentificationNumber());
+ q.bind("status", paymentInfo.getStatus());
+ q.bind("payment_type", paymentInfo.getType());
+ q.bind("reference_id", paymentInfo.getReferenceId());
+ q.bind("payment_method_id", paymentInfo.getPaymentMethodId());
+ q.bind("payment_method", paymentInfo.getPaymentMethod());
+ q.bind("card_type", paymentInfo.getCardType());
+ q.bind("card_country", paymentInfo.getCardCountry());
+ q.bind("effective_date", getDate(paymentInfo.getEffectiveDate()));
+ }
+ };
+ }
+ }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
index 0966829..bdd9829 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
@@ -24,12 +24,10 @@ import java.util.UUID;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.dao.AuditSqlDao;
import com.ning.billing.util.dao.BinderBase;
-import com.ning.billing.util.dao.HistorySqlDao;
+import com.ning.billing.util.dao.EntityHistory;
import com.ning.billing.util.dao.MapperBase;
-import com.ning.billing.util.entity.dao.EntityDao;
-import com.ning.billing.util.entity.dao.EntitySqlDao;
+import com.ning.billing.util.entity.dao.UpdatableEntitySqlDao;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
@@ -40,25 +38,22 @@ import org.skife.jdbi.v2.sqlobject.SqlUpdate;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
import org.skife.jdbi.v2.unstable.BindIn;
import com.ning.billing.payment.api.DefaultPaymentInfoEvent;
-import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(PaymentSqlDao.PaymentInfoMapper.class)
-public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, EntitySqlDao,
- HistorySqlDao<PaymentInfoEvent>, AuditSqlDao, CloseMe {
+public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, UpdatableEntitySqlDao<PaymentInfoEvent>, CloseMe {
@SqlQuery
PaymentInfoEvent getPaymentInfoForPaymentAttemptId(@Bind("payment_attempt_id") String paymentAttemptId);
@SqlUpdate
void updatePaymentInfo(@Bind("payment_method") String paymentMethod,
- @Bind("payment_id") String paymentId,
+ @Bind("id") String paymentId,
@Bind("card_type") String cardType,
@Bind("card_country") String cardCountry,
@CallContextBinder CallContext context);
@@ -74,12 +69,17 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, EntitySqlDa
@CallContextBinder final CallContext context);
@SqlQuery
- PaymentInfoEvent getPaymentInfo(@Bind("paymentId") final String paymentId);
+ PaymentInfoEvent getPaymentInfo(@Bind("id") final String paymentId);
+
+ @Override
+ @SqlUpdate
+ public void insertHistoryFromTransaction(@PaymentHistoryBinder final EntityHistory<PaymentInfoEvent> account,
+ @CallContextBinder final CallContext context);
public static final class PaymentInfoBinder extends BinderBase implements Binder<Bind, PaymentInfoEvent> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentInfoEvent paymentInfo) {
- stmt.bind("payment_id", paymentInfo.getPaymentId());
+ stmt.bind("id", paymentInfo.getId().toString());
stmt.bind("amount", paymentInfo.getAmount());
stmt.bind("refund_amount", paymentInfo.getRefundAmount());
stmt.bind("payment_number", paymentInfo.getPaymentNumber());
@@ -98,8 +98,7 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, EntitySqlDa
public static class PaymentInfoMapper extends MapperBase implements ResultSetMapper<PaymentInfoEvent> {
@Override
public PaymentInfoEvent map(int index, ResultSet rs, StatementContext ctx) throws SQLException {
-
- String paymentId = rs.getString("id");
+ UUID id = getUUID(rs, "id");
BigDecimal amount = rs.getBigDecimal("amount");
BigDecimal refundAmount = rs.getBigDecimal("refund_amount");
String paymentNumber = rs.getString("payment_number");
@@ -115,7 +114,7 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, EntitySqlDa
UUID userToken = null; //rs.getString("user_token") != null ? UUID.fromString(rs.getString("user_token")) : null;
- return new DefaultPaymentInfoEvent(paymentId,
+ return new DefaultPaymentInfoEvent(id,
amount,
refundAmount,
bankIdentificationNumber,
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
index 625504b..94a97db 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
@@ -38,7 +38,7 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
@Override
public Either<PaymentErrorEvent, PaymentInfoEvent> processInvoice(Account account, Invoice invoice) {
PaymentInfoEvent payment = new DefaultPaymentInfoEvent.Builder()
- .setPaymentId(UUID.randomUUID().toString())
+ .setId(UUID.randomUUID())
.setAmount(invoice.getBalance())
.setStatus("Processed")
.setEffectiveDate(new DateTime(DateTimeZone.UTC))
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 a1ccd55..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);
- eventBus.post(result.isLeft() ? result.getLeft() : result.getRight());
- }
+ 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.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);
}
- catch(AccountApiException e) {
- log.warn("could not process invoice payment", e);
- }
- catch (EventBusException ex) {
- throw new RuntimeException(ex);
- }
+ 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 84c9739..2563638 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/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
new file mode 100644
index 0000000..812da6a
--- /dev/null
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
@@ -0,0 +1,106 @@
+group paymentAttemptSqlDao;
+
+paymentAttemptFields(prefix) ::= <<
+ <prefix>id,
+ <prefix>invoice_id,
+ <prefix>account_id,
+ <prefix>amount,
+ <prefix>currency,
+ <prefix>payment_id,
+ <prefix>payment_attempt_date,
+ <prefix>invoice_date,
+ <prefix>retry_count,
+ <prefix>created_by,
+ <prefix>created_date,
+ <prefix>updated_by,
+ <prefix>updated_date
+>>
+
+insertPaymentAttempt() ::= <<
+ INSERT INTO payment_attempts (<paymentAttemptFields()>)
+ VALUES (:id, :invoice_id, :account_id, :amount, :currency, :payment_id,
+ :payment_attempt_date, :invoice_date, :retry_count, :userName, :createdDate, :userName, :createdDate);
+>>
+
+getPaymentAttemptForPaymentId() ::= <<
+ SELECT <paymentAttemptFields()>
+ FROM payment_attempts
+ WHERE id = :id;
+>>
+
+getPaymentAttemptById() ::= <<
+ SELECT <paymentAttemptFields()>
+ FROM payment_attempts
+ WHERE id = :id;
+>>
+
+getPaymentAttemptsForInvoiceIds(invoiceIds) ::= <<
+ SELECT <paymentAttemptFields()>
+ FROM payment_attempts
+ WHERE invoice_id in (<invoiceIds>);
+>>
+
+getPaymentAttemptsForInvoiceId() ::= <<
+ SELECT <paymentAttemptFields()>
+ FROM payment_attempts
+ WHERE invoice_id = :invoice_id;
+>>
+
+updatePaymentAttemptWithPaymentId() ::= <<
+ UPDATE payment_attempts
+ SET payment_id = :payment_id,
+ updated_by = :userName,
+ updated_date = :updatedDate
+ WHERE id = :id;
+>>
+
+historyFields(prefix) ::= <<
+ record_id,
+ id,
+ account_id,
+ invoice_id,
+ amount,
+ currency,
+ payment_attempt_date,
+ payment_id,
+ retry_count,
+ invoice_date,
+ created_by,
+ created_date,
+ updated_by,
+ updated_date
+>>
+
+insertHistoryFromTransaction() ::= <<
+ INSERT INTO payment_attempt_history (<historyFields()>)
+ VALUES (:recordId, :id, :account_id, :invoice_id, :amount, :currency, :payment_attempt_date, :payment_id,
+ :retry_count, :invoice_date, :userName, :createdDate, :userName, :updatedDate);
+>>
+
+getRecordId() ::= <<
+ SELECT record_id
+ FROM payment_attempts
+ WHERE id = :id;
+>>
+
+getHistoryRecordId() ::= <<
+ SELECT MAX(history_record_id)
+ FROM payment_attempt_history
+ WHERE record_id = :recordId;
+>>
+
+auditFields(prefix) ::= <<
+ <prefix>table_name,
+ <prefix>record_id,
+ <prefix>change_type,
+ <prefix>change_date,
+ <prefix>changed_by,
+ <prefix>reason_code,
+ <prefix>comments,
+ <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+ INSERT INTO audit_log(<auditFields()>)
+ VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
index 473caa6..3f125ab 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
@@ -1,23 +1,7 @@
group PaymentSqlDao;
-paymentAttemptFields(prefix) ::= <<
- <prefix>payment_attempt_id,
- <prefix>invoice_id,
- <prefix>account_id,
- <prefix>amount,
- <prefix>currency,
- <prefix>payment_id,
- <prefix>payment_attempt_date,
- <prefix>invoice_date,
- <prefix>retry_count,
- <prefix>created_by,
- <prefix>created_date,
- <prefix>updated_by,
- <prefix>updated_date
->>
-
paymentInfoFields(prefix) ::= <<
- <prefix>payment_id,
+ <prefix>id,
<prefix>amount,
<prefix>refund_amount,
<prefix>bank_identification_number,
@@ -36,60 +20,9 @@ paymentInfoFields(prefix) ::= <<
<prefix>updated_date
>>
-insertPaymentAttempt() ::= <<
- INSERT INTO payment_attempts (<paymentAttemptFields()>)
- VALUES (:payment_attempt_id, :invoice_id, :account_id, :amount, :currency, :payment_id,
- :payment_attempt_date, :invoice_date, :retry_count, :userName, :createdDate, :userName, :createdDate);
->>
-
-insertPaymentAttemptHistory() ::= <<
- INSERT INTO payment_attempt_history (history_record_id, <paymentAttemptFields()>)
- VALUES (:historyRecordId, :payment_attempt_id, :invoice_id, :account_id, :amount, :currency, :payment_id,
- :payment_attempt_date, :invoice_date, :retry_count, :userName, :createdDate, :userName, :createdDate);
->>
-
-getPaymentAttemptForPaymentId() ::= <<
- SELECT <paymentAttemptFields()>
- FROM payment_attempts
- WHERE payment_id = :payment_id
->>
-
-getPaymentAttemptById() ::= <<
- SELECT <paymentAttemptFields()>
- FROM payment_attempts
- WHERE payment_attempt_id = :payment_attempt_id
->>
-
-getPaymentAttemptsForInvoiceIds(invoiceIds) ::= <<
- SELECT <paymentAttemptFields()>
- FROM payment_attempts
- WHERE invoice_id in (<invoiceIds>)
->>
-
-getPaymentAttemptsForInvoiceId() ::= <<
- SELECT <paymentAttemptFields()>
- FROM payment_attempts
- WHERE invoice_id = :invoice_id
->>
-
-updatePaymentAttemptWithPaymentId() ::= <<
- UPDATE payment_attempts
- SET payment_id = :payment_id,
- updated_by = :userName,
- updated_date = :updatedDate
- WHERE payment_attempt_id = :payment_attempt_id
->>
-
insertPaymentInfo() ::= <<
INSERT INTO payments (<paymentInfoFields()>)
- VALUES (:payment_id, :amount, :refund_amount, :bank_identification_number, :payment_number,
- :payment_type, :status, :reference_id, :payment_method_id, :payment_method, :card_type,
- :card_country, :effective_date, :userName, :createdDate, :userName, :createdDate);
->>
-
-insertPaymentInfoHistory() ::= <<
- INSERT INTO payment_history (history_record_id, <paymentInfoFields()>)
- VALUES (:historyRecordId, :payment_id, :amount, :refund_amount, :bank_identification_number, :payment_number,
+ VALUES (:id, :amount, :refund_amount, :bank_identification_number, :payment_number,
:payment_type, :status, :reference_id, :payment_method_id, :payment_method, :card_type,
:card_country, :effective_date, :userName, :createdDate, :userName, :createdDate);
>>
@@ -101,25 +34,91 @@ updatePaymentInfo() ::= <<
card_country = :card_country,
updated_by = :userName,
updated_date = :updatedDate
- WHERE payment_id = :payment_id
+ WHERE id = :id
>>
-getPaymentInfos(invoiceIds) ::= <<
+getPaymentInfoList(invoiceIds) ::= <<
SELECT <paymentInfoFields("p.")>
FROM payments p, payment_attempts pa
- WHERE pa.invoice_id in (<invoiceIds>)
- AND pa.payment_id = p.payment_id
+ WHERE pa.invoice_id in (<invoiceIds>)
+ AND pa.payment_id = p.id
+>>
+
+getLastPaymentInfo(invoiceIds) ::= <<
+ SELECT <paymentInfoFields("p.")>
+ FROM payments p, payment_attempts pa
+ WHERE pa.invoice_id in (<invoiceIds>)
+ AND pa.payment_id = p.id
+ ORDER BY p.created_date DESC
+ LIMIT 1;
>>
getPaymentInfoForPaymentAttemptId() ::= <<
SELECT <paymentInfoFields("p.")>
FROM payments p, payment_attempts pa
- WHERE pa.payment_attempt_id = :payment_attempt_id
- AND pa.payment_id = p.payment_id
+ WHERE pa.payment_attempt_id = :payment_attempt_id
+ AND pa.payment_id = p.id
>>
getPaymentInfo() ::= <<
SELECT <paymentInfoFields()>
FROM payments
- WHERE payment_id = :paymentId
+ WHERE id = :id
+>>
+
+historyFields(prefix) ::= <<
+ record_id,
+ id,
+ amount,
+ refund_amount,
+ payment_number,
+ bank_identification_number,
+ status,
+ reference_id,
+ payment_type,
+ payment_method_id,
+ payment_method,
+ card_type,
+ card_country,
+ effective_date,
+ created_by,
+ created_date,
+ updated_by,
+ updated_date
+>>
+
+insertHistoryFromTransaction() ::= <<
+ INSERT INTO payment_history (<historyFields()>)
+ VALUES (:recordId, :id, :amount, :refund_amount, :bank_identification_number, :payment_number,
+ :payment_type, :status, :reference_id, :payment_method_id, :payment_method, :card_type,
+ :card_country, :effective_date, :userName, :createdDate, :userName, :updatedDate);
+>>
+
+getRecordId() ::= <<
+ SELECT record_id
+ FROM payments
+ WHERE id = :id;
+>>
+
+getHistoryRecordId() ::= <<
+ SELECT MAX(history_record_id)
+ FROM payment_history
+ WHERE record_id = :recordId;
>>
+
+auditFields(prefix) ::= <<
+ <prefix>table_name,
+ <prefix>record_id,
+ <prefix>change_type,
+ <prefix>change_date,
+ <prefix>changed_by,
+ <prefix>reason_code,
+ <prefix>comments,
+ <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+ INSERT INTO audit_log(<auditFields()>)
+ VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java b/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java
index b973d36..198e986 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java
@@ -49,13 +49,13 @@ public class TestEventJson {
@Test(groups= {"fast"})
public void testPaymentInfoEvent() throws Exception {
- PaymentInfoEvent e = new DefaultPaymentInfoEvent(UUID.randomUUID().toString(), new BigDecimal(12), new BigDecimal(12.9), "BNP", "eeert", "success",
+ PaymentInfoEvent e = new DefaultPaymentInfoEvent(UUID.randomUUID(), new BigDecimal(12), new BigDecimal(12.9), "BNP", "eeert", "success",
"credit", "ref", "paypal", "paypal", "", "", UUID.randomUUID(), new DateTime());
String json = mapper.writeValueAsString(e);
- Class<?> claz = Class.forName(DefaultPaymentInfoEvent.class.getName());
- Object obj = mapper.readValue(json, claz);
+ Class<?> clazz = Class.forName(DefaultPaymentInfoEvent.class.getName());
+ Object obj = mapper.readValue(json, clazz);
Assert.assertTrue(obj.equals(e));
}
}
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java
index 833f926..0ff39d2 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java
@@ -20,13 +20,13 @@ import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import com.google.inject.Inject;
-import com.ning.billing.account.glue.AccountModuleWithMocks;
-import com.ning.billing.invoice.glue.InvoiceModuleWithMocks;
import com.ning.billing.mock.glue.MockJunctionModule;
import com.ning.billing.payment.setup.PaymentTestModuleWithMocks;
import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.MockClockModule;
+import com.ning.billing.util.glue.CallContextModule;
-@Guice(modules = { PaymentTestModuleWithMocks.class, AccountModuleWithMocks.class, InvoiceModuleWithMocks.class, MockJunctionModule.class })
+@Guice(modules = { PaymentTestModuleWithMocks.class, MockClockModule.class, MockJunctionModule.class, CallContextModule.class })
@Test(groups = "fast")
public class TestMockPaymentApi extends TestPaymentApi {
@Inject
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 53635fb..c7f925b 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
@@ -36,12 +36,12 @@ import org.testng.annotations.Test;
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.payment.MockRecurringInvoiceItem;
import com.ning.billing.payment.TestHelper;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
@@ -50,7 +50,6 @@ import com.ning.billing.util.callcontext.CallOrigin;
import com.ning.billing.util.callcontext.DefaultCallContext;
import com.ning.billing.util.callcontext.UserType;
import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.entity.EntityPersistenceException;
public abstract class TestPaymentApi {
@Inject
@@ -59,6 +58,8 @@ public abstract class TestPaymentApi {
protected PaymentApi paymentApi;
@Inject
protected TestHelper testHelper;
+ @Inject
+ protected InvoicePaymentApi invoicePaymentApi;
protected CallContext context;
@@ -78,7 +79,9 @@ public abstract class TestPaymentApi {
}
@Test(enabled=true)
- public void testCreateCreditCardPayment() throws AccountApiException, EntityPersistenceException {
+ public void testCreateCreditCardPayment() throws Exception {
+ ((ZombieControl)invoicePaymentApi).addResult("notifyOfPaymentAttempt", BrainDeadProxyFactory.ZOMBIE_VOID);
+
final DateTime now = new DateTime(DateTimeZone.UTC);
final Account account = testHelper.createTestCreditCardAccount();
final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD);
@@ -86,7 +89,7 @@ public abstract class TestPaymentApi {
final UUID subscriptionId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
- invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(), account.getId(),
+ invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(), account.getId(),
subscriptionId,
bundleId,
"test plan", "test phase",
@@ -96,25 +99,24 @@ 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());
+ assertNotNull(paymentInfo.getId());
assertTrue(paymentInfo.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
assertNotNull(paymentInfo.getPaymentNumber());
assertFalse(paymentInfo.getStatus().equals("Error"));
- PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
+ PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getId());
assertNotNull(paymentAttempt);
assertNotNull(paymentAttempt.getId());
assertEquals(paymentAttempt.getInvoiceId(), invoice.getId());
assertTrue(paymentAttempt.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
assertEquals(paymentAttempt.getCurrency(), Currency.USD);
- assertEquals(paymentAttempt.getPaymentId(), paymentInfo.getPaymentId());
+ assertEquals(paymentAttempt.getPaymentId(), paymentInfo.getId());
DateTime nowTruncated = now.withMillisOfSecond(0).withSecondOfMinute(0);
DateTime paymentAttemptDateTruncated = paymentAttempt.getPaymentAttemptDate().withMillisOfSecond(0).withSecondOfMinute(0);
assertEquals(paymentAttemptDateTruncated.compareTo(nowTruncated), 0);
@@ -126,7 +128,7 @@ public abstract class TestPaymentApi {
PaymentInfoEvent paymentInfoFromGet = paymentInfos.get(0);
assertEquals(paymentInfo.getAmount(), paymentInfoFromGet.getAmount());
assertEquals(paymentInfo.getRefundAmount(), paymentInfoFromGet.getRefundAmount());
- assertEquals(paymentInfo.getPaymentId(), paymentInfoFromGet.getPaymentId());
+ assertEquals(paymentInfo.getId(), paymentInfoFromGet.getId());
assertEquals(paymentInfo.getPaymentNumber(), paymentInfoFromGet.getPaymentNumber());
assertEquals(paymentInfo.getStatus(), paymentInfoFromGet.getStatus());
assertEquals(paymentInfo.getBankIdentificationNumber(), paymentInfoFromGet.getBankIdentificationNumber());
@@ -139,7 +141,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);
@@ -150,32 +152,22 @@ public abstract class TestPaymentApi {
.setEmail(account.getEmail())
.setDefaultMethod(true)
.build();
- Either<PaymentErrorEvent, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
-
- assertTrue(paymentMethodIdOrError.isRight());
- assertNotNull(paymentMethodIdOrError.getRight());
-
- Either<PaymentErrorEvent, PaymentMethodInfo> paymentMethodInfoOrError = paymentApi.getPaymentMethod(accountKey, paymentMethodIdOrError.getRight());
+ String paymentMethodId = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
- assertTrue(paymentMethodInfoOrError.isRight());
- assertNotNull(paymentMethodInfoOrError.getRight());
+ PaymentMethodInfo paymentMethodInfo = paymentApi.getPaymentMethod(accountKey, paymentMethodId);
- Either<PaymentErrorEvent, PaymentProviderAccount> accountOrError = paymentApi.getPaymentProviderAccount(accountKey);
-
- assertTrue(accountOrError.isRight());
-
- return accountOrError.getRight();
+ return paymentApi.getPaymentProviderAccount(accountKey);
}
@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);
@@ -190,48 +182,12 @@ public abstract class TestPaymentApi {
zombieAccount.addResult("getCurrency", account.getCurrency());
zombieAccount.addResult("getBillCycleDay", account.getBillCycleDay());
- Either<PaymentErrorEvent, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(account.getExternalKey(), context);
- assertTrue(voidOrError.isRight());
+ paymentApi.updatePaymentProviderAccountContact(updatedAccount.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);
}
-
- @Test(enabled=true)
- public void testDeleteNonDefaultPaymentMethod() throws AccountApiException, EntityPersistenceException {
- final Account account = testHelper.createTestPayPalAccount();
- paymentApi.createPaymentProviderAccount(account, context);
-
- String accountKey = account.getExternalKey();
-
- PaypalPaymentMethodInfo paymentMethod1 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(false).setBaid("12345").setEmail(account.getEmail()).build();
- Either<PaymentErrorEvent, String> paymentMethodIdOrError1 = paymentApi.addPaymentMethod(accountKey, paymentMethod1, context);
-
- assertTrue(paymentMethodIdOrError1.isRight());
- assertNotNull(paymentMethodIdOrError1.getRight());
-
- PaypalPaymentMethodInfo paymentMethod2 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(true).setBaid("12345").setEmail(account.getEmail()).build();
-
- Either<PaymentErrorEvent, String> paymentMethodIdOrError2 = paymentApi.addPaymentMethod(accountKey, paymentMethod2, context);
-
- assertTrue(paymentMethodIdOrError2.isRight());
- assertNotNull(paymentMethodIdOrError2.getRight());
-
- Either<PaymentErrorEvent, List<PaymentMethodInfo>> paymentMethodsOrError = paymentApi.getPaymentMethods(accountKey);
-
- assertTrue(paymentMethodsOrError.isRight());
-
- Either<PaymentErrorEvent, Void> errorOrVoid1 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError1.getRight(), context);
- Either<PaymentErrorEvent, Void> errorOrVoid2 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError2.getRight(), context);
-
- assertTrue(errorOrVoid1.isRight());
- assertTrue(errorOrVoid2.isLeft());
- }
-
}
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
index 85ff33e..3f90466 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
@@ -35,11 +35,11 @@ import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentInfoEvent;
public class MockPaymentDao implements PaymentDao {
- private final Map<String, PaymentInfoEvent> payments = new ConcurrentHashMap<String, PaymentInfoEvent>();
+ private final Map<UUID, PaymentInfoEvent> payments = new ConcurrentHashMap<UUID, PaymentInfoEvent>();
private final Map<UUID, PaymentAttempt> paymentAttempts = new ConcurrentHashMap<UUID, PaymentAttempt>();
@Override
- public PaymentAttempt getPaymentAttemptForPaymentId(String paymentId) {
+ public PaymentAttempt getPaymentAttemptForPaymentId(UUID paymentId) {
for (PaymentAttempt paymentAttempt : paymentAttempts.values()) {
if (paymentId.equals(paymentAttempt.getPaymentId())) {
return paymentAttempt;
@@ -52,7 +52,7 @@ public class MockPaymentDao implements PaymentDao {
public PaymentAttempt createPaymentAttempt(Invoice invoice, CallContext context) {
PaymentAttempt updatedPaymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice.getId(), invoice.getAccountId(),
invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(),
- null, null, null);
+ null, null, null, null, null);
paymentAttempts.put(updatedPaymentAttempt.getId(), updatedPaymentAttempt);
return updatedPaymentAttempt;
@@ -64,7 +64,8 @@ public class MockPaymentDao implements PaymentDao {
paymentAttempt.getInvoiceId(),
paymentAttempt.getAccountId(), paymentAttempt.getAmount(), paymentAttempt.getCurrency(),
paymentAttempt.getInvoiceDate(), paymentAttempt.getPaymentAttemptDate(),
- paymentAttempt.getPaymentId(), paymentAttempt.getRetryCount());
+ paymentAttempt.getPaymentId(), paymentAttempt.getRetryCount(),
+ paymentAttempt.getCreatedDate(), paymentAttempt.getUpdatedDate());
paymentAttempts.put(updatedPaymentAttempt.getId(), updatedPaymentAttempt);
return updatedPaymentAttempt;
@@ -72,11 +73,11 @@ public class MockPaymentDao implements PaymentDao {
@Override
public void savePaymentInfo(PaymentInfoEvent paymentInfo, CallContext context) {
- payments.put(paymentInfo.getPaymentId(), paymentInfo);
+ payments.put(paymentInfo.getId(), paymentInfo);
}
@Override
- public void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId, CallContext context) {
+ public void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, UUID paymentId, CallContext context) {
PaymentAttempt existingPaymentAttempt = paymentAttempts.get(paymentAttemptId);
if (existingPaymentAttempt != null) {
@@ -97,7 +98,7 @@ public class MockPaymentDao implements PaymentDao {
}
@Override
- public void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context) {
+ public void updatePaymentInfo(String paymentMethodType, UUID paymentId, String cardType, String cardCountry, CallContext context) {
DefaultPaymentInfoEvent existingPayment = (DefaultPaymentInfoEvent) payments.get(paymentId);
if (existingPayment != null) {
PaymentInfoEvent payment = existingPayment.cloner()
@@ -118,7 +119,7 @@ public class MockPaymentDao implements PaymentDao {
paymentsToReturn.addAll(Collections2.filter(payments.values(), new Predicate<PaymentInfoEvent>() {
@Override
public boolean apply(PaymentInfoEvent input) {
- return input.getPaymentId().equals(attempt.getPaymentId());
+ return input.getId().equals(attempt.getPaymentId());
}
}));
}
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index 232a448..40b92ef 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -44,7 +44,7 @@ public abstract class TestPaymentDao {
@Test
public void testCreatePayment() {
- PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString())
+ PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID())
.setAmount(BigDecimal.TEN)
.setStatus("Processed")
.setBankIdentificationNumber("1234")
@@ -60,7 +60,7 @@ public abstract class TestPaymentDao {
@Test
public void testUpdatePaymentInfo() {
- PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString())
+ PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID())
.setAmount(BigDecimal.TEN)
.setStatus("Processed")
.setBankIdentificationNumber("1234")
@@ -73,13 +73,13 @@ public abstract class TestPaymentDao {
CallContext context = new TestCallContext("PaymentTests");
paymentDao.savePaymentInfo(paymentInfo, context);
- paymentDao.updatePaymentInfo("CreditCard", paymentInfo.getPaymentId(), "Visa", "US", context);
+ paymentDao.updatePaymentInfo("CreditCard", paymentInfo.getId(), "Visa", "US", context);
}
@Test
public void testUpdatePaymentAttempt() {
PaymentAttempt paymentAttempt = new DefaultPaymentAttempt.Builder().setPaymentAttemptId(UUID.randomUUID())
- .setPaymentId(UUID.randomUUID().toString())
+ .setPaymentId(UUID.randomUUID())
.setInvoiceId(UUID.randomUUID())
.setAccountId(UUID.randomUUID())
.setAmount(BigDecimal.TEN)
@@ -95,14 +95,14 @@ public abstract class TestPaymentDao {
final UUID invoiceId = UUID.randomUUID();
final UUID paymentAttemptId = UUID.randomUUID();
final UUID accountId = UUID.randomUUID();
- final String paymentId = UUID.randomUUID().toString();
+ final UUID paymentId = UUID.randomUUID();
final BigDecimal invoiceAmount = BigDecimal.TEN;
// Move the clock backwards to test the updated_date field (see below)
ClockMock clock = new ClockMock();
CallContext thisContext = new DefaultCallContext("Payment Tests", CallOrigin.TEST, UserType.TEST, clock);
- PaymentAttempt originalPaymentAttempt = new DefaultPaymentAttempt(paymentAttemptId, invoiceId, accountId, invoiceAmount, Currency.USD, clock.getUTCNow(), clock.getUTCNow(), paymentId, 0);
+ PaymentAttempt originalPaymentAttempt = new DefaultPaymentAttempt(paymentAttemptId, invoiceId, accountId, invoiceAmount, Currency.USD, clock.getUTCNow(), clock.getUTCNow(), paymentId, 0, null, null);
PaymentAttempt attempt = paymentDao.createPaymentAttempt(originalPaymentAttempt, thisContext);
List<PaymentAttempt> attemptsFromGet = paymentDao.getPaymentAttemptsForInvoiceId(invoiceId.toString());
@@ -117,7 +117,7 @@ public abstract class TestPaymentDao {
Assert.assertEquals(attempt3, attempt4);
- PaymentInfoEvent originalPaymentInfo = new DefaultPaymentInfoEvent.Builder().setPaymentId(paymentId)
+ PaymentInfoEvent originalPaymentInfo = new DefaultPaymentInfoEvent.Builder().setId(paymentId)
.setAmount(invoiceAmount)
.setStatus("Processed")
.setBankIdentificationNumber("1234")
@@ -133,7 +133,7 @@ public abstract class TestPaymentDao {
Assert.assertEquals(paymentInfo, originalPaymentInfo);
clock.setDeltaFromReality(60 * 60 * 1000); // move clock forward one hour
- paymentDao.updatePaymentInfo(originalPaymentInfo.getPaymentMethod(), originalPaymentInfo.getPaymentId(), originalPaymentInfo.getCardType(), originalPaymentInfo.getCardCountry(), thisContext);
+ paymentDao.updatePaymentInfo(originalPaymentInfo.getPaymentMethod(), originalPaymentInfo.getId(), originalPaymentInfo.getCardType(), originalPaymentInfo.getCardCountry(), thisContext);
paymentInfo = paymentDao.getPaymentInfoList(Arrays.asList(invoiceId.toString())).get(0);
// TODO: replace these asserts
// Assert.assertEquals(paymentInfo.getCreatedDate().compareTo(attempt.getCreatedDate()), 0);
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
index 84e3e5a..7c2fe65 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
@@ -33,9 +33,11 @@ public class TestPaymentDaoWithEmbeddedDb extends TestPaymentDao {
@BeforeClass(groups = { "slow", "database" })
public void startMysql() throws IOException {
final String paymentddl = IOUtils.toString(MysqlTestingHelper.class.getResourceAsStream("/com/ning/billing/payment/ddl.sql"));
+ final String utilddl = IOUtils.toString(MysqlTestingHelper.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
helper.startMysql();
helper.initDb(paymentddl);
+ helper.initDb(utilddl);
}
@AfterClass(groups = { "slow", "database" })
diff --git a/payment/src/test/java/com/ning/billing/payment/MockInvoice.java b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
new file mode 100644
index 0000000..20c0446
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
@@ -0,0 +1,237 @@
+/*
+ * 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;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import com.ning.billing.util.dao.ObjectType;
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.entity.ExtendedEntityBase;
+
+public class MockInvoice extends ExtendedEntityBase implements Invoice {
+ private final List<InvoiceItem> invoiceItems = new ArrayList<InvoiceItem>();
+ private final List<InvoicePayment> payments = new ArrayList<InvoicePayment>();
+ private final UUID accountId;
+ private final Integer invoiceNumber;
+ private final DateTime invoiceDate;
+ private final DateTime targetDate;
+ private final Currency currency;
+ private final boolean migrationInvoice;
+
+ // used to create a new invoice
+ public MockInvoice(UUID accountId, DateTime invoiceDate, DateTime targetDate, Currency currency) {
+ this(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, false);
+ }
+
+ // used to hydrate invoice from persistence layer
+ public MockInvoice(UUID invoiceId, UUID accountId, @Nullable Integer invoiceNumber, DateTime invoiceDate,
+ DateTime targetDate, Currency currency, boolean isMigrationInvoice) {
+ super(invoiceId);
+ this.accountId = accountId;
+ this.invoiceNumber = invoiceNumber;
+ this.invoiceDate = invoiceDate;
+ this.targetDate = targetDate;
+ this.currency = currency;
+ this.migrationInvoice = isMigrationInvoice;
+ }
+
+ @Override
+ public boolean addInvoiceItem(final InvoiceItem item) {
+ return invoiceItems.add(item);
+ }
+
+ @Override
+ public boolean addInvoiceItems(final List<InvoiceItem> items) {
+ return this.invoiceItems.addAll(items);
+ }
+
+ @Override
+ public List<InvoiceItem> getInvoiceItems() {
+ return invoiceItems;
+ }
+
+ @Override
+ public <T extends InvoiceItem> List<InvoiceItem> getInvoiceItems(Class<T> clazz) {
+ List<InvoiceItem> results = new ArrayList<InvoiceItem>();
+ for (InvoiceItem item : invoiceItems) {
+ if ( clazz.isInstance(item) ) {
+ results.add(item);
+ }
+ }
+ return results;
+ }
+
+ @Override
+ public int getNumberOfItems() {
+ return invoiceItems.size();
+ }
+
+ @Override
+ public boolean addPayment(final InvoicePayment payment) {
+ return payments.add(payment);
+ }
+
+ @Override
+ public boolean addPayments(final List<InvoicePayment> payments) {
+ return this.payments.addAll(payments);
+ }
+
+ @Override
+ public List<InvoicePayment> getPayments() {
+ return payments;
+ }
+
+ @Override
+ public int getNumberOfPayments() {
+ return payments.size();
+ }
+
+ @Override
+ public UUID getId() {
+ return id;
+ }
+
+ @Override
+ public UUID getAccountId() {
+ return accountId;
+ }
+
+ /**
+ * null until retrieved from the database
+ * @return the invoice number
+ */
+ @Override
+ public Integer getInvoiceNumber() {
+ return invoiceNumber;
+ }
+
+ @Override
+ public DateTime getInvoiceDate() {
+ return invoiceDate;
+ }
+
+ @Override
+ public DateTime getTargetDate() {
+ return targetDate;
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return currency;
+ }
+
+ @Override
+ public boolean isMigrationInvoice() {
+ return migrationInvoice;
+ }
+
+ @Override
+ public DateTime getLastPaymentAttempt() {
+ DateTime lastPaymentAttempt = null;
+
+ for (final InvoicePayment paymentAttempt : payments) {
+ DateTime paymentAttemptDate = paymentAttempt.getPaymentAttemptDate();
+ if (lastPaymentAttempt == null) {
+ lastPaymentAttempt = paymentAttemptDate;
+ }
+
+ if (lastPaymentAttempt.isBefore(paymentAttemptDate)) {
+ lastPaymentAttempt = paymentAttemptDate;
+ }
+ }
+
+ return lastPaymentAttempt;
+ }
+
+ @Override
+ public BigDecimal getAmountPaid() {
+ BigDecimal amountPaid = BigDecimal.ZERO;
+ for (final InvoicePayment payment : payments) {
+ if (payment.getAmount() != null) {
+ amountPaid = amountPaid.add(payment.getAmount());
+ }
+ }
+ return amountPaid;
+ }
+
+ @Override
+ public BigDecimal getTotalAmount() {
+ BigDecimal result = BigDecimal.ZERO;
+
+ for(InvoiceItem i : invoiceItems) {
+ result = result.add(i.getAmount());
+ }
+ return result;
+ }
+
+ @Override
+ public BigDecimal getBalance() {
+ return getTotalAmount().subtract(getAmountPaid());
+ }
+
+ @Override
+ public boolean isDueForPayment(final DateTime targetDate, final int numberOfDays) {
+ if (getTotalAmount().compareTo(BigDecimal.ZERO) == 0) {
+ return false;
+ }
+
+ DateTime lastPaymentAttempt = getLastPaymentAttempt();
+ if (lastPaymentAttempt == null) {
+ return true;
+ }
+
+ return !lastPaymentAttempt.plusDays(numberOfDays).isAfter(targetDate);
+ }
+
+ @Override
+ public String toString() {
+ return "DefaultInvoice [items=" + invoiceItems + ", payments=" + payments + ", id=" + id + ", accountId=" + accountId + ", invoiceDate=" + invoiceDate + ", targetDate=" + targetDate + ", currency=" + currency + ", amountPaid=" + getAmountPaid() + ", lastPaymentAttempt=" + getLastPaymentAttempt() + "]";
+ }
+
+ @Override
+ public ObjectType getObjectType() {
+ return ObjectType.RECURRING_INVOICE_ITEM;
+ }
+
+ @Override
+ public void saveFieldValue(String fieldName, String fieldValue, CallContext context) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void saveFields(List<CustomField> fields, CallContext context) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clearPersistedFields(CallContext context) {
+ throw new UnsupportedOperationException();
+ }
+}
+
diff --git a/payment/src/test/java/com/ning/billing/payment/MockInvoiceCreationEvent.java b/payment/src/test/java/com/ning/billing/payment/MockInvoiceCreationEvent.java
new file mode 100644
index 0000000..9a700cd
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/MockInvoiceCreationEvent.java
@@ -0,0 +1,157 @@
+/*
+ * 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;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.util.bus.BusEvent.BusEventType;
+
+public class MockInvoiceCreationEvent implements InvoiceCreationEvent {
+
+ private final UUID invoiceId;
+ private final UUID accountId;
+ private final BigDecimal amountOwed;
+ private final Currency currency;
+ private final DateTime invoiceCreationDate;
+ private final UUID userToken;
+
+ @JsonCreator
+ public MockInvoiceCreationEvent(@JsonProperty("invoiceId") UUID invoiceId,
+ @JsonProperty("accountId") UUID accountId,
+ @JsonProperty("amountOwed") BigDecimal amountOwed,
+ @JsonProperty("currency") Currency currency,
+ @JsonProperty("invoiceCreationDate") DateTime invoiceCreationDate,
+ @JsonProperty("userToken") UUID userToken) {
+ this.invoiceId = invoiceId;
+ this.accountId = accountId;
+ this.amountOwed = amountOwed;
+ this.currency = currency;
+ this.invoiceCreationDate = invoiceCreationDate;
+ this.userToken = userToken;
+ }
+
+ @JsonIgnore
+ @Override
+ public BusEventType getBusEventType() {
+ return BusEventType.INVOICE_CREATION;
+ }
+
+ @Override
+ public UUID getUserToken() {
+ return userToken;
+ }
+
+ @Override
+ public UUID getInvoiceId() {
+ return invoiceId;
+ }
+
+ @Override
+ public UUID getAccountId() {
+ return accountId;
+ }
+
+ @Override
+ public BigDecimal getAmountOwed() {
+ return amountOwed;
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return currency;
+ }
+
+ @Override
+ public DateTime getInvoiceCreationDate() {
+ return invoiceCreationDate;
+ }
+
+ @Override
+ public String toString() {
+ return "DefaultInvoiceCreationNotification [invoiceId=" + invoiceId + ", accountId=" + accountId + ", amountOwed=" + amountOwed + ", currency=" + currency + ", invoiceCreationDate=" + invoiceCreationDate + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((accountId == null) ? 0 : accountId.hashCode());
+ result = prime * result
+ + ((amountOwed == null) ? 0 : amountOwed.hashCode());
+ result = prime * result
+ + ((currency == null) ? 0 : currency.hashCode());
+ result = prime
+ * result
+ + ((invoiceCreationDate == null) ? 0 : invoiceCreationDate
+ .hashCode());
+ result = prime * result
+ + ((invoiceId == null) ? 0 : invoiceId.hashCode());
+ result = prime * result
+ + ((userToken == null) ? 0 : userToken.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ MockInvoiceCreationEvent other = (MockInvoiceCreationEvent) obj;
+ if (accountId == null) {
+ if (other.accountId != null)
+ return false;
+ } else if (!accountId.equals(other.accountId))
+ return false;
+ if (amountOwed == null) {
+ if (other.amountOwed != null)
+ return false;
+ } else if (!amountOwed.equals(other.amountOwed))
+ return false;
+ if (currency != other.currency)
+ return false;
+ if (invoiceCreationDate == null) {
+ if (other.invoiceCreationDate != null)
+ return false;
+ } else if (invoiceCreationDate.compareTo(other.invoiceCreationDate) != 0)
+ return false;
+ if (invoiceId == null) {
+ if (other.invoiceId != null)
+ return false;
+ } else if (!invoiceId.equals(other.invoiceId))
+ return false;
+ if (userToken == null) {
+ if (other.userToken != null)
+ return false;
+ } else if (!userToken.equals(other.userToken))
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
new file mode 100644
index 0000000..93c90fa
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
@@ -0,0 +1,264 @@
+/*
+ * 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;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.util.entity.EntityBase;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.joda.time.DateTime;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+public class MockRecurringInvoiceItem extends EntityBase implements InvoiceItem {
+ private final BigDecimal rate;
+ private final UUID reversedItemId;
+ protected final UUID invoiceId;
+ protected final UUID accountId;
+ protected final UUID subscriptionId;
+ protected final UUID bundleId;
+ protected final String planName;
+ protected final String phaseName;
+ protected final DateTime startDate;
+ protected final DateTime endDate;
+ protected final BigDecimal amount;
+ protected final Currency currency;
+
+
+ public MockRecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+ DateTime startDate, DateTime endDate,
+ BigDecimal amount, BigDecimal rate,
+ Currency currency) {
+ this(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, rate, null);
+
+ }
+
+ public MockRecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+ DateTime startDate, DateTime endDate,
+ BigDecimal amount, BigDecimal rate,
+ Currency currency, UUID reversedItemId) {
+ this(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate,
+ amount, currency, rate, reversedItemId);
+ }
+
+ public MockRecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+ DateTime startDate, DateTime endDate,
+ BigDecimal amount, BigDecimal rate,
+ Currency currency) {
+ this(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, rate, null);
+
+ }
+
+ public MockRecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+ DateTime startDate, DateTime endDate,
+ BigDecimal amount, BigDecimal rate,
+ Currency currency, UUID reversedItemId) {
+ this(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, rate, reversedItemId);
+ }
+ public MockRecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+ DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency, BigDecimal rate, UUID reversedItemId){
+ this(UUID.randomUUID(), invoiceId, accountId, bundleId, subscriptionId, planName, phaseName,
+ startDate, endDate, amount, currency, rate, reversedItemId);
+ }
+
+
+ public MockRecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, @Nullable UUID bundleId, @Nullable UUID subscriptionId, String planName, String phaseName,
+ DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
+ BigDecimal rate, UUID reversedItemId) {
+ super(id);
+ this.invoiceId = invoiceId;
+ this.accountId = accountId;
+ this.subscriptionId = subscriptionId;
+ this.bundleId = bundleId;
+ this.planName = planName;
+ this.phaseName = phaseName;
+ this.startDate = startDate;
+ this.endDate = endDate;
+ this.amount = amount;
+ this.currency = currency;
+ this.rate = rate;
+ this.reversedItemId = reversedItemId;
+ }
+
+ @Override
+ public UUID getId() {
+ return id;
+ }
+
+ @Override
+ public UUID getInvoiceId() {
+ return invoiceId;
+ }
+
+ @Override
+ public UUID getBundleId() {
+ return bundleId;
+ }
+
+ public UUID getAccountId() {
+ return accountId;
+ }
+
+ @Override
+ public UUID getSubscriptionId() {
+ return subscriptionId;
+ }
+
+ @Override
+ public String getPlanName() {
+ return planName;
+ }
+
+ @Override
+ public String getPhaseName() {
+ return phaseName;
+ }
+
+ @Override
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ @Override
+ public DateTime getStartDate() {
+ return startDate;
+ }
+
+ @Override
+ public DateTime getEndDate() {
+ return endDate;
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return currency;
+ }
+ @Override
+ public InvoiceItem asReversingItem() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String getDescription() {
+ return String.format("%s from %s to %s", phaseName, startDate.toString(), endDate.toString());
+ }
+
+ public UUID getReversedItemId() {
+ return reversedItemId;
+ }
+
+ public boolean reversesItem() {
+ return (reversedItemId != null);
+ }
+
+ public BigDecimal getRate() {
+ return rate;
+ }
+
+ @Override
+ public int compareTo(InvoiceItem item) {
+ if (item == null) {
+ return -1;
+ }
+ if (!(item instanceof MockRecurringInvoiceItem)) {
+ return -1;
+ }
+
+ MockRecurringInvoiceItem that = (MockRecurringInvoiceItem) item;
+ int compareAccounts = getAccountId().compareTo(that.getAccountId());
+ if (compareAccounts == 0 && bundleId != null) {
+ int compareBundles = getBundleId().compareTo(that.getBundleId());
+ if (compareBundles == 0 && subscriptionId != null) {
+
+ int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
+ if (compareSubscriptions == 0) {
+ int compareStartDates = getStartDate().compareTo(that.getStartDate());
+ if (compareStartDates == 0) {
+ return getEndDate().compareTo(that.getEndDate());
+ } else {
+ return compareStartDates;
+ }
+ } else {
+ return compareSubscriptions;
+ }
+ } else {
+ return compareBundles;
+ }
+ } else {
+ return compareAccounts;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MockRecurringInvoiceItem that = (MockRecurringInvoiceItem) o;
+
+ if (accountId.compareTo(that.accountId) != 0) return false;
+ if (amount.compareTo(that.amount) != 0) return false;
+ if (currency != that.currency) return false;
+ if (startDate.compareTo(that.startDate) != 0) return false;
+ if (endDate.compareTo(that.endDate) != 0) return false;
+ if (!phaseName.equals(that.phaseName)) return false;
+ if (!planName.equals(that.planName)) return false;
+ if (rate.compareTo(that.rate) != 0) return false;
+ if (reversedItemId != null ? !reversedItemId.equals(that.reversedItemId) : that.reversedItemId != null)
+ return false;
+ if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null)
+ return false;
+ if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = accountId.hashCode();
+ result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
+ result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
+ result = 31 * result + planName.hashCode();
+ result = 31 * result + phaseName.hashCode();
+ result = 31 * result + startDate.hashCode();
+ result = 31 * result + endDate.hashCode();
+ result = 31 * result + amount.hashCode();
+ result = 31 * result + rate.hashCode();
+ result = 31 * result + currency.hashCode();
+ result = 31 * result + (reversedItemId != null ? reversedItemId.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(phaseName).append(", ");
+ sb.append(startDate.toString()).append(", ");
+ sb.append(endDate.toString()).append(", ");
+ sb.append(amount.toString()).append(", ");
+ sb.append("subscriptionId = ").append(subscriptionId == null ? null : subscriptionId.toString()).append(", ");
+ sb.append("bundleId = ").append(bundleId == null ? null : bundleId.toString()).append(", ");
+
+ return sb.toString();
+ }
+}
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index e6cda1a..f3cb154 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -44,7 +44,7 @@ import com.ning.billing.util.clock.Clock;
public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
private final AtomicBoolean makeNextInvoiceFail = new AtomicBoolean(false);
- private final Map<String, PaymentInfoEvent> payments = new ConcurrentHashMap<String, PaymentInfoEvent>();
+ private final Map<UUID, PaymentInfoEvent> payments = new ConcurrentHashMap<UUID, PaymentInfoEvent>();
private final Map<String, PaymentProviderAccount> accounts = new ConcurrentHashMap<String, PaymentProviderAccount>();
private final Map<String, PaymentMethodInfo> paymentMethods = new ConcurrentHashMap<String, PaymentMethodInfo>();
private final Clock clock;
@@ -64,7 +64,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("unknown", "test error", account.getId(), invoice.getId(), null));
}
else {
- PaymentInfoEvent payment = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString())
+ PaymentInfoEvent payment = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID())
.setAmount(invoice.getBalance())
.setStatus("Processed")
.setBankIdentificationNumber("1234")
@@ -73,7 +73,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
.setReferenceId("12345")
.setType("Electronic")
.build();
- payments.put(payment.getPaymentId(), payment);
+ payments.put(payment.getId(), payment);
return Either.right(payment);
}
}
diff --git a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java
index cf56d78..da38b34 100644
--- a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java
+++ b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithEmbeddedDb.java
@@ -20,8 +20,6 @@ import org.apache.commons.collections.MapUtils;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Provider;
-import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.account.api.user.DefaultAccountUserApi;
import com.ning.billing.config.PaymentConfig;
import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.mock.BrainDeadProxyFactory;
diff --git a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java
index 8ec8862..14f2ab9 100644
--- a/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java
+++ b/payment/src/test/java/com/ning/billing/payment/setup/PaymentTestModuleWithMocks.java
@@ -16,8 +16,6 @@
package com.ning.billing.payment.setup;
-import com.ning.billing.invoice.api.test.DefaultInvoiceTestApi;
-import com.ning.billing.invoice.api.test.InvoiceTestApi;
import org.apache.commons.collections.MapUtils;
import com.google.common.collect.ImmutableMap;
@@ -25,14 +23,14 @@ import com.google.inject.Provider;
import com.ning.billing.config.PaymentConfig;
import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.mock.BrainDeadProxyFactory;
-import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.glue.MockInvoiceModule;
+import com.ning.billing.mock.glue.MockNotificationQueueModule;
+import com.ning.billing.mock.glue.TestDbiModule;
import com.ning.billing.payment.dao.MockPaymentDao;
import com.ning.billing.payment.dao.PaymentDao;
import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
-import com.ning.billing.util.bus.Bus;
-import com.ning.billing.util.bus.InMemoryBus;
-import com.ning.billing.util.notificationq.MockNotificationQueueService;
-import com.ning.billing.util.notificationq.NotificationQueueService;
+import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.BusModule.BusType;
public class PaymentTestModuleWithMocks extends PaymentModule {
public static class MockProvider implements Provider<BillingApi> {
@@ -62,9 +60,9 @@ public class PaymentTestModuleWithMocks extends PaymentModule {
@Override
protected void configure() {
super.configure();
- bind(Bus.class).to(InMemoryBus.class).asEagerSingleton();
- bind(InvoiceTestApi.class).to(DefaultInvoiceTestApi.class).asEagerSingleton();
-
- bind(NotificationQueueService.class).to(MockNotificationQueueService.class).asEagerSingleton();
+ install(new BusModule(BusType.MEMORY));
+ install(new MockNotificationQueueModule());
+ install(new MockInvoiceModule());
+ install(new TestDbiModule());
}
}
diff --git a/payment/src/test/java/com/ning/billing/payment/TestHelper.java b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
index 93c7080..33dc142 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestHelper.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
@@ -16,24 +16,23 @@
package com.ning.billing.payment;
-import java.math.BigDecimal;
import java.util.UUID;
-import com.ning.billing.invoice.api.test.InvoiceTestApi;
-import com.ning.billing.mock.BrainDeadProxyFactory;
import org.apache.commons.lang.RandomStringUtils;
import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.invoice.api.InvoiceItem;
-import com.ning.billing.invoice.model.DefaultInvoice;
-import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.Bus.EventBusException;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.CallOrigin;
@@ -42,13 +41,15 @@ import com.ning.billing.util.entity.EntityPersistenceException;
public class TestHelper {
protected final AccountUserApi accountUserApi;
- protected final InvoiceTestApi invoiceTestApi;
+ protected final InvoicePaymentApi invoicePaymentApi;
private final CallContext context;
+ private final Bus eventBus;
@Inject
- public TestHelper(CallContextFactory factory, AccountUserApi accountUserApi, InvoiceTestApi invoiceTestApi) {
+ public TestHelper(CallContextFactory factory, AccountUserApi accountUserApi, InvoicePaymentApi invoicePaymentApi, Bus eventBus) {
+ this.eventBus = eventBus;
this.accountUserApi = accountUserApi;
- this.invoiceTestApi = invoiceTestApi;
+ this.invoicePaymentApi = invoicePaymentApi;
context = factory.createCallContext("Princess Buttercup", CallOrigin.TEST, UserType.TEST);
}
@@ -70,13 +71,13 @@ public class TestHelper {
public Invoice createTestInvoice(Account account,
DateTime targetDate,
Currency currency,
- InvoiceItem... items) {
- Invoice invoice = new DefaultInvoice(account.getId(), new DateTime(), targetDate, currency);
+ InvoiceItem... items) throws EventBusException {
+ Invoice invoice = new MockInvoice(account.getId(), new DateTime(), targetDate, currency);
for (InvoiceItem item : items) {
- if (item instanceof RecurringInvoiceItem) {
- RecurringInvoiceItem recurringInvoiceItem = (RecurringInvoiceItem) item;
- invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(),
+ if (item instanceof MockRecurringInvoiceItem) {
+ MockRecurringInvoiceItem recurringInvoiceItem = (MockRecurringInvoiceItem) item;
+ invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(),
account.getId(),
recurringInvoiceItem.getBundleId(),
recurringInvoiceItem.getSubscriptionId(),
@@ -90,21 +91,15 @@ public class TestHelper {
}
}
- invoiceTestApi.create(invoice, context);
- return invoice;
- }
-
- public Invoice createTestInvoice(Account account) {
- final DateTime now = new DateTime(DateTimeZone.UTC);
- final UUID subscriptionId = UUID.randomUUID();
- final UUID bundleId = UUID.randomUUID();
- final BigDecimal amount = new BigDecimal("10.00");
+ // invoiceTestApi.create(invoice, context);
+ ((ZombieControl)invoicePaymentApi).addResult("getInvoice", invoice);
+ InvoiceCreationEvent event = new MockInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
+ invoice.getBalance(), invoice.getCurrency(),
+ invoice.getInvoiceDate(),
+ context.getUserToken());
- final InvoiceItem item = new RecurringInvoiceItem(null, account.getId(), bundleId, subscriptionId, "test plan", "test phase", now, now.plusMonths(1),
- amount, new BigDecimal("1.0"), Currency.USD);
-
-
- return createTestInvoice(account, now, Currency.USD, item);
+ eventBus.post(event);
+ return invoice;
}
public Account createTestAccount(String email) {
@@ -121,6 +116,7 @@ public class TestHelper {
zombie.addResult("getEmail", email);
zombie.addResult("getCurrency", Currency.USD);
zombie.addResult("getBillCycleDay", 1);
+ zombie.addResult("getPaymentProviderName", "");
return account;
}
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 8b7720a..2c519d0 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -40,17 +40,16 @@ import org.testng.annotations.Test;
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
-import com.ning.billing.account.glue.AccountModuleWithMocks;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.config.PaymentConfig;
import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.glue.InvoiceModuleWithMocks;
-import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+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;
import com.ning.billing.payment.api.PaymentStatus;
import com.ning.billing.payment.dao.PaymentDao;
@@ -60,11 +59,13 @@ import com.ning.billing.payment.setup.PaymentTestModuleWithMocks;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.clock.MockClockModule;
+import com.ning.billing.util.glue.CallContextModule;
import com.ning.billing.util.notificationq.MockNotificationQueue;
import com.ning.billing.util.notificationq.Notification;
import com.ning.billing.util.notificationq.NotificationQueueService;
-@Guice(modules = { PaymentTestModuleWithMocks.class, AccountModuleWithMocks.class, InvoiceModuleWithMocks.class, MockJunctionModule.class })
+@Guice(modules = { PaymentTestModuleWithMocks.class, MockClockModule.class, MockJunctionModule.class, CallContextModule.class })
@Test(groups = "fast")
public class TestRetryService {
@Inject
@@ -74,6 +75,8 @@ public class TestRetryService {
@Inject
private PaymentApi paymentApi;
@Inject
+ private InvoicePaymentApi invoicePaymentApi;
+ @Inject
private TestHelper testHelper;
@Inject
private PaymentProviderPluginRegistry registry;
@@ -104,6 +107,8 @@ public class TestRetryService {
mockPaymentProviderPlugin = (MockPaymentProviderPlugin)registry.getPlugin(null);
mockNotificationQueue = (MockNotificationQueue)notificationQueueService.getNotificationQueue(RetryService.SERVICE_NAME, RetryService.QUEUE_NAME);
context = new DefaultCallContext("RetryServiceTests", CallOrigin.INTERNAL, UserType.TEST, clock);
+ ((ZombieControl)invoicePaymentApi).addResult("notifyOfPaymentAttempt", BrainDeadProxyFactory.ZOMBIE_VOID);
+
}
@AfterMethod(alwaysRun = true)
@@ -122,7 +127,7 @@ public class TestRetryService {
final DateTime startDate = clock.getUTCNow();
final DateTime endDate = startDate.plusMonths(1);
- invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(),
+ invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(),
account.getId(),
subscriptionId,
bundleId,
@@ -134,11 +139,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();
@@ -165,7 +172,7 @@ public class TestRetryService {
final DateTime now = clock.getUTCNow();
- invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(),
+ invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(),
account.getId(),
subscriptionId,
bundleId,
@@ -198,7 +205,7 @@ public class TestRetryService {
assertEquals(paymentInfo.getStatus(), PaymentStatus.Processed.toString());
List<PaymentAttempt> updatedAttempts = paymentApi.getPaymentAttemptsForInvoiceId(invoice.getId().toString());
- assertEquals(paymentInfo.getPaymentId(), updatedAttempts.get(0).getPaymentId());
+ assertEquals(paymentInfo.getId(), updatedAttempts.get(0).getPaymentId());
}
}
pom.xml 12(+12 -0)
diff --git a/pom.xml b/pom.xml
index 02b1aa6..7fe6a40 100644
--- a/pom.xml
+++ b/pom.xml
@@ -176,6 +176,18 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
+ <artifactId>killbill-overdue</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-overdue</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
<artifactId>killbill-util</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
server/pom.xml 12(+8 -4)
diff --git a/server/pom.xml b/server/pom.xml
index 4bc0388..e740c10 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -155,10 +155,14 @@
</dependency>
<!-- FROM MASTER POM / LIBRARY -->
- <dependency>
- <groupId>com.ning.billing</groupId>
- <artifactId>killbill-api</artifactId>
- </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-account</artifactId>
+ </dependency>
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-jaxrs</artifactId>
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
index 3ec9e22..227e94a 100644
--- a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
@@ -26,11 +26,11 @@ import com.ning.billing.util.bus.BusService;
import com.ning.jetty.base.modules.ServerModuleBuilder;
import com.ning.jetty.core.listeners.SetupServer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.google.inject.Injector;
import com.google.inject.Module;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.map.SerializationConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,6 +72,9 @@ public class KillbillGuiceListener extends SetupServer
killbillBusService = theInjector.getInstance(BusService.class);
killbilleventHandler = theInjector.getInstance(KillbillEventHandler.class);
+ ObjectMapper mapper = theInjector.getInstance(ObjectMapper.class);
+ mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
+
//
// Fire all Startup levels up to service start
//
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
index 8a9e490..d6c3691 100644
--- a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -17,6 +17,7 @@
package com.ning.billing.server.modules;
import com.ning.billing.util.email.EmailModule;
+import com.ning.billing.util.email.templates.TemplateModule;
import com.ning.billing.util.glue.GlobalLockerModule;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.IDBI;
@@ -26,16 +27,17 @@ import com.ning.billing.account.glue.AccountModule;
import com.ning.billing.analytics.setup.AnalyticsModule;
import com.ning.billing.beatrix.glue.BeatrixModule;
import com.ning.billing.catalog.glue.CatalogModule;
-import com.ning.billing.entitlement.glue.EntitlementModule;
-import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
+import com.ning.billing.invoice.glue.DefaultInvoiceModule;
import com.ning.billing.jaxrs.resources.AccountResource;
import com.ning.billing.jaxrs.resources.BundleResource;
-import com.ning.billing.jaxrs.resources.BundleTimelineResource;
import com.ning.billing.jaxrs.resources.InvoiceResource;
import com.ning.billing.jaxrs.resources.PaymentResource;
import com.ning.billing.jaxrs.resources.SubscriptionResource;
+import com.ning.billing.jaxrs.resources.TagResource;
import com.ning.billing.jaxrs.util.KillbillEventHandler;
-import com.ning.billing.junction.glue.JunctionModule;
+import com.ning.billing.jaxrs.util.TagHelper;
+import com.ning.billing.junction.glue.DefaultJunctionModule;
import com.ning.billing.payment.setup.PaymentModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.CallContextModule;
@@ -60,12 +62,13 @@ public class KillbillServerModule extends AbstractModule
}
protected void configureResources() {
+ bind(TagHelper.class).asEagerSingleton();
bind(AccountResource.class).asEagerSingleton();
bind(BundleResource.class).asEagerSingleton();
bind(SubscriptionResource.class).asEagerSingleton();
- bind(BundleTimelineResource.class).asEagerSingleton();
bind(InvoiceResource.class).asEagerSingleton();
bind(PaymentResource.class).asEagerSingleton();
+ bind(TagResource.class).asEagerSingleton();
bind(KillbillEventHandler.class).asEagerSingleton();
}
@@ -83,12 +86,13 @@ public class KillbillServerModule extends AbstractModule
install(new NotificationQueueModule());
install(new CallContextModule());
install(new AccountModule());
- install(new InvoiceModule());
- install(new EntitlementModule());
+ install(new DefaultInvoiceModule());
+ install(new TemplateModule());
+ install(new DefaultEntitlementModule());
install(new AnalyticsModule());
install(new PaymentModule());
install(new BeatrixModule());
- install(new JunctionModule());
+ install(new DefaultJunctionModule());
installClock();
}
}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
index a74d8df..4b21087 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -16,15 +16,20 @@
package com.ning.billing.jaxrs;
+import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import javax.ws.rs.core.Response.Status;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.PropertyNamingStrategy;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.slf4j.Logger;
@@ -38,7 +43,9 @@ import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.jaxrs.json.AccountJson;
import com.ning.billing.jaxrs.json.AccountTimelineJson;
import com.ning.billing.jaxrs.json.BundleJsonNoSubsciptions;
+import com.ning.billing.jaxrs.json.CustomFieldJson;
import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
+import com.ning.billing.jaxrs.json.TagDefinitionJson;
import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
import com.ning.http.client.Response;
@@ -48,6 +55,8 @@ public class TestAccount extends TestJaxrsBase {
private static final Logger log = LoggerFactory.getLogger(TestAccount.class);
+
+
@Test(groups="slow", enabled=true)
public void testAccountOk() throws Exception {
@@ -138,6 +147,60 @@ public class TestAccount extends TestJaxrsBase {
Assert.assertEquals(objFromJson.getBundles().size(), 1);
Assert.assertEquals(objFromJson.getBundles().get(0).getSubscriptions().size(), 1);
Assert.assertEquals(objFromJson.getBundles().get(0).getSubscriptions().get(0).getEvents().size(), 2);
-
+ }
+
+ @Test(groups="slow", enabled=false)
+ public void testAccountWithTags() throws Exception {
+ //Create Tag definition
+ TagDefinitionJson input = new TagDefinitionJson("yoyo", "nothing more to say");
+ String baseJson = mapper.writeValueAsString(input);
+ Response response = doPost(BaseJaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ AccountJson accountJson = createAccount("couroucoucou", "shdwdsqgfhwe", "couroucoucou@yahoo.com");
+ assertNotNull(accountJson);
+
+ Map<String, String> queryParams = new HashMap<String, String>();
+ queryParams.put(BaseJaxrsResource.QUERY_TAGS, input.getName());
+ String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + BaseJaxrsResource.TAGS + "/" + accountJson.getAcountId() ;
+ response = doPost(uri, null, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ /*
+ * STEPH Some how Location returns the ID twice (confused) :
+ * Location: http://127.0.0.1:8080/1.0/kb/accounts/tags/ebb5f830-6f0a-4521-9553-521d173169be/ebb5f830-6f0a-4521-9553-521d173169be
+ *
+ String location = response.getHeader("Location");
+ Assert.assertNotNull(location);
+
+ // Retrieves by Id based on Location returned
+ response = doGetWithUrl(location, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ */
+
+ }
+
+ @Test(groups="slow", enabled=false)
+ public void testAccountWithCustomFields() throws Exception {
+
+ AccountJson accountJson = createAccount("carafe", "shdwhwgaz", "carafe@yahoo.com");
+ assertNotNull(accountJson);
+
+ List<CustomFieldJson> customFields = new LinkedList<CustomFieldJson>();
+ customFields.add(new CustomFieldJson("1", "value1"));
+ customFields.add(new CustomFieldJson("2", "value2"));
+ customFields.add(new CustomFieldJson("3", "value3"));
+ String baseJson = mapper.writeValueAsString(customFields);
+
+ String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + BaseJaxrsResource.CUSTOM_FIELDS + "/" + accountJson.getAcountId() ;
+ Response response = doPost(uri,baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+ String location = response.getHeader("Location");
+ Assert.assertNotNull(location);
+
+ // Retrieves by Id based on Location returned
+ response = doGetWithUrl(location, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
}
}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
index 0d1f1cd..f0182bd 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
@@ -23,12 +23,12 @@ import java.util.Map;
import javax.ws.rs.core.Response.Status;
-import org.codehaus.jackson.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.ning.billing.jaxrs.json.AccountJson;
import com.ning.billing.jaxrs.json.BundleJsonNoSubsciptions;
import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
new file mode 100644
index 0000000..9a039fd
--- /dev/null
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
@@ -0,0 +1,126 @@
+/*
+ * 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.jaxrs;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.joda.time.DateTime;
+import org.joda.time.Interval;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.BundleJsonNoSubsciptions;
+import com.ning.billing.jaxrs.json.InvoiceJson;
+import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
+import com.ning.http.client.Response;
+
+public class TestInvoice extends TestJaxrsBase {
+
+ private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTime();
+
+ private static final Logger log = LoggerFactory.getLogger(TestInvoice.class);
+
+
+ @Test(groups="slow", enabled=true)
+ public void testInvoiceOk() throws Exception {
+
+ DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+ clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+
+
+ AccountJson accountJson = createAccount("poupou", "qhddffrwe", "poupou@yahoo.com");
+ assertNotNull(accountJson);
+
+ BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAcountId(), "9967599");
+ assertNotNull(bundleJson);
+
+ SubscriptionJsonNoEvents subscriptionJson = createSubscription(bundleJson.getBundleId(), "Shotgun", ProductCategory.BASE.toString(), BillingPeriod.MONTHLY.toString(), true);
+ assertNotNull(subscriptionJson);
+
+ // MOVE AFTER TRIAL
+ Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(3).plusDays(1));
+ clock.addDeltaFromReality(it.toDurationMillis());
+
+ crappyWaitForLackOfProperSynchonization();
+
+ String uri = BaseJaxrsResource.INVOICES_PATH;
+ Map<String, String> queryParams = new HashMap<String, String>();
+ queryParams.put(BaseJaxrsResource.QUERY_ACCOUNT_ID, accountJson.getAcountId());
+
+ Response response = doGet(uri, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+ Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ String baseJson = response.getResponseBody();
+ List<InvoiceJson> objFromJson = mapper.readValue(baseJson, new TypeReference<List<InvoiceJson>>() {});
+ assertNotNull(objFromJson);
+ log.info(baseJson);
+ assertEquals(objFromJson.size(), 4);
+
+ // Check we can retrieve an individual invoice
+ uri = BaseJaxrsResource.INVOICES_PATH + "/" + objFromJson.get(0).getInvoiceId();
+ response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ baseJson = response.getResponseBody();
+ InvoiceJson firstInvoiceJson = mapper.readValue(baseJson, InvoiceJson.class);
+ assertNotNull(objFromJson);
+ assertEquals(firstInvoiceJson, objFromJson.get(0));
+
+ // Then create a dryRun Invoice
+ DateTime futureDate = clock.getUTCNow().plusMonths(1).plusDays(3);
+ uri = BaseJaxrsResource.INVOICES_PATH;
+ queryParams.put(BaseJaxrsResource.QUERY_TARGET_DATE, futureDate.toString());
+ queryParams.put(BaseJaxrsResource.QUERY_DRY_RUN, "true");
+ response = doPost(uri, null, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+ Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ baseJson = response.getResponseBody();
+ InvoiceJson futureInvoice = mapper.readValue(baseJson, InvoiceJson.class);
+ assertNotNull(futureInvoice);
+ log.info(baseJson);
+
+ // The one more time with no DryRun
+ queryParams.remove(BaseJaxrsResource.QUERY_DRY_RUN);
+ response = doPost(uri, null, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+ Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ String location = response.getHeader("Location");
+ Assert.assertNotNull(location);
+
+ // Check again # invoices, should be 5 this time
+ uri = BaseJaxrsResource.INVOICES_PATH;
+ response = doGet(uri, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ baseJson = response.getResponseBody();
+ objFromJson = mapper.readValue(baseJson, new TypeReference<List<InvoiceJson>>() {});
+ assertNotNull(objFromJson);
+ log.info(baseJson);
+ assertEquals(objFromJson.size(), 5);
+ }
+}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index e3c9db4..cf9eddd 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -31,9 +31,9 @@ import java.util.concurrent.TimeUnit;
import javax.ws.rs.core.Response.Status;
import com.ning.billing.util.email.EmailModule;
+import com.ning.billing.util.email.templates.TemplateModule;
import com.ning.billing.util.glue.GlobalLockerModule;
import org.apache.commons.io.IOUtils;
-import org.codehaus.jackson.map.ObjectMapper;
import org.eclipse.jetty.servlet.FilterHolder;
import org.skife.config.ConfigurationObjectFactory;
import org.skife.jdbi.v2.IDBI;
@@ -45,11 +45,15 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.joda.JodaModule;
import com.google.inject.Module;
import com.ning.billing.account.glue.AccountModule;
import com.ning.billing.analytics.setup.AnalyticsModule;
+import com.ning.billing.api.TestApiListener;
import com.ning.billing.beatrix.glue.BeatrixModule;
-import com.ning.billing.beatrix.integration.TestBusHandler;
import com.ning.billing.beatrix.integration.TestIntegration;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.glue.CatalogModule;
@@ -57,13 +61,13 @@ import com.ning.billing.config.PaymentConfig;
import com.ning.billing.dbi.DBIProvider;
import com.ning.billing.dbi.DbiConfig;
import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.entitlement.glue.EntitlementModule;
-import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
+import com.ning.billing.invoice.glue.DefaultInvoiceModule;
import com.ning.billing.jaxrs.json.AccountJson;
import com.ning.billing.jaxrs.json.BundleJsonNoSubsciptions;
import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
-import com.ning.billing.junction.glue.JunctionModule;
+import com.ning.billing.junction.glue.DefaultJunctionModule;
import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
import com.ning.billing.payment.setup.PaymentModule;
import com.ning.billing.server.listeners.KillbillGuiceListener;
@@ -87,7 +91,7 @@ public class TestJaxrsBase {
private final static String PLUGIN_NAME = "noop";
- protected static final int DEFAULT_HTTP_TIMEOUT_SEC = 5;
+ protected static final int DEFAULT_HTTP_TIMEOUT_SEC = 5;
protected static final Map<String, String> DEFAULT_EMPTY_QUERY = new HashMap<String, String>();
@@ -106,8 +110,13 @@ public class TestJaxrsBase {
protected AsyncHttpClient httpClient;
protected ObjectMapper mapper;
protected ClockMock clock;
- protected TestBusHandler busHandler;
+ protected TestApiListener busHandler;
+ // Context informtation to be passed around
+ private static final String createdBy = "Toto";
+ private static final String reason = "i am god";
+ private static final String comment = "no comment";
+
public static void loadSystemPropertiesFromClasspath(final String resource) {
final URL url = TestJaxrsBase.class.getResource(resource);
assertNotNull(url);
@@ -188,12 +197,13 @@ public class TestJaxrsBase {
install(new NotificationQueueModule());
install(new CallContextModule());
install(new AccountModule());
- install(new InvoiceModule());
- install(new EntitlementModule());
+ install(new DefaultInvoiceModule());
+ install(new TemplateModule());
+ install(new DefaultEntitlementModule());
install(new AnalyticsModule());
install(new PaymentMockModule());
install(new BeatrixModule());
- install(new JunctionModule());
+ install(new DefaultJunctionModule());
installClock();
}
@@ -222,7 +232,12 @@ public class TestJaxrsBase {
loadConfig();
httpClient = new AsyncHttpClient();
mapper = new ObjectMapper();
- busHandler = new TestBusHandler(null);
+ mapper.registerModule(new JodaModule());
+ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+
+ mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
+
+ busHandler = new TestApiListener(null);
this.helper = listener.getMysqlTestingHelper();
this.clock = (ClockMock) listener.getClock();
}
@@ -372,8 +387,10 @@ public class TestJaxrsBase {
BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("POST", getUrlFromUri(uri), queryParams);
if (body != null) {
builder.setBody(body);
+ } else {
+ builder.setBody("{}");
}
- return executeAndWait(builder, timeoutSec);
+ return executeAndWait(builder, timeoutSec, true);
}
protected Response doPut(final String uri, final String body, final Map<String, String> queryParams, final int timeoutSec) {
@@ -381,14 +398,16 @@ public class TestJaxrsBase {
BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("PUT", url, queryParams);
if (body != null) {
builder.setBody(body);
+ } else {
+ builder.setBody("{}");
}
- return executeAndWait(builder, timeoutSec);
+ return executeAndWait(builder, timeoutSec, true);
}
protected Response doDelete(final String uri, final Map<String, String> queryParams, final int timeoutSec) {
final String url = String.format("http://%s:%d%s", config.getServerHost(), config.getServerPort(), uri);
BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("DELETE", url, queryParams);
- return executeAndWait(builder, timeoutSec);
+ return executeAndWait(builder, timeoutSec, true);
}
protected Response doGet(final String uri, final Map<String, String> queryParams, final int timeoutSec) {
@@ -398,10 +417,17 @@ public class TestJaxrsBase {
protected Response doGetWithUrl(final String url, final Map<String, String> queryParams, final int timeoutSec) {
BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("GET", url, queryParams);
- return executeAndWait(builder, timeoutSec);
+ return executeAndWait(builder, timeoutSec, false);
}
- private Response executeAndWait(final BoundRequestBuilder builder, final int timeoutSec) {
+ private Response executeAndWait(final BoundRequestBuilder builder, final int timeoutSec, final boolean addContextHeader) {
+
+ if (addContextHeader) {
+ builder.addHeader(BaseJaxrsResource.HDR_CREATED_BY, createdBy);
+ builder.addHeader(BaseJaxrsResource.HDR_REASON, reason);
+ builder.addHeader(BaseJaxrsResource.HDR_COMMENT, comment);
+ }
+
Response response = null;
try {
ListenableFuture<Response> futureStatus =
@@ -465,7 +491,7 @@ public class TestJaxrsBase {
* but until we have a strong need for it, this is in the TODO list...
*/
protected void crappyWaitForLackOfProperSynchonization() throws Exception {
- Thread.sleep(5000);
+ Thread.sleep(7000);
}
}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestTag.java b/server/src/test/java/com/ning/billing/jaxrs/TestTag.java
new file mode 100644
index 0000000..c1f460a
--- /dev/null
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestTag.java
@@ -0,0 +1,114 @@
+/*
+ * 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.jaxrs;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.ning.billing.jaxrs.json.TagDefinitionJson;
+import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
+import com.ning.http.client.Response;
+
+public class TestTag extends TestJaxrsBase {
+
+ private static final Logger log = LoggerFactory.getLogger(TestTag.class);
+
+ @Test(groups="slow", enabled=true)
+ public void testTagDefinitionOk() throws Exception {
+
+ TagDefinitionJson input = new TagDefinitionJson("blue", "realxing color");
+ String baseJson = mapper.writeValueAsString(input);
+ Response response = doPost(BaseJaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ String location = response.getHeader("Location");
+ assertNotNull(location);
+
+ // Retrieves by Id based on Location returned
+ response = doGetWithUrl(location, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
+ baseJson = response.getResponseBody();
+ TagDefinitionJson objFromJson = mapper.readValue(baseJson, TagDefinitionJson.class);
+ assertNotNull(objFromJson);
+ assertEquals(objFromJson, input);
+ }
+
+ @Test(groups="slow", enabled=true)
+ public void testMultipleTagDefinitionOk() throws Exception {
+
+ Response response = doGet(BaseJaxrsResource.TAG_DEFINITIONS_PATH, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ String baseJson = response.getResponseBody();
+
+ List<TagDefinitionJson> objFromJson = mapper.readValue(baseJson, new TypeReference<List<TagDefinitionJson>>() {});
+ int sizeSystemTag = (objFromJson == null || objFromJson.size() == 0) ? 0 : objFromJson.size();
+
+ TagDefinitionJson input = new TagDefinitionJson("blue", "realxing color");
+ baseJson = mapper.writeValueAsString(input);
+ response = doPost(BaseJaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ input = new TagDefinitionJson("red", "hot color");
+ baseJson = mapper.writeValueAsString(input);
+ response = doPost(BaseJaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ input = new TagDefinitionJson("yellow", "vibrant color");
+ baseJson = mapper.writeValueAsString(input);
+ response = doPost(BaseJaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ input = new TagDefinitionJson("green", "super realxing color");
+ baseJson = mapper.writeValueAsString(input);
+ response = doPost(BaseJaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+ response = doGet(BaseJaxrsResource.TAG_DEFINITIONS_PATH, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ baseJson = response.getResponseBody();
+
+ objFromJson = mapper.readValue(baseJson, new TypeReference<List<TagDefinitionJson>>() {});
+ assertNotNull(objFromJson);
+ assertEquals(objFromJson.size(), 4 + sizeSystemTag);
+
+ // STEPH currently broken Tag API does not work as expected...
+
+ /*
+ String uri = BaseJaxrsResource.TAG_DEFINITIONS_PATH + "/green";
+ response = doDelete(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());
+
+ response = doGet(BaseJaxrsResource.TAG_DEFINITIONS_PATH, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+ baseJson = response.getResponseBody();
+
+ objFromJson = mapper.readValue(baseJson, new TypeReference<List<TagDefinitionJson>>() {});
+ assertNotNull(objFromJson);
+ assertEquals(objFromJson.size(), 3 + sizeSystemTag);
+ */
+ }
+
+}
diff --git a/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java b/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java
index 94f5a8d..b9c6faa 100644
--- a/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java
+++ b/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java
@@ -23,13 +23,15 @@ public class BusEventEntry implements NotificationLifecycle {
private final long id;
private final String owner;
+ private final String createdOwner;
private final DateTime nextAvailable;
private final NotificationLifecycleState processingState;
private final String busEventClass;
private final String busEventJson;
- public BusEventEntry(final long id, final String owner, final DateTime nextAvailable, NotificationLifecycleState processingState, final String busEventClass, final String busEventJson) {
+ public BusEventEntry(final long id, final String createdOwner, final String owner, final DateTime nextAvailable, NotificationLifecycleState processingState, final String busEventClass, final String busEventJson) {
this.id = id;
+ this.createdOwner = createdOwner;
this.owner = owner;
this.nextAvailable = nextAvailable;
this.processingState = processingState;
@@ -37,8 +39,8 @@ public class BusEventEntry implements NotificationLifecycle {
this.busEventJson = busEventJson;
}
- public BusEventEntry(final String busEventClass, final String busEventJson) {
- this(0, null, null, null, busEventClass, busEventJson);
+ public BusEventEntry(final String createdOwner, final String busEventClass, final String busEventJson) {
+ this(0, createdOwner, null, null, null, busEventClass, busEventJson);
}
@@ -61,6 +63,11 @@ public class BusEventEntry implements NotificationLifecycle {
}
@Override
+ public String getCreatedOwner() {
+ return createdOwner;
+ }
+
+ @Override
public DateTime getNextAvailableDate() {
return nextAvailable;
}
diff --git a/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java b/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java
index 406a2f8..7da7d08 100644
--- a/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java
@@ -42,7 +42,7 @@ public interface PersistentBusSqlDao extends Transactional<PersistentBusSqlDao>,
@SqlQuery
@Mapper(PersistentBusSqlMapper.class)
- public BusEventEntry getNextBusEventEntry(@Bind("max") int max, @Bind("now") Date now);
+ public BusEventEntry getNextBusEventEntry(@Bind("max") int max, @Bind("owner") String owner, @Bind("now") Date now);
@SqlUpdate
public int claimBusEvent(@Bind("owner") String owner, @Bind("nextAvailable") Date nextAvailable,
@@ -69,6 +69,7 @@ public interface PersistentBusSqlDao extends Transactional<PersistentBusSqlDao>,
stmt.bind("className", evt.getBusEventClass());
stmt.bind("eventJson", evt.getBusEventJson());
stmt.bind("createdDate", getDate(new DateTime()));
+ stmt.bind("creatingOwner", evt.getCreatedOwner());
stmt.bind("processingAvailableDate", getDate(evt.getNextAvailableDate()));
stmt.bind("processingOwner", evt.getOwner());
stmt.bind("processingState", NotificationLifecycleState.AVAILABLE.toString());
@@ -83,12 +84,13 @@ public interface PersistentBusSqlDao extends Transactional<PersistentBusSqlDao>,
final Long recordId = r.getLong("record_id");
final String className = r.getString("class_name");
+ final String createdOwner = r.getString("creating_owner");
final String eventJson = r.getString("event_json");
final DateTime nextAvailableDate = getDate(r, "processing_available_date");
final String processingOwner = r.getString("processing_owner");
final NotificationLifecycleState processingState = NotificationLifecycleState.valueOf(r.getString("processing_state"));
- return new BusEventEntry(recordId, processingOwner, nextAvailableDate, processingState, className, eventJson);
+ return new BusEventEntry(recordId, createdOwner, processingOwner, nextAvailableDate, processingState, className, eventJson);
}
}
}
diff --git a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
index 004e3ab..bfce245 100644
--- a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
+++ b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
@@ -19,11 +19,8 @@ package com.ning.billing.util.bus;
import java.util.Collections;
import java.util.Date;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
@@ -40,11 +37,12 @@ import com.ning.billing.util.Hostname;
import com.ning.billing.util.bus.dao.BusEventEntry;
import com.ning.billing.util.bus.dao.PersistentBusSqlDao;
import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.queue.PersistentQueueBase;
-public class PersistentBus implements Bus {
+public class PersistentBus extends PersistentQueueBase implements Bus {
- private final static int NB_BUS_THREADS = 3;
+ private final static int NB_BUS_THREADS = 1;
private final static long TIMEOUT_MSEC = 15L * 1000L; // 15 sec
private final static long DELTA_IN_PROCESSING_TIME_MS = 1000L * 60L * 5L; // 5 minutes
private final static long SLEEP_TIME_MS = 1000; // 1 sec
@@ -53,16 +51,13 @@ public class PersistentBus implements Bus {
private static final Logger log = LoggerFactory.getLogger(PersistentBus.class);
private final PersistentBusSqlDao dao;
- private final ExecutorService executor;
private final ObjectMapper objectMapper;
private final EventBusDelegate eventBusDelegate;
private final Clock clock;
private final String hostname;
- protected boolean isProcessingEvents;
- private int curActiveThreads;
-
+
private static final class EventBusDelegate extends EventBus {
public EventBusDelegate(String busName) {
@@ -86,110 +81,34 @@ public class PersistentBus implements Bus {
@Inject
public PersistentBus(final IDBI dbi, final Clock clock) {
+ super("Bus", Executors.newFixedThreadPool(NB_BUS_THREADS, new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(new ThreadGroup(DefaultBusService.EVENT_BUS_GROUP_NAME),
+ r,
+ DefaultBusService.EVENT_BUS_TH_NAME);
+ }
+ }), NB_BUS_THREADS, TIMEOUT_MSEC, SLEEP_TIME_MS);
this.dao = dbi.onDemand(PersistentBusSqlDao.class);
this.clock = clock;
this.objectMapper = new ObjectMapper();
this.objectMapper.disable(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS);
this.eventBusDelegate = new EventBusDelegate("Killbill EventBus");
- final ThreadGroup group = new ThreadGroup(DefaultBusService.EVENT_BUS_GROUP_NAME);
- this.executor = Executors.newFixedThreadPool(NB_BUS_THREADS, new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- return new Thread(group, r, DefaultBusService.EVENT_BUS_TH_NAME);
- }
- });
this.hostname = Hostname.get();
- this.isProcessingEvents = false;
}
-
-
@Override
public void start() {
-
- isProcessingEvents = true;
- curActiveThreads = 0;
-
- final PersistentBus thePersistentBus = this;
-
- final CountDownLatch doneInitialization = new CountDownLatch(NB_BUS_THREADS);
-
- for (int i = 0; i < NB_BUS_THREADS; i++) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
-
- log.info(String.format("PersistentBus thread %s [%d] started",
- Thread.currentThread().getName(),
- Thread.currentThread().getId()));
-
- synchronized(thePersistentBus) {
- curActiveThreads++;
- }
-
- doneInitialization.countDown();
-
- try {
- while (true) {
-
- synchronized(thePersistentBus) {
- if (!isProcessingEvents) {
- thePersistentBus.notify();
- break;
- }
- }
-
- try {
- doProcessEvents();
- } catch (Exception e) {
- log.error(String.format("PersistentBus thread %s [%d] got an exception..",
- Thread.currentThread().getName(),
- Thread.currentThread().getId()), e);
- }
- sleepALittle();
- }
- } catch (InterruptedException e) {
- log.info(Thread.currentThread().getName() + " got interrupted, exting...");
- } catch (Throwable e) {
- log.error(Thread.currentThread().getName() + " got an exception exiting...", e);
- // Just to make it really obvious in the log
- e.printStackTrace();
- } finally {
-
- log.info(String.format("PersistentBus thread %s [%d] exited",
- Thread.currentThread().getName(),
- Thread.currentThread().getId()));
-
- synchronized(thePersistentBus) {
- curActiveThreads--;
- }
- }
- }
-
- private void sleepALittle() throws InterruptedException {
- Thread.sleep(SLEEP_TIME_MS);
- }
- });
- }
- try {
- doneInitialization.await(TIMEOUT_MSEC, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- log.warn("PersistentBus start sequence got interrupted...");
- }
+ startQueue();
}
-
-
- private BusEvent deserializeBusEvent(final String className, final String json) {
- try {
- Class<?> claz = Class.forName(className);
- return (BusEvent) objectMapper.readValue(json, claz);
- } catch (Exception e) {
- log.error(String.format("Failed to deserialize json object %s for class %s", json, className), e);
- return null;
- }
+
+ @Override
+ public void stop() {
+ stopQueue();
}
-
- private int doProcessEvents() {
+
+ @Override
+ public int doProcessEvents() {
List<BusEventEntry> events = getNextBusEvent();
if (events.size() == 0) {
@@ -198,22 +117,32 @@ public class PersistentBus implements Bus {
int result = 0;
for (final BusEventEntry cur : events) {
- BusEvent e = deserializeBusEvent(cur.getBusEventClass(), cur.getBusEventJson());
+ BusEvent evt = deserializeBusEvent(cur.getBusEventClass(), cur.getBusEventJson());
result++;
- // STEPH need to look at failure cases
- eventBusDelegate.post(e);
+ // STEPH exception handling is done by GUAVA-- logged a bug Issue-780
+ eventBusDelegate.post(evt);
dao.clearBusEvent(cur.getId(), hostname);
}
return result;
}
+ private BusEvent deserializeBusEvent(final String className, final String json) {
+ try {
+ Class<?> claz = Class.forName(className);
+ return (BusEvent) objectMapper.readValue(json, claz);
+ } catch (Exception e) {
+ log.error(String.format("Failed to deserialize json object %s for class %s", json, className), e);
+ return null;
+ }
+ }
+
private List<BusEventEntry> getNextBusEvent() {
final Date now = clock.getUTCNow().toDate();
final Date nextAvailable = clock.getUTCNow().plus(DELTA_IN_PROCESSING_TIME_MS).toDate();
- BusEventEntry input = dao.getNextBusEventEntry(MAX_BUS_EVENTS, now);
+ BusEventEntry input = dao.getNextBusEventEntry(MAX_BUS_EVENTS, hostname, now);
if (input == null) {
return Collections.emptyList();
}
@@ -226,34 +155,6 @@ public class PersistentBus implements Bus {
return Collections.emptyList();
}
-
- @Override
- public void stop() {
- int remaining = 0;
- try {
- synchronized(this) {
- isProcessingEvents = false;
- long ini = System.currentTimeMillis();
- long remainingWaitTimeMs = TIMEOUT_MSEC;
- while (curActiveThreads > 0 && remainingWaitTimeMs > 0) {
- wait(1000);
- remainingWaitTimeMs = TIMEOUT_MSEC - (System.currentTimeMillis() - ini);
- }
- remaining = curActiveThreads;
- }
-
- } catch (InterruptedException ignore) {
- log.info("PersistentBus has been interrupted during stop sequence");
- } finally {
- if (remaining > 0) {
- log.error(String.format("PersistentBus stopped with %d active remaing threads", remaining));
- } else {
- log.info("PersistentBus completed sucesfully shutdown sequence");
- }
- curActiveThreads = 0;
- }
- }
-
@Override
public void register(Object handlerInstance) throws EventBusException {
eventBusDelegate.register(handlerInstance);
@@ -286,7 +187,7 @@ public class PersistentBus implements Bus {
private void postFromTransaction(BusEvent event, PersistentBusSqlDao transactional) {
try {
String json = objectMapper.writeValueAsString(event);
- BusEventEntry entry = new BusEventEntry(event.getClass().getName(), json);
+ BusEventEntry entry = new BusEventEntry(hostname, event.getClass().getName(), json);
transactional.insertBusEvent(entry);
} catch (Exception e) {
log.error("Failed to post BusEvent " + event.toString(), e);
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java
index accb6b8..b918fac 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java
@@ -28,7 +28,7 @@ public class AuditedCustomFieldDao extends AuditedCollectionDaoBase<CustomField>
private final CustomFieldSqlDao dao;
@Inject
- public AuditedCustomFieldDao(IDBI dbi) {
+ public AuditedCustomFieldDao(final IDBI dbi) {
dao = dbi.onDemand(CustomFieldSqlDao.class);
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditBinder.java b/util/src/main/java/com/ning/billing/util/dao/AuditBinder.java
index 8a9a64e..a518578 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditBinder.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditBinder.java
@@ -37,6 +37,7 @@ public @interface AuditBinder {
return new Binder<AuditBinder, EntityAudit>() {
@Override
public void bind(SQLStatement q, AuditBinder bind, EntityAudit audit) {
+ q.bind("tableName", audit.getTableName().toString());
q.bind("recordId", audit.getRecordId());
q.bind("changeType", audit.getChangeType().toString());
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
index 65bae2d..da6df68 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
@@ -77,7 +77,7 @@ public abstract class AuditedCollectionDaoBase<T extends Entity> implements Audi
Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
- dao.insertAuditFromTransaction(getTableName(), entityAudits, context);
+ dao.insertAuditFromTransaction(entityAudits, context);
}
@Override
@@ -109,7 +109,7 @@ public abstract class AuditedCollectionDaoBase<T extends Entity> implements Audi
for (EntityHistory<T> history : histories) {
Long recordId = history.getValue();
Long historyRecordId = historyRecordIds.get(recordId);
- audits.add(new EntityAudit(historyRecordId, history.getChangeType()));
+ audits.add(new EntityAudit(getTableName(), historyRecordId, history.getChangeType()));
}
return audits;
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
index 72b2db9..d488c6b 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditSqlDao.java
@@ -29,18 +29,16 @@ import java.util.List;
@ExternalizedSqlViaStringTemplate3
public interface AuditSqlDao {
@SqlUpdate
- public void insertAuditFromTransaction(@TableNameBinder final TableName tableName,
- @AuditBinder final EntityAudit audit,
+ public void insertAuditFromTransaction(@AuditBinder final EntityAudit audit,
@CallContextBinder final CallContext context);
@SqlBatch(transactional = false)
- public void insertAuditFromTransaction(@TableNameBinder final TableName tableName,
- @AuditBinder final List<EntityAudit> audit,
+ public void insertAuditFromTransaction(@AuditBinder final List<EntityAudit> audit,
@CallContextBinder final CallContext context);
@SqlQuery
- public Long getRecordId(@TableNameBinder final TableName tableName, @Bind("id") final String id);
+ public Long getRecordId(@Bind("id") final String id);
@SqlQuery
- public Long getHistoryRecordId(@TableNameBinder final TableName tableName, @Bind("recordId") final Long recordId);
+ public Long getHistoryRecordId(@Bind("recordId") final Long recordId);
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/EntityAudit.java b/util/src/main/java/com/ning/billing/util/dao/EntityAudit.java
index f417d00..15280fa 100644
--- a/util/src/main/java/com/ning/billing/util/dao/EntityAudit.java
+++ b/util/src/main/java/com/ning/billing/util/dao/EntityAudit.java
@@ -19,14 +19,20 @@ package com.ning.billing.util.dao;
import com.ning.billing.util.ChangeType;
public class EntityAudit {
+ private final TableName tableName;
private final Long recordId;
private final ChangeType changeType;
- public EntityAudit(Long recordId, ChangeType changeType) {
+ public EntityAudit(TableName tableName, Long recordId, ChangeType changeType) {
+ this.tableName = tableName;
this.recordId = recordId;
this.changeType = changeType;
}
+ public TableName getTableName() {
+ return tableName;
+ }
+
public Long getRecordId() {
return recordId;
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/MapperBase.java b/util/src/main/java/com/ning/billing/util/dao/MapperBase.java
index 3229863..119b727 100644
--- a/util/src/main/java/com/ning/billing/util/dao/MapperBase.java
+++ b/util/src/main/java/com/ning/billing/util/dao/MapperBase.java
@@ -31,6 +31,7 @@ public abstract class MapperBase {
}
protected UUID getUUID(ResultSet resultSet, String fieldName) throws SQLException {
- return UUID.fromString(resultSet.getString(fieldName));
+ String result = resultSet.getString(fieldName);
+ return result == null ? null : UUID.fromString(result);
}
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableName.java b/util/src/main/java/com/ning/billing/util/dao/TableName.java
index 07749e1..28a070a 100644
--- a/util/src/main/java/com/ning/billing/util/dao/TableName.java
+++ b/util/src/main/java/com/ning/billing/util/dao/TableName.java
@@ -23,11 +23,13 @@ public enum TableName {
BUNDLES("bundles"),
CUSTOM_FIELD_HISTORY("custom_field_history"),
ENTITLEMENT_EVENTS("entitlement_events"),
+ FIXED_INVOICE_ITEMS("fixed_invoice_items"),
INVOICE_PAYMENTS("invoice_payments"),
INVOICES("invoices"),
PAYMENT_ATTEMPTS("payment_attempts"),
PAYMENT_HISTORY("payment_history"),
PAYMENTS("payments"),
+ RECURRING_INVOICE_ITEMS("recurring_invoice_items"),
SUBSCRIPTIONS("subscriptions"),
TAG_HISTORY("tag_history");
diff --git a/util/src/main/java/com/ning/billing/util/email/DefaultEmailSender.java b/util/src/main/java/com/ning/billing/util/email/DefaultEmailSender.java
index 103a87b..b4e3587 100644
--- a/util/src/main/java/com/ning/billing/util/email/DefaultEmailSender.java
+++ b/util/src/main/java/com/ning/billing/util/email/DefaultEmailSender.java
@@ -16,16 +16,16 @@
package com.ning.billing.util.email;
-import com.google.inject.Inject;
-import com.ning.billing.ErrorCode;
+import java.util.List;
+
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.List;
+import com.google.inject.Inject;
-public class DefaultEmailSender implements EmailSender {
+public class DefaultEmailSender implements EmailSender {
private final Logger log = LoggerFactory.getLogger(EmailSender.class);
private final EmailConfig config;
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
index dcdfbce..780a34f 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
@@ -35,7 +35,7 @@ public interface EntitySqlDao<T extends Entity> {
public T getById(@Bind("id") final String id);
@SqlQuery
- public Long getRecordId(@Bind("objectId") final String objectId);
+ public Long getRecordId(@Bind("id") final String id);
@SqlQuery
public Long getHistoryRecordId(@Bind("recordId") final Long recordId);
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/UpdatableEntitySqlDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/UpdatableEntitySqlDao.java
index e7ffa15..59bc69e 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/UpdatableEntitySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/UpdatableEntitySqlDao.java
@@ -17,12 +17,13 @@
package com.ning.billing.util.entity.dao;
import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.dao.AuditSqlDao;
import com.ning.billing.util.dao.EntityHistory;
import com.ning.billing.util.entity.Entity;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
// this interface needs to be extended by an interface that provides (externalized) sql and object binders and mappers
-public interface UpdatableEntitySqlDao<T extends Entity> extends EntitySqlDao<T> {
+public interface UpdatableEntitySqlDao<T extends Entity> extends EntitySqlDao<T>, AuditSqlDao {
@SqlUpdate
public void update(final T entity, final CallContext context);
diff --git a/util/src/main/java/com/ning/billing/util/glue/BusModule.java b/util/src/main/java/com/ning/billing/util/glue/BusModule.java
index 2d1d30b..656253d 100644
--- a/util/src/main/java/com/ning/billing/util/glue/BusModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/BusModule.java
@@ -29,8 +29,7 @@ public class BusModule extends AbstractModule {
public BusModule() {
super();
- // Default to Memory at this point
- type = BusType.MEMORY;
+ type = BusType.PERSISTENT;
}
public BusModule(BusType type) {
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
index f3cecc1..1ae51ee 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
@@ -49,14 +49,14 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
//
@SqlQuery
@Mapper(NotificationSqlMapper.class)
- public List<Notification> getReadyNotifications(@Bind("now") Date now, @Bind("max") int max, @Bind("queueName") String queueName);
+ public List<Notification> getReadyNotifications(@Bind("now") Date now, @Bind("owner") String owner, @Bind("max") int max, @Bind("queueName") String queueName);
@SqlUpdate
public int claimNotification(@Bind("owner") String owner, @Bind("nextAvailable") Date nextAvailable,
- @Bind("recordId") long id, @Bind("now") Date now);
+ @Bind("id") String id, @Bind("now") Date now);
@SqlUpdate
- public void clearNotification(@Bind("recordId") long id, @Bind("owner") String owner);
+ public void clearNotification(@Bind("id") String id, @Bind("owner") String owner);
@SqlUpdate
public void removeNotificationsByKey(@Bind("notificationKey") String key);
@@ -65,14 +65,14 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
public void insertNotification(@Bind(binder = NotificationSqlDaoBinder.class) Notification evt);
@SqlUpdate
- public void insertClaimedHistory(@Bind("sequenceId") int sequenceId, @Bind("owner") String owner,
- @Bind("claimedDate") Date claimedDate, @Bind("notificationId") String notificationId);
+ public void insertClaimedHistory(@Bind("ownerId") String ownerId, @Bind("claimedDate") Date claimedDate, @Bind("notificationId") String notificationId);
public static class NotificationSqlDaoBinder extends BinderBase implements Binder<Bind, Notification> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Notification evt) {
- stmt.bind("id", evt.getUUID().toString());
+ stmt.bind("id", evt.getId().toString());
stmt.bind("createdDate", getDate(new DateTime()));
+ stmt.bind("creatingOwner", evt.getCreatedOwner());
stmt.bind("notificationKey", evt.getNotificationKey());
stmt.bind("effectiveDate", getDate(evt.getEffectiveDate()));
stmt.bind("queueName", evt.getQueueName());
@@ -88,8 +88,9 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
public Notification map(int index, ResultSet r, StatementContext ctx)
throws SQLException {
- final Long recordId = r.getLong("record_id");
+ final Long ordering = r.getLong("record_id");
final UUID id = getUUID(r, "id");
+ final String createdOwner = r.getString("creating_owner");
final String notificationKey = r.getString("notification_key");
final String queueName = r.getString("queue_name");
final DateTime effectiveDate = getDate(r, "effective_date");
@@ -97,7 +98,7 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
final String processingOwner = r.getString("processing_owner");
final NotificationLifecycleState processingState = NotificationLifecycleState.valueOf(r.getString("processing_state"));
- return new DefaultNotification(recordId, id, processingOwner, queueName, nextAvailableDate,
+ return new DefaultNotification(ordering, id, createdOwner, processingOwner, queueName, nextAvailableDate,
processingState, notificationKey, effectiveDate);
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
index 26e6c4e..d6f1453 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
@@ -18,13 +18,13 @@ package com.ning.billing.util.notificationq;
import java.util.UUID;
+import com.ning.billing.util.entity.EntityBase;
import org.joda.time.DateTime;
-public class DefaultNotification implements Notification {
-
- private final long id;
- private final UUID uuid;
+public class DefaultNotification extends EntityBase implements Notification {
+ private final long ordering;
private final String owner;
+ private final String createdOwner;
private final String queueName;
private final DateTime nextAvailableDate;
private final NotificationLifecycleState lifecycleState;
@@ -32,13 +32,13 @@ public class DefaultNotification implements Notification {
private final DateTime effectiveDate;
- public DefaultNotification(long id, UUID uuid, String owner, String queueName, DateTime nextAvailableDate,
+ public DefaultNotification(long ordering, UUID id, String createdOwner, String owner, String queueName, DateTime nextAvailableDate,
NotificationLifecycleState lifecycleState,
String notificationKey, DateTime effectiveDate) {
- super();
- this.id = id;
- this.uuid = uuid;
+ super(id);
+ this.ordering = ordering;
this.owner = owner;
+ this.createdOwner = createdOwner;
this.queueName = queueName;
this.nextAvailableDate = nextAvailableDate;
this.lifecycleState = lifecycleState;
@@ -46,17 +46,12 @@ public class DefaultNotification implements Notification {
this.effectiveDate = effectiveDate;
}
- @Override
- public long getId() {
- return id;
- }
-
- public DefaultNotification(String queueName, String notificationKey, DateTime effectiveDate) {
- this(-1L, UUID.randomUUID(), null, queueName, null, NotificationLifecycleState.AVAILABLE, notificationKey, effectiveDate);
+ public DefaultNotification(String queueName, String createdOwner, String notificationKey, DateTime effectiveDate) {
+ this(-1L, UUID.randomUUID(), createdOwner, null, queueName, null, NotificationLifecycleState.AVAILABLE, notificationKey, effectiveDate);
}
@Override
- public UUID getUUID() {
- return uuid;
+ public Long getOrdering() {
+ return ordering;
}
@Override
@@ -108,4 +103,8 @@ public class DefaultNotification implements Notification {
return queueName;
}
+ @Override
+ public String getCreatedOwner() {
+ return createdOwner;
+ }
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
index 392a218..4f114b6 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
@@ -41,10 +41,10 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
}
@Override
- protected int doProcessEvents(final int sequenceId) {
+ public int doProcessEvents() {
logDebug("ENTER doProcessEvents");
- List<Notification> notifications = getReadyNotifications(sequenceId);
+ List<Notification> notifications = getReadyNotifications();
if (notifications.size() == 0) {
logDebug("EXIT doProcessEvents");
return 0;
@@ -56,19 +56,19 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
for (final Notification cur : notifications) {
nbProcessedEvents.incrementAndGet();
logDebug("handling notification %s, key = %s for time %s",
- cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
+ cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
handler.handleReadyNotification(cur.getNotificationKey(), cur.getEffectiveDate());
result++;
clearNotification(cur);
logDebug("done handling notification %s, key = %s for time %s",
- cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
+ cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
}
return result;
}
@Override
public void recordFutureNotification(DateTime futureNotificationTime, NotificationKey notificationKey) {
- Notification notification = new DefaultNotification(getFullQName(), notificationKey.toString(), futureNotificationTime);
+ Notification notification = new DefaultNotification(getFullQName(), hostname, notificationKey.toString(), futureNotificationTime);
dao.insertNotification(notification);
}
@@ -76,32 +76,32 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
public void recordFutureNotificationFromTransaction(final Transmogrifier transactionalDao,
final DateTime futureNotificationTime, final NotificationKey notificationKey) {
NotificationSqlDao transactionalNotificationDao = transactionalDao.become(NotificationSqlDao.class);
- Notification notification = new DefaultNotification(getFullQName(), notificationKey.toString(), futureNotificationTime);
+ Notification notification = new DefaultNotification(getFullQName(), hostname, notificationKey.toString(), futureNotificationTime);
transactionalNotificationDao.insertNotification(notification);
}
private void clearNotification(final Notification cleared) {
- dao.clearNotification(cleared.getId(), hostname);
+ dao.clearNotification(cleared.getId().toString(), hostname);
}
- private List<Notification> getReadyNotifications(final int seqId) {
+ private List<Notification> getReadyNotifications() {
final Date now = clock.getUTCNow().toDate();
final Date nextAvailable = clock.getUTCNow().plus(config.getDaoClaimTimeMs()).toDate();
- List<Notification> input = dao.getReadyNotifications(now, config.getDaoMaxReadyEvents(), getFullQName());
+ List<Notification> input = dao.getReadyNotifications(now, hostname, config.getDaoMaxReadyEvents(), getFullQName());
List<Notification> claimedNotifications = new ArrayList<Notification>();
for (Notification cur : input) {
logDebug("about to claim notification %s, key = %s for time %s",
- cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
- final boolean claimed = (dao.claimNotification(hostname, nextAvailable, cur.getId(), now) == 1);
+ cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
+ final boolean claimed = (dao.claimNotification(hostname, nextAvailable, cur.getId().toString(), now) == 1);
logDebug("claimed notification %s, key = %s for time %s result = %s",
- cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate(), Boolean.valueOf(claimed));
+ cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate(), Boolean.valueOf(claimed));
if (claimed) {
claimedNotifications.add(cur);
- dao.insertClaimedHistory(seqId, hostname, now, cur.getUUID().toString());
+ dao.insertClaimedHistory(hostname, now, cur.getId().toString());
}
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/Notification.java b/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
index d59098b..bd3169a 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
@@ -16,22 +16,15 @@
package com.ning.billing.util.notificationq;
-import java.util.UUID;
-
+import com.ning.billing.util.entity.Entity;
import org.joda.time.DateTime;
-
-public interface Notification extends NotificationLifecycle {
-
- public long getId();
-
- public UUID getUUID();
+public interface Notification extends NotificationLifecycle, Entity {
+ public Long getOrdering();
public String getNotificationKey();
public DateTime getEffectiveDate();
public String getQueueName();
-
-
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java
index 32cba9d..0110cf5 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java
@@ -29,6 +29,8 @@ public interface NotificationLifecycle {
}
public String getOwner();
+
+ public String getCreatedOwner();
public DateTime getNextAvailableDate();
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java
index 14b68e0..d5c2425 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java
@@ -22,8 +22,9 @@ import org.joda.time.DateTime;
import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
+import com.ning.billing.util.queue.QueueLifecycle;
-public interface NotificationQueue {
+public interface NotificationQueue extends QueueLifecycle {
/**
*
@@ -61,25 +62,9 @@ public interface NotificationQueue {
public int processReadyNotification();
/**
- * Stops the queue. Blocks until queue is completely stopped.
- *
- * @see NotificationQueueHandler.completedQueueStop to be notified when the notification thread exited
- */
- public void stopQueue();
-
- /**
- * Starts the queue. Blocks until queue has completely started.
- *
- * @see NotificationQueueHandler.completedQueueStart to be notified when the notification thread started
- */
- public void startQueue();
-
- /**
*
* @return the name of that queue
*/
public String getFullQName();
-
-
}
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
index eb3f269..7c82db6 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
@@ -17,10 +17,8 @@
package com.ning.billing.util.notificationq;
import java.lang.Thread.UncaughtExceptionHandler;
-import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
@@ -30,48 +28,30 @@ import com.ning.billing.config.NotificationConfig;
import com.ning.billing.util.Hostname;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
+import com.ning.billing.util.queue.PersistentQueueBase;
-public abstract class NotificationQueueBase implements NotificationQueue {
+public abstract class NotificationQueueBase extends PersistentQueueBase implements NotificationQueue {
protected final static Logger log = LoggerFactory.getLogger(NotificationQueueBase.class);
- private static final long MAX_NOTIFICATION_THREAD_WAIT_MS = 10000; // 10 secs
- private static final long NOTIFICATION_THREAD_WAIT_INCREMENT_MS = 1000; // 1 sec
- private static final long NANO_TO_MS = (1000 * 1000);
-
protected static final String NOTIFICATION_THREAD_PREFIX = "Notification-";
- protected final long STOP_WAIT_TIMEOUT_MS = 60000;
+ protected static final long STOP_WAIT_TIMEOUT_MS = 60000;
protected final String svcName;
protected final String queueName;
protected final NotificationQueueHandler handler;
protected final NotificationConfig config;
- protected final Executor executor;
protected final Clock clock;
protected final String hostname;
- protected static final AtomicInteger sequenceId = new AtomicInteger();
-
protected AtomicLong nbProcessedEvents;
- // Use this object's monitor for synchronization (no need for volatile)
- protected boolean isProcessingEvents;
-
- private boolean startedComplete = false;
- private boolean stoppedComplete = false;
-
// Package visibility on purpose
NotificationQueueBase(final Clock clock, final String svcName, final String queueName, final NotificationQueueHandler handler, final NotificationConfig config) {
- this.clock = clock;
- this.svcName = svcName;
- this.queueName = queueName;
- this.handler = handler;
- this.config = config;
- this.hostname = Hostname.get();
+ super(svcName, Executors.newFixedThreadPool(1, new ThreadFactory() {
- this.executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread th = new Thread(r);
@@ -84,103 +64,21 @@ public abstract class NotificationQueueBase implements NotificationQueue {
});
return th;
}
- });
- }
-
+ }), 1, STOP_WAIT_TIMEOUT_MS, config.getNotificationSleepTimeMs());
- @Override
- public int processReadyNotification() {
- return doProcessEvents(sequenceId.incrementAndGet());
+ this.clock = clock;
+ this.svcName = svcName;
+ this.queueName = queueName;
+ this.handler = handler;
+ this.config = config;
+ this.hostname = Hostname.get();
+ this.nbProcessedEvents = new AtomicLong();
}
@Override
- public void stopQueue() {
- if (config.isNotificationProcessingOff()) {
- completedQueueStop();
- return;
- }
-
- synchronized(this) {
- isProcessingEvents = false;
- try {
- log.info("NotificationQueue requested to stop");
- wait(STOP_WAIT_TIMEOUT_MS);
- log.info("NotificationQueue requested should have exited");
- } catch (InterruptedException e) {
- log.warn("NotificationQueue got interrupted exception when stopping notifications", e);
- }
- }
- waitForNotificationStopCompletion();
- }
-
- @Override
- public void startQueue() {
-
- this.isProcessingEvents = true;
- this.nbProcessedEvents = new AtomicLong();
-
-
- if (config.isNotificationProcessingOff()) {
- log.warn(String.format("KILLBILL NOTIFICATION PROCESSING FOR SVC %s IS OFF !!!", getFullQName()));
- completedQueueStart();
- return;
- }
- final NotificationQueueBase notificationQueue = this;
-
- executor.execute(new Runnable() {
- @Override
- public void run() {
-
- log.info(String.format("NotificationQueue thread %s [%d] started",
- Thread.currentThread().getName(),
- Thread.currentThread().getId()));
-
- // Thread is now started, notify the listener
- completedQueueStart();
-
- try {
- while (true) {
-
- synchronized (notificationQueue) {
- if (!isProcessingEvents) {
- log.info(String.format("NotificationQueue has been requested to stop, thread %s [%d] stopping...",
- Thread.currentThread().getName(),
- Thread.currentThread().getId()));
- notificationQueue.notify();
- break;
- }
- }
-
- // Callback may trigger exceptions in user code so catch anything here and live with it.
- try {
- doProcessEvents(sequenceId.getAndIncrement());
- } catch (Exception e) {
- log.error(String.format("NotificationQueue thread %s [%d] got an exception..",
- Thread.currentThread().getName(),
- Thread.currentThread().getId()), e);
- }
- sleepALittle();
- }
- } catch (InterruptedException e) {
- log.warn(Thread.currentThread().getName() + " got interrupted ", e);
- } catch (Throwable e) {
- log.error(Thread.currentThread().getName() + " got an exception exiting...", e);
- // Just to make it really obvious in the log
- e.printStackTrace();
- } finally {
- completedQueueStop();
- log.info(String.format("NotificationQueue thread %s [%d] exited...",
- Thread.currentThread().getName(),
- Thread.currentThread().getId()));
- }
- }
-
- private void sleepALittle() throws InterruptedException {
- Thread.sleep(config.getNotificationSleepTimeMs());
- }
- });
- waitForNotificationStartCompletion();
+ public int processReadyNotification() {
+ return doProcessEvents();
}
@Override
@@ -188,61 +86,12 @@ public abstract class NotificationQueueBase implements NotificationQueue {
return getFullQName();
}
- private void completedQueueStop() {
- synchronized (this) {
- stoppedComplete = true;
- this.notifyAll();
- }
- }
-
- private void completedQueueStart() {
- synchronized (this) {
- startedComplete = true;
- this.notifyAll();
- }
- }
-
- private void waitForNotificationStartCompletion() {
- waitForNotificationEventCompletion(true);
- }
-
- private void waitForNotificationStopCompletion() {
- waitForNotificationEventCompletion(false);
- }
-
- private void waitForNotificationEventCompletion(boolean startEvent) {
-
- long ini = System.nanoTime();
- synchronized(this) {
- do {
- if ((startEvent ? startedComplete : stoppedComplete)) {
- break;
- }
- try {
- this.wait(NOTIFICATION_THREAD_WAIT_INCREMENT_MS);
- } catch (InterruptedException e ) {
- Thread.currentThread().interrupt();
- throw new NotificationError(e);
- }
- } while (!(startEvent ? startedComplete : stoppedComplete) &&
- (System.nanoTime() - ini) / NANO_TO_MS < MAX_NOTIFICATION_THREAD_WAIT_MS);
-
- if (!(startEvent ? startedComplete : stoppedComplete)) {
- log.error("Could not {} notification thread in {} msec !!!",
- (startEvent ? "start" : "stop"),
- MAX_NOTIFICATION_THREAD_WAIT_MS);
- throw new NotificationError("Failed to start service!!");
- }
- log.info("Notification thread has been {} in {} ms",
- (startEvent ? "started" : "stopped"),
- (System.nanoTime() - ini) / NANO_TO_MS);
- }
- }
@Override
public String getFullQName() {
return svcName + ":" + queueName;
}
- protected abstract int doProcessEvents(int sequenceId);
+ @Override
+ public abstract int doProcessEvents();
}
diff --git a/util/src/main/java/com/ning/billing/util/queue/PersistentQueueBase.java b/util/src/main/java/com/ning/billing/util/queue/PersistentQueueBase.java
new file mode 100644
index 0000000..a6844ad
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/queue/PersistentQueueBase.java
@@ -0,0 +1,159 @@
+/*
+ * 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.util.queue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public abstract class PersistentQueueBase implements QueueLifecycle {
+
+ private static final Logger log = LoggerFactory.getLogger(PersistentQueueBase.class);
+
+ private final int nbThreads;
+ private final Executor executor;
+ private final String svcName;
+ private final long sleepTimeMs;
+ private final long waitTimeoutMs;
+
+ private boolean isProcessingEvents;
+ private int curActiveThreads;
+
+ public PersistentQueueBase(final String svcName, final Executor executor, final int nbThreads, final long waitTimeoutMs, final long sleepTimeMs) {
+ this.executor = executor;
+ this.nbThreads = nbThreads;
+ this.svcName = svcName;
+ this.waitTimeoutMs = waitTimeoutMs;
+ this.sleepTimeMs = sleepTimeMs;
+ this.isProcessingEvents = false;
+ this.curActiveThreads = 0;
+ }
+
+ @Override
+ public void startQueue() {
+
+ isProcessingEvents = true;
+ curActiveThreads = 0;
+
+ final PersistentQueueBase thePersistentQ = this;
+ final CountDownLatch doneInitialization = new CountDownLatch(nbThreads);
+
+ log.info(String.format("%s: Starting with %d threads",
+ svcName, nbThreads));
+
+ for (int i = 0; i < nbThreads; i++) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+
+ log.info(String.format("%s: Thread %s [%d] starting",
+ svcName,
+ Thread.currentThread().getName(),
+ Thread.currentThread().getId()));
+
+ synchronized(thePersistentQ) {
+ curActiveThreads++;
+ }
+
+ doneInitialization.countDown();
+
+ try {
+ while (true) {
+
+ synchronized(thePersistentQ) {
+ if (!isProcessingEvents) {
+ thePersistentQ.notify();
+ break;
+ }
+ }
+
+ try {
+ doProcessEvents();
+ } catch (Exception e) {
+ log.warn(String.format("%s: Thread %s [%d] got an exception, catching and moving on...",
+ svcName,
+ Thread.currentThread().getName(),
+ Thread.currentThread().getId()), e);
+ }
+ sleepALittle();
+ }
+ } catch (InterruptedException e) {
+ log.info(String.format("%s: Thread %s got interrupted, exting... ", svcName, Thread.currentThread().getName()));
+ } catch (Throwable e) {
+ log.error(String.format("%s: Thread %s got an exception, exting... ", svcName, Thread.currentThread().getName()), e);
+ } finally {
+
+ log.info(String.format("%s: Thread %s has exited", svcName, Thread.currentThread().getName()));
+ synchronized(thePersistentQ) {
+ curActiveThreads--;
+ }
+ }
+ }
+
+ private void sleepALittle() throws InterruptedException {
+ Thread.sleep(sleepTimeMs);
+ }
+ });
+ }
+ try {
+ boolean success = doneInitialization.await(sleepTimeMs, TimeUnit.MILLISECONDS);
+ if (!success) {
+
+ log.warn(String.format("%s: Failed to wait for all threads to be started, got %d/%d", svcName, (nbThreads - doneInitialization.getCount()), nbThreads));
+ } else {
+ log.info(String.format("%s: Done waiting for all threads to be started, got %d/%d", svcName, (nbThreads - doneInitialization.getCount()), nbThreads));
+ }
+ } catch (InterruptedException e) {
+ log.warn(String.format("%s: Start sequence, got interrupted", svcName));
+ }
+ }
+
+
+ @Override
+ public void stopQueue() {
+ int remaining = 0;
+ try {
+ synchronized(this) {
+ isProcessingEvents = false;
+ long ini = System.currentTimeMillis();
+ long remainingWaitTimeMs = waitTimeoutMs;
+ while (curActiveThreads > 0 && remainingWaitTimeMs > 0) {
+ wait(1000);
+ remainingWaitTimeMs = waitTimeoutMs - (System.currentTimeMillis() - ini);
+ }
+ remaining = curActiveThreads;
+ }
+
+ } catch (InterruptedException ignore) {
+ log.info(String.format("%s: Stop sequence has been interrupted, remaining active threads = %d", svcName, curActiveThreads));
+ } finally {
+ if (remaining > 0) {
+ log.error(String.format("%s: Stop sequence completed with %d active remaing threads", svcName, curActiveThreads));
+ } else {
+ log.info(String.format("%s: Stop sequence completed with %d active remaing threads", svcName, curActiveThreads));
+ }
+ curActiveThreads = 0;
+ }
+ }
+
+
+ @Override
+ public abstract int doProcessEvents();
+}
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
index 4a5741d..a9a2373 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
@@ -72,7 +72,7 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag> implements TagD
List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId);
Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
- tagSqlDao.insertAuditFromTransaction(getTableName(), entityAudits, context);
+ tagSqlDao.insertAuditFromTransaction(entityAudits, context);
return null;
}
@@ -108,7 +108,7 @@ public class AuditedTagDao extends AuditedCollectionDaoBase<Tag> implements TagD
List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId);
Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
- tagSqlDao.insertAuditFromTransaction(getTableName(), entityAudits, context);
+ tagSqlDao.insertAuditFromTransaction(entityAudits, context);
return null;
}
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java
index 2416b21..d2d4a6f 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java
@@ -22,8 +22,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import com.google.inject.Inject;
-import com.ning.billing.util.clock.Clock;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.sqlobject.Binder;
import org.skife.jdbi.v2.sqlobject.BinderFactory;
diff --git a/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg
index de6ce41..0cbd4ec 100644
--- a/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg
@@ -6,6 +6,7 @@ getNextBusEventEntry() ::= <<
, class_name
, event_json
, created_date
+ , creating_owner
, processing_owner
, processing_available_date
, processing_state
@@ -59,6 +60,7 @@ insertBusEvent() ::= <<
class_name
, event_json
, created_date
+ , creating_owner
, processing_owner
, processing_available_date
, processing_state
@@ -66,6 +68,7 @@ insertBusEvent() ::= <<
:className
, :eventJson
, :createdDate
+ , :creatingOwner
, :processingOwner
, :processingAvailableDate
, :processingState
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index ebade12..9ea7c1a 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -103,6 +103,7 @@ CREATE TABLE notifications (
id char(36) NOT NULL,
created_date datetime NOT NULL,
notification_key varchar(256) NOT NULL,
+ creating_owner char(50) NOT NULL,
effective_date datetime NOT NULL,
queue_name char(64) NOT NULL,
processing_owner char(50) DEFAULT NULL,
@@ -118,7 +119,6 @@ CREATE INDEX `idx_get_ready` ON notifications (`effective_date`,`created_date`,
DROP TABLE IF EXISTS claimed_notifications;
CREATE TABLE claimed_notifications (
record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
- sequence_id int(11) unsigned NOT NULL,
owner_id varchar(64) NOT NULL,
claimed_date datetime NOT NULL,
notification_id char(36) NOT NULL,
@@ -145,8 +145,9 @@ DROP TABLE IF EXISTS bus_events;
CREATE TABLE bus_events (
record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
class_name varchar(128) NOT NULL,
- event_json varchar(1024) NOT NULL,
+ event_json varchar(2048) NOT NULL,
created_date datetime NOT NULL,
+ creating_owner char(50) NOT NULL,
processing_owner char(50) DEFAULT NULL,
processing_available_date datetime DEFAULT NULL,
processing_state varchar(14) DEFAULT 'AVAILABLE',
diff --git a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
index 0ea9bd6..0731adc 100644
--- a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
@@ -6,6 +6,7 @@ getReadyNotifications() ::= <<
, id
, notification_key
, created_date
+ , creating_owner
, effective_date
, queue_name
, processing_owner
@@ -26,7 +27,6 @@ getReadyNotifications() ::= <<
;
>>
-
claimNotification() ::= <<
update notifications
set
@@ -34,7 +34,7 @@ claimNotification() ::= <<
, processing_available_date = :nextAvailable
, processing_state = 'IN_PROCESSING'
where
- record_id = :recordId
+ id = :id
and processing_state != 'PROCESSED'
and processing_state != 'REMOVED'
and (processing_owner IS NULL OR processing_available_date \<= :now)
@@ -46,7 +46,7 @@ clearNotification() ::= <<
set
processing_state = 'PROCESSED'
where
- record_id = :recordId
+ id = :id
;
>>
@@ -59,12 +59,12 @@ removeNotificationsByKey() ::= <<
;
>>
-
insertNotification() ::= <<
insert into notifications (
id
, notification_key
, created_date
+ , creating_owner
, effective_date
, queue_name
, processing_owner
@@ -74,6 +74,7 @@ insertNotification() ::= <<
:id
, :notificationKey
, :createdDate
+ , :creatingOwner
, :effectiveDate
, :queueName
, :processingOwner
@@ -82,16 +83,13 @@ insertNotification() ::= <<
);
>>
-
insertClaimedHistory() ::= <<
insert into claimed_notifications (
- sequence_id
- , owner_id
+ owner_id
, claimed_date
, notification_id
) values (
- :sequenceId
- , :owner
+ :ownerId
, :claimedDate
, :notificationId
);
diff --git a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
index 1b0d9f6..c68c759 100644
--- a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
@@ -158,10 +158,14 @@ public class MysqlTestingHelper
public void stopMysql()
{
- if (mysqldResource != null) {
- mysqldResource.shutdown();
- FileUtils.deleteQuietly(dbDir);
- log.info("MySQLd stopped");
+ try {
+ if (mysqldResource != null) {
+ mysqldResource.shutdown();
+ FileUtils.deleteQuietly(dbDir);
+ log.info("MySQLd stopped");
+ }
+ } catch (Exception ex) {
+ //fail silently
}
}
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockDbHelperModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockDbHelperModule.java
index 0487e0d..232c4e8 100644
--- a/util/src/test/java/com/ning/billing/mock/glue/MockDbHelperModule.java
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockDbHelperModule.java
@@ -32,7 +32,7 @@ public class MockDbHelperModule extends AbstractModule {
installMysqlTestingHelper();
}
- protected void installMysqlTestingHelper() {
+ public void installMysqlTestingHelper() {
final MysqlTestingHelper helper = new MysqlTestingHelper();
bind(MysqlTestingHelper.class).toInstance(helper);
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java
index 4a813c4..044618e 100644
--- a/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockEntitlementModule.java
@@ -20,25 +20,43 @@ import com.google.inject.AbstractModule;
import com.ning.billing.entitlement.api.EntitlementService;
import com.ning.billing.entitlement.api.billing.ChargeThruApi;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
+import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.glue.EntitlementModule;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.util.glue.RealImplementation;
-public class MockEntitlementModule extends AbstractModule {
-
+public class MockEntitlementModule extends AbstractModule implements EntitlementModule {
- protected void installEntitlementService() {
+ /* (non-Javadoc)
+ * @see com.ning.billing.mock.glue.EntitlementModule#installEntitlementService()
+ */
+ @Override
+ public void installEntitlementService() {
bind(EntitlementService.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementService.class));
}
- protected void installEntitlementUserApi() {
+
+ /* (non-Javadoc)
+ * @see com.ning.billing.mock.glue.EntitlementModule#installEntitlementUserApi()
+ */
+ @Override
+ public void installEntitlementUserApi() {
bind(EntitlementUserApi.class).annotatedWith(RealImplementation.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class));
}
- protected void installEntitlementMigrationApi() {
+ /* (non-Javadoc)
+ * @see com.ning.billing.mock.glue.EntitlementModule#installEntitlementMigrationApi()
+ */
+ @Override
+ public void installEntitlementMigrationApi() {
bind(EntitlementMigrationApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementMigrationApi.class));
}
- protected void installChargeThruApi() {
+ /* (non-Javadoc)
+ * @see com.ning.billing.mock.glue.EntitlementModule#installChargeThruApi()
+ */
+ @Override
+ public void installChargeThruApi() {
bind(ChargeThruApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(ChargeThruApi.class));
}
@@ -48,5 +66,11 @@ public class MockEntitlementModule extends AbstractModule {
installEntitlementUserApi();
installEntitlementMigrationApi();
installChargeThruApi();
+ installEntitlementTimelineApi();
+ }
+
+ @Override
+ public void installEntitlementTimelineApi() {
+ bind(EntitlementTimelineApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementTimelineApi.class));
}
}
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockInvoiceModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockInvoiceModule.java
new file mode 100644
index 0000000..f499e9a
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockInvoiceModule.java
@@ -0,0 +1,57 @@
+/*
+ * 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.mock.glue;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.glue.InvoiceModule;
+import com.ning.billing.invoice.api.InvoiceMigrationApi;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.invoice.api.test.InvoiceTestApi;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+
+public class MockInvoiceModule extends AbstractModule implements InvoiceModule {
+
+ @Override
+ public void installInvoiceUserApi() {
+ bind(InvoiceUserApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceUserApi.class));
+ }
+
+ @Override
+ public void installInvoicePaymentApi() {
+ bind(InvoicePaymentApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(InvoicePaymentApi.class));
+ }
+
+ @Override
+ public void installInvoiceMigrationApi() {
+ bind(InvoiceMigrationApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceMigrationApi.class));
+ }
+
+ @Override
+ public void installInvoiceTestApi() {
+ bind(InvoiceTestApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceTestApi.class));
+ }
+
+ @Override
+ protected void configure() {
+ installInvoiceUserApi();
+ installInvoicePaymentApi();
+ installInvoiceMigrationApi();
+ installInvoiceTestApi();
+ }
+
+}
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java
index d21806d..1549c0b 100644
--- a/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java
@@ -19,11 +19,12 @@ package com.ning.billing.mock.glue;
import com.google.inject.AbstractModule;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.glue.JunctionModule;
import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.junction.api.BlockingApi;
import com.ning.billing.mock.BrainDeadProxyFactory;
-public class MockJunctionModule extends AbstractModule {
+public class MockJunctionModule extends AbstractModule implements JunctionModule {
private BillingApi billingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(BillingApi.class);
private BlockingApi blockingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(BlockingApi.class);
private AccountUserApi userApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -37,20 +38,24 @@ public class MockJunctionModule extends AbstractModule {
installEntitlementUserApi();
}
- protected void installBillingApi() {
+ @Override
+ public void installBillingApi() {
bind(BillingApi.class).toInstance(billingApi);
}
- protected void installAccountUserApi() {
+ @Override
+ public void installAccountUserApi() {
bind(AccountUserApi.class).toInstance(userApi);
}
- protected void installBlockingApi() {
+ @Override
+ public void installBlockingApi() {
bind(BlockingApi.class).toInstance(blockingApi);
}
- protected void installEntitlementUserApi() {
+ @Override
+ public void installEntitlementUserApi() {
bind(EntitlementUserApi.class).toInstance(entUserApi);
}
}
diff --git a/util/src/test/java/com/ning/billing/mock/glue/TestDbiModule.java b/util/src/test/java/com/ning/billing/mock/glue/TestDbiModule.java
new file mode 100644
index 0000000..c42717d
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/glue/TestDbiModule.java
@@ -0,0 +1,43 @@
+/*
+ * 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.mock.glue;
+
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.dbi.DBIProvider;
+import com.ning.billing.dbi.DbiConfig;
+import com.ning.billing.dbi.MysqlTestingHelper;
+
+public class TestDbiModule extends AbstractModule {
+
+ protected void configure() {
+
+ final MysqlTestingHelper helper = new MysqlTestingHelper();
+ bind(MysqlTestingHelper.class).toInstance(helper);
+ if (helper.isUsingLocalInstance()) {
+ bind(IDBI.class).toProvider(DBIProvider.class).asEagerSingleton();
+ final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
+ bind(DbiConfig.class).toInstance(config);
+ } else {
+ final IDBI dbi = helper.getDBI();
+ bind(IDBI.class).toInstance(dbi);
+ }
+
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/mock/MockAccountBuilder.java b/util/src/test/java/com/ning/billing/mock/MockAccountBuilder.java
new file mode 100644
index 0000000..8b9c2ee
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/MockAccountBuilder.java
@@ -0,0 +1,383 @@
+/*
+ * 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.mock;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.MutableAccountData;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.junction.api.BlockingState;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
+
+public class MockAccountBuilder {
+ private final UUID id;
+ private String externalKey;
+ private String email;
+ private String name;
+ private int firstNameLength;
+ private Currency currency;
+ private int billingCycleDay;
+ private String paymentProviderName;
+ private DateTimeZone timeZone;
+ private String locale;
+ private String address1;
+ private String address2;
+ private String companyName;
+ private String city;
+ private String stateOrProvince;
+ private String country;
+ private String postalCode;
+ private String phone;
+ private boolean migrated;
+ private boolean isNotifiedForInvoices;
+
+ public MockAccountBuilder() {
+ this(UUID.randomUUID());
+ }
+
+ public MockAccountBuilder(final UUID id) {
+ this.id = id;
+ }
+
+ public MockAccountBuilder externalKey(final String externalKey) {
+ this.externalKey = externalKey;
+ return this;
+ }
+
+ public MockAccountBuilder email(final String email) {
+ this.email = email;
+ return this;
+ }
+
+ public MockAccountBuilder name(final String name) {
+ this.name = name;
+ return this;
+ }
+
+ public MockAccountBuilder firstNameLength(final int firstNameLength) {
+ this.firstNameLength = firstNameLength;
+ return this;
+ }
+
+ public MockAccountBuilder billingCycleDay(final int billingCycleDay) {
+ this.billingCycleDay = billingCycleDay;
+ return this;
+ }
+
+ public MockAccountBuilder currency(final Currency currency) {
+ this.currency = currency;
+ return this;
+ }
+
+ public MockAccountBuilder paymentProviderName(final String paymentProviderName) {
+ this.paymentProviderName = paymentProviderName;
+ return this;
+ }
+
+ public MockAccountBuilder timeZone(final DateTimeZone timeZone) {
+ this.timeZone = timeZone;
+ return this;
+ }
+
+ public MockAccountBuilder locale(final String locale) {
+ this.locale = locale;
+ return this;
+ }
+
+ public MockAccountBuilder address1(final String address1) {
+ this.address1 = address1;
+ return this;
+ }
+
+ public MockAccountBuilder address2(final String address2) {
+ this.address2 = address2;
+ return this;
+ }
+
+ public MockAccountBuilder companyName(final String companyName) {
+ this.companyName = companyName;
+ return this;
+ }
+
+ public MockAccountBuilder city(final String city) {
+ this.city = city;
+ return this;
+ }
+
+ public MockAccountBuilder stateOrProvince(final String stateOrProvince) {
+ this.stateOrProvince = stateOrProvince;
+ return this;
+ }
+
+ public MockAccountBuilder postalCode(final String postalCode) {
+ this.postalCode = postalCode;
+ return this;
+ }
+
+ public MockAccountBuilder country(final String country) {
+ this.country = country;
+ return this;
+ }
+
+ public MockAccountBuilder phone(final String phone) {
+ this.phone = phone;
+ return this;
+ }
+
+ public MockAccountBuilder migrated(final boolean migrated) {
+ this.migrated = migrated;
+ return this;
+ }
+
+ public MockAccountBuilder isNotifiedForInvoices(final boolean isNotifiedForInvoices) {
+ this.isNotifiedForInvoices = isNotifiedForInvoices;
+ return this;
+ }
+
+ public Account build() {
+ return new Account(){
+
+ @Override
+ public String getExternalKey() {
+ return externalKey;
+ }
+
+ @Override
+ public String getName() {
+
+ return name;
+ }
+
+ @Override
+ public int getFirstNameLength() {
+
+ return firstNameLength;
+ }
+
+ @Override
+ public String getEmail() {
+
+ return email;
+ }
+
+ @Override
+ public int getBillCycleDay() {
+
+ return billingCycleDay;
+ }
+
+ @Override
+ public Currency getCurrency() {
+
+ return currency;
+ }
+
+ @Override
+ public String getPaymentProviderName() {
+
+ return paymentProviderName;
+ }
+
+ @Override
+ public DateTimeZone getTimeZone() {
+
+ return timeZone;
+ }
+
+ @Override
+ public String getLocale() {
+
+ return locale;
+ }
+
+ @Override
+ public String getAddress1() {
+
+ return address1;
+ }
+
+ @Override
+ public String getAddress2() {
+
+ return address2;
+ }
+
+ @Override
+ public String getCompanyName() {
+
+ return companyName;
+ }
+
+ @Override
+ public String getCity() {
+
+ return city;
+ }
+
+ @Override
+ public String getStateOrProvince() {
+
+ return stateOrProvince;
+ }
+
+ @Override
+ public String getPostalCode() {
+
+ return postalCode;
+ }
+
+ @Override
+ public String getCountry() {
+
+ return country;
+ }
+
+ @Override
+ public String getPhone() {
+
+ return phone;
+ }
+
+ @Override
+ public boolean isMigrated() {
+
+ return migrated;
+ }
+
+ @Override
+ public boolean isNotifiedForInvoices() {
+
+ return isNotifiedForInvoices;
+ }
+
+ @Override
+ public String getFieldValue(String fieldName) {
+
+ return null;
+ }
+
+ @Override
+ public void setFieldValue(String fieldName, String fieldValue) {
+
+
+ }
+
+ @Override
+ public void saveFieldValue(String fieldName, String fieldValue, CallContext context) {
+
+
+ }
+
+ @Override
+ public List<CustomField> getFieldList() {
+ return null;
+ }
+
+ @Override
+ public void setFields(List<CustomField> fields) {
+ }
+
+ @Override
+ public void saveFields(List<CustomField> fields, CallContext context) {
+ }
+
+ @Override
+ public void clearFields() {
+ }
+
+ @Override
+ public void clearPersistedFields(CallContext context) {
+ }
+
+ @Override
+ public ObjectType getObjectType() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UUID getId() {
+ return id;
+ }
+
+ @Override
+ public List<Tag> getTagList() {
+ return null;
+ }
+
+ @Override
+ public boolean hasTag(TagDefinition tagDefinition) {
+ return false;
+ }
+
+ @Override
+ public boolean hasTag(ControlTagType controlTagType) {
+ return false;
+ }
+
+ @Override
+ public void addTag(TagDefinition definition) {
+ }
+
+ @Override
+ public void addTags(List<Tag> tags) {
+ }
+
+ @Override
+ public void addTagsFromDefinitions(List<TagDefinition> tagDefinitions) {
+ }
+
+ @Override
+ public void clearTags() {
+ }
+
+ @Override
+ public void removeTag(TagDefinition definition) {
+ }
+
+ @Override
+ public boolean generateInvoice() {
+ return true;
+ }
+
+ @Override
+ public boolean processPayment() {
+ return true;
+ }
+
+ @Override
+ public BlockingState getBlockingState() {
+ return null;
+ }
+
+ @Override
+ public MutableAccountData toMutableAccountData() {
+ throw new NotImplementedException();
+ }
+ };
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/util/bus/TestEventBusBase.java b/util/src/test/java/com/ning/billing/util/bus/TestEventBusBase.java
index 371d1f9..ddc89ed 100644
--- a/util/src/test/java/com/ning/billing/util/bus/TestEventBusBase.java
+++ b/util/src/test/java/com/ning/billing/util/bus/TestEventBusBase.java
@@ -49,7 +49,8 @@ public class TestEventBusBase {
eventBus.stop();
}
- public static final class MyEvent implements BusEvent {
+
+ public static class MyEvent implements BusEvent {
private String name;
private Long value;
@@ -91,6 +92,18 @@ public class TestEventBusBase {
return type;
}
}
+
+ public static final class MyEventWithException extends MyEvent {
+
+ @JsonCreator
+ public MyEventWithException(@JsonProperty("name") String name,
+ @JsonProperty("value") Long value,
+ @JsonProperty("token") UUID token,
+ @JsonProperty("type") String type) {
+ super(name, value, token, type);
+ }
+ }
+
public static final class MyOtherEvent implements BusEvent {
@@ -135,6 +148,12 @@ public class TestEventBusBase {
return type;
}
}
+
+ public static class MyEventHandlerException extends RuntimeException {
+ public MyEventHandlerException(String msg) {
+ super(msg);
+ }
+ }
public static class MyEventHandler {
@@ -158,6 +177,11 @@ public class TestEventBusBase {
//log.debug("Got event {} {}", event.name, event.value);
}
+ @Subscribe
+ public synchronized void processEvent(MyEventWithException event) {
+ throw new MyEventHandlerException("FAIL");
+ }
+
public synchronized boolean waitForCompletion(long timeoutMs) {
long ini = System.currentTimeMillis();
@@ -176,6 +200,20 @@ public class TestEventBusBase {
}
}
+ public void testSimpleWithException() {
+ try {
+ MyEventHandler handler = new MyEventHandler(1);
+ eventBus.register(handler);
+
+ eventBus.post(new MyEventWithException("my-event", 1L, UUID.randomUUID(), BusEventType.ACCOUNT_CHANGE.toString()));
+
+ Thread.sleep(50000);
+ } catch (Exception e) {
+
+ }
+
+ }
+
public void testSimple() {
try {
diff --git a/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java b/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java
index 530a4e7..b42b694 100644
--- a/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java
+++ b/util/src/test/java/com/ning/billing/util/bus/TestPersistentEventBus.java
@@ -82,9 +82,16 @@ public class TestPersistentEventBus extends TestEventBusBase {
}
}
- @Test(groups = "slow")
+ @Test(groups = {"slow"})
public void testSimple() {
super.testSimple();
}
+
+ // Until Guava fixes exception handling, r13?
+ @Test(groups={"slow"}, enabled=false)
+ public void testSimpleWithException() {
+ super.testSimpleWithException();
+
+ }
}
diff --git a/util/src/test/java/com/ning/billing/util/clock/ClockMock.java b/util/src/test/java/com/ning/billing/util/clock/ClockMock.java
index 9e51a80..ab702cb 100644
--- a/util/src/test/java/com/ning/billing/util/clock/ClockMock.java
+++ b/util/src/test/java/com/ning/billing/util/clock/ClockMock.java
@@ -16,147 +16,134 @@
package com.ning.billing.util.clock;
-import com.ning.billing.catalog.api.Duration;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
+import org.joda.time.Days;
+import org.joda.time.Months;
+import org.joda.time.MutablePeriod;
+import org.joda.time.Period;
+import org.joda.time.ReadablePeriod;
+import org.joda.time.Weeks;
+import org.joda.time.Years;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.List;
-
-// STEPH should really be in tests but not accessible from other sub modules
-public class ClockMock extends DefaultClock {
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.TimeUnit;
+public class ClockMock implements Clock {
+
+ private MutablePeriod delta = new MutablePeriod();
private static final Logger log = LoggerFactory.getLogger(ClockMock.class);
- private enum DeltaType {
- DELTA_NONE,
- DELTA_DURATION,
- DELTA_ABS
- }
-
- private long deltaFromRealityMs;
- private List<Duration> deltaFromRealityDuration;
- private long deltaFromRealityDurationEpsilon;
- private DeltaType deltaType;
-
- public ClockMock() {
- deltaType = DeltaType.DELTA_NONE;
- deltaFromRealityMs = 0;
- deltaFromRealityDurationEpsilon = 0;
- deltaFromRealityDuration = null;
- }
-
+
@Override
public synchronized DateTime getNow(DateTimeZone tz) {
- return adjust(super.getNow(tz));
+ return getUTCNow().toDateTime(tz);
}
@Override
public synchronized DateTime getUTCNow() {
- return getNow(DateTimeZone.UTC);
+ return truncate(adjust(now()));
+ }
+
+ private DateTime adjust(DateTime now) {
+ return now.plus(delta);
}
- private void logClockAdjustment(DateTime prev, DateTime next) {
- log.info(String.format(" ************ ADJUSTING CLOCK FROM %s to %s ********************", prev, next));
+ public synchronized void setTime(DateTime time) {
+ DateTime prev = getUTCNow();
+ delta = new MutablePeriod(now(), time);
+ logChange(prev);
+ }
+
+ public synchronized void addDays(int days) {
+ adjustTo(Days.days(days));
+ }
+
+ public synchronized void addWeeks(int weeks) {
+ adjustTo(Weeks.weeks(weeks));
+ }
+
+ public synchronized void addMonths(int months) {
+ adjustTo(Months.months(months));
+ }
+
+ public synchronized void addYears(int years) {
+ adjustTo(Years.years(years));
+ }
+
+ public synchronized void reset() {
+ delta = new MutablePeriod();
+ }
+
+ @Override
+ public String toString() {
+ return getUTCNow().toString();
+ }
+
+ private void adjustTo(ReadablePeriod period) {
+ DateTime prev = getUTCNow();
+ delta.add(period);
+ logChange(prev);
+ }
+
+ private void logChange(DateTime prev) {
+ DateTime now = getUTCNow();
+ log.info(String.format(" ************ ADJUSTING CLOCK FROM %s to %s ********************", prev, now));
+ }
+
+ private DateTime now() {
+ return new DateTime(DateTimeZone.UTC);
}
- public synchronized void setDeltaFromReality(Duration delta, long epsilon) {
+ private DateTime truncate(DateTime time) {
+ return time.minus(time.getMillisOfSecond());
+ }
+
+ //
+ //Backward compatibility stuff
+ //
+ public synchronized void setDeltaFromReality(Duration duration, long epsilon) {
DateTime prev = getUTCNow();
- deltaType = DeltaType.DELTA_DURATION;
- deltaFromRealityDuration = new ArrayList<Duration>();
- deltaFromRealityDuration.add(delta);
- deltaFromRealityDurationEpsilon = epsilon;
- deltaFromRealityMs = 0;
- logClockAdjustment(prev, getUTCNow());
+ delta.addMillis((int)epsilon);
+ addDeltaFromReality(duration);
+ logChange(prev);
+
}
public synchronized void addDeltaFromReality(Duration delta) {
- DateTime prev = getUTCNow();
- if (deltaType != DeltaType.DELTA_DURATION) {
- throw new RuntimeException("ClockMock should be set with type DELTA_DURATION");
- }
- deltaFromRealityDuration.add(delta);
- logClockAdjustment(prev, getUTCNow());
+ adjustTo(periodFromDuration(delta));
}
public synchronized void setDeltaFromReality(long delta) {
- DateTime prev = getUTCNow();
- deltaType = DeltaType.DELTA_ABS;
- deltaFromRealityDuration = null;
- deltaFromRealityDurationEpsilon = 0;
- deltaFromRealityMs = delta;
- logClockAdjustment(prev, getUTCNow());
+ adjustTo(new Period(delta));
}
public synchronized void addDeltaFromReality(long delta) {
- DateTime prev = getUTCNow();
- if (deltaType != DeltaType.DELTA_ABS) {
- throw new RuntimeException("ClockMock should be set with type DELTA_ABS");
- }
- deltaFromRealityDuration = null;
- deltaFromRealityDurationEpsilon = 0;
- deltaFromRealityMs += delta;
- logClockAdjustment(prev, getUTCNow());
+ adjustTo(new Period(delta));
}
public synchronized void resetDeltaFromReality() {
- deltaType = DeltaType.DELTA_NONE;
- deltaFromRealityDuration = null;
- deltaFromRealityDurationEpsilon = 0;
- deltaFromRealityMs = 0;
+ reset();
}
+
+ public ReadablePeriod periodFromDuration(Duration duration) {
+ if (duration.getUnit() != TimeUnit.UNLIMITED) {return new Period();}
- private DateTime adjust(DateTime realNow) {
- switch(deltaType) {
- case DELTA_NONE:
- return realNow;
- case DELTA_ABS:
- return adjustFromAbsolute(realNow);
- case DELTA_DURATION:
- return adjustFromDuration(realNow);
- default:
- return null;
- }
- }
-
- private DateTime adjustFromDuration(DateTime input) {
-
- DateTime result = input;
- for (Duration cur : deltaFromRealityDuration) {
- switch (cur.getUnit()) {
+ switch (duration.getUnit()) {
case DAYS:
- result = result.plusDays(cur.getNumber());
- break;
-
+ return Days.days(duration.getNumber());
case MONTHS:
- result = result.plusMonths(cur.getNumber());
- break;
-
+ return Months.months(duration.getNumber());
case YEARS:
- result = result.plusYears(cur.getNumber());
- break;
-
+ return Years.years(duration.getNumber());
case UNLIMITED:
- default:
- throw new RuntimeException("ClockMock is adjusting an unlimited time period");
- }
+ return Years.years(100);
+ default:
+ return new Period();
}
- if (deltaFromRealityDurationEpsilon != 0) {
- result = result.plus(deltaFromRealityDurationEpsilon);
- }
- return result;
- }
-
- private DateTime adjustFromAbsolute(DateTime input) {
- return truncateMs(input.plus(deltaFromRealityMs));
}
-
- @Override
- public String toString() {
- return getUTCNow().toString();
- }
-
+
}
diff --git a/util/src/test/java/com/ning/billing/util/clock/MockClockModule.java b/util/src/test/java/com/ning/billing/util/clock/MockClockModule.java
index a8f0605..ece94b0 100644
--- a/util/src/test/java/com/ning/billing/util/clock/MockClockModule.java
+++ b/util/src/test/java/com/ning/billing/util/clock/MockClockModule.java
@@ -28,3 +28,4 @@ public class MockClockModule extends AbstractModule {
}
}
+
\ No newline at end of file
diff --git a/util/src/test/java/com/ning/billing/util/clock/OldClockMock.java b/util/src/test/java/com/ning/billing/util/clock/OldClockMock.java
new file mode 100644
index 0000000..b31db77
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/clock/OldClockMock.java
@@ -0,0 +1,162 @@
+/*
+ * 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.util.clock;
+
+import com.ning.billing.catalog.api.Duration;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+// STEPH should really be in tests but not accessible from other sub modules
+public class OldClockMock extends DefaultClock {
+
+ private static final Logger log = LoggerFactory.getLogger(OldClockMock.class);
+
+ private enum DeltaType {
+ DELTA_NONE,
+ DELTA_DURATION,
+ DELTA_ABS
+ }
+
+ private long deltaFromRealityMs;
+ private List<Duration> deltaFromRealityDuration;
+ private long deltaFromRealityDurationEpsilon;
+ private DeltaType deltaType;
+
+ public OldClockMock() {
+ deltaType = DeltaType.DELTA_NONE;
+ deltaFromRealityMs = 0;
+ deltaFromRealityDurationEpsilon = 0;
+ deltaFromRealityDuration = null;
+ }
+
+ @Override
+ public synchronized DateTime getNow(DateTimeZone tz) {
+ return adjust(super.getNow(tz));
+ }
+
+ @Override
+ public synchronized DateTime getUTCNow() {
+ return getNow(DateTimeZone.UTC);
+ }
+
+ private void logClockAdjustment(DateTime prev, DateTime next) {
+ log.info(String.format(" ************ ADJUSTING CLOCK FROM %s to %s ********************", prev, next));
+ }
+
+ public synchronized void setDeltaFromReality(Duration delta, long epsilon) {
+ DateTime prev = getUTCNow();
+ deltaType = DeltaType.DELTA_DURATION;
+ deltaFromRealityDuration = new ArrayList<Duration>();
+ deltaFromRealityDuration.add(delta);
+ deltaFromRealityDurationEpsilon = epsilon;
+ deltaFromRealityMs = 0;
+ logClockAdjustment(prev, getUTCNow());
+ }
+
+ public synchronized void addDeltaFromReality(Duration delta) {
+ DateTime prev = getUTCNow();
+ if (deltaType != DeltaType.DELTA_DURATION) {
+ throw new RuntimeException("ClockMock should be set with type DELTA_DURATION");
+ }
+ deltaFromRealityDuration.add(delta);
+ logClockAdjustment(prev, getUTCNow());
+ }
+
+ public synchronized void setDeltaFromReality(long delta) {
+ DateTime prev = getUTCNow();
+ deltaType = DeltaType.DELTA_ABS;
+ deltaFromRealityDuration = null;
+ deltaFromRealityDurationEpsilon = 0;
+ deltaFromRealityMs = delta;
+ logClockAdjustment(prev, getUTCNow());
+ }
+
+ public synchronized void addDeltaFromReality(long delta) {
+ DateTime prev = getUTCNow();
+ if (deltaType != DeltaType.DELTA_ABS) {
+ throw new RuntimeException("ClockMock should be set with type DELTA_ABS");
+ }
+ deltaFromRealityDuration = null;
+ deltaFromRealityDurationEpsilon = 0;
+ deltaFromRealityMs += delta;
+ logClockAdjustment(prev, getUTCNow());
+ }
+
+ public synchronized void resetDeltaFromReality() {
+ deltaType = DeltaType.DELTA_NONE;
+ deltaFromRealityDuration = null;
+ deltaFromRealityDurationEpsilon = 0;
+ deltaFromRealityMs = 0;
+ }
+
+ private DateTime adjust(DateTime realNow) {
+ switch(deltaType) {
+ case DELTA_NONE:
+ return realNow;
+ case DELTA_ABS:
+ return adjustFromAbsolute(realNow);
+ case DELTA_DURATION:
+ return adjustFromDuration(realNow);
+ default:
+ return null;
+ }
+ }
+
+ private DateTime adjustFromDuration(DateTime input) {
+
+ DateTime result = input;
+ for (Duration cur : deltaFromRealityDuration) {
+ switch (cur.getUnit()) {
+ case DAYS:
+ result = result.plusDays(cur.getNumber());
+ break;
+
+ case MONTHS:
+ result = result.plusMonths(cur.getNumber());
+ break;
+
+ case YEARS:
+ result = result.plusYears(cur.getNumber());
+ break;
+
+ case UNLIMITED:
+ default:
+ throw new RuntimeException("ClockMock is adjusting an unlimited time period");
+ }
+ }
+ if (deltaFromRealityDurationEpsilon != 0) {
+ result = result.plus(deltaFromRealityDurationEpsilon);
+ }
+ return result;
+ }
+
+ private DateTime adjustFromAbsolute(DateTime input) {
+ return truncateMs(input.plus(deltaFromRealityMs));
+ }
+
+ @Override
+ public String toString() {
+ return getUTCNow().toString();
+ }
+
+
+}
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java b/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
index cc7c458..6cf0eb9 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
@@ -20,11 +20,10 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
+
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.tweak.HandleCallback;
@@ -49,8 +48,8 @@ import static org.testng.Assert.assertNotNull;
@Guice(modules = TestNotificationSqlDao.TestNotificationSqlDaoModule.class)
public class TestNotificationSqlDao {
- private static AtomicInteger sequenceId = new AtomicInteger();
-
+ private final static String hostname = "Yop";
+
@Inject
private IDBI dbi;
@@ -104,12 +103,12 @@ public class TestNotificationSqlDao {
String notificationKey = UUID.randomUUID().toString();
DateTime effDt = new DateTime();
- Notification notif = new DefaultNotification("testBasic",notificationKey, effDt);
+ Notification notif = new DefaultNotification("testBasic", hostname, notificationKey, effDt);
dao.insertNotification(notif);
Thread.sleep(1000);
DateTime now = new DateTime();
- List<Notification> notifications = dao.getReadyNotifications(now.toDate(), 3, "testBasic");
+ List<Notification> notifications = dao.getReadyNotifications(now.toDate(), hostname, 3, "testBasic");
assertNotNull(notifications);
assertEquals(notifications.size(), 1);
@@ -121,20 +120,20 @@ public class TestNotificationSqlDao {
assertEquals(notification.getNextAvailableDate(), null);
DateTime nextAvailable = now.plusMinutes(5);
- int res = dao.claimNotification(ownerId, nextAvailable.toDate(), notification.getId(), now.toDate());
+ int res = dao.claimNotification(ownerId, nextAvailable.toDate(), notification.getId().toString(), now.toDate());
assertEquals(res, 1);
- dao.insertClaimedHistory(sequenceId.incrementAndGet(), ownerId, now.toDate(), notification.getUUID().toString());
+ dao.insertClaimedHistory(ownerId, now.toDate(), notification.getId().toString());
- notification = fetchNotification(notification.getUUID().toString());
+ notification = fetchNotification(notification.getId().toString());
assertEquals(notification.getNotificationKey(), notificationKey);
validateDate(notification.getEffectiveDate(), effDt);
assertEquals(notification.getOwner().toString(), ownerId);
assertEquals(notification.getProcessingState(), NotificationLifecycleState.IN_PROCESSING);
validateDate(notification.getNextAvailableDate(), nextAvailable);
- dao.clearNotification(notification.getId(), ownerId);
+ dao.clearNotification(notification.getId().toString(), ownerId);
- notification = fetchNotification(notification.getUUID().toString());
+ notification = fetchNotification(notification.getId().toString());
assertEquals(notification.getNotificationKey(), notificationKey);
validateDate(notification.getEffectiveDate(), effDt);
//assertEquals(notification.getOwner(), null);
@@ -153,6 +152,7 @@ public class TestNotificationSqlDao {
", id" +
", notification_key" +
", created_date" +
+ ", creating_owner" +
", effective_date" +
", queue_name" +
", processing_owner" +
@@ -197,12 +197,6 @@ public class TestNotificationSqlDao {
bind(MysqlTestingHelper.class).toInstance(helper);
IDBI dbi = helper.getDBI();
bind(IDBI.class).toInstance(dbi);
-
- /*
- bind(DBI.class).toProvider(DBIProvider.class).asEagerSingleton();
- final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
- bind(DbiConfig.class).toInstance(config);
- */
}
}
}
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
index a9cd1db..7d8b477 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
@@ -50,7 +50,7 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
@Override
public void recordFutureNotification(DateTime futureNotificationTime, NotificationKey notificationKey) {
- Notification notification = new DefaultNotification("MockQueue", notificationKey.toString(), futureNotificationTime);
+ Notification notification = new DefaultNotification("MockQueue", hostname, notificationKey.toString(), futureNotificationTime);
synchronized(notifications) {
notifications.add(notification);
}
@@ -75,7 +75,7 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
}
@Override
- protected int doProcessEvents(int sequenceId) {
+ public int doProcessEvents() {
int result = 0;
@@ -96,7 +96,7 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
result = readyNotifications.size();
for (Notification cur : readyNotifications) {
handler.handleReadyNotification(cur.getNotificationKey(), cur.getEffectiveDate());
- DefaultNotification processedNotification = new DefaultNotification(-1L, cur.getUUID(), hostname, "MockQueue", clock.getUTCNow().plus(config.getDaoClaimTimeMs()), NotificationLifecycleState.PROCESSED, cur.getNotificationKey(), cur.getEffectiveDate());
+ DefaultNotification processedNotification = new DefaultNotification(-1L, cur.getId(), hostname, hostname, "MockQueue", clock.getUTCNow().plus(config.getDaoClaimTimeMs()), NotificationLifecycleState.PROCESSED, cur.getNotificationKey(), cur.getEffectiveDate());
oldNotifications.add(cur);
processedNotifications.add(processedNotification);
}