killbill-aplcache
Changes
invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java 8(+7 -1)
invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java 2(+2 -0)
pom.xml 17(+16 -1)
util/pom.xml 16(+16 -0)
util/src/main/java/com/ning/billing/util/email/formatters/DefaultInvoiceItemFormatter.java 135(+135 -0)
util/src/main/java/com/ning/billing/util/email/translation/DefaultCatalogTranslation.java 37(+37 -0)
util/src/main/java/com/ning/billing/util/email/translation/DefaultInvoiceTranslation.java 136(+136 -0)
util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache 96(+96 -0)
util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_EN_US.properties 2(+2 -0)
util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_FR_CA.properties 1(+1 -0)
Details
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index db73376..b65c80c 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -168,7 +168,15 @@ public enum ErrorCode {
OVERDUE_OVERDUEABLE_NOT_SUPPORTED(5001, "The Overdueable type '%s' is not supported"),
OVERDUE_CAT_ERROR_ENCOUNTERED(5002,"Catalog error encountered on Overdueable: id='%s', type='%s'"),
-
+ /*
+ *
+ * Range 9000: Miscellaneous
+ *
+ */
+ EMAIL_SENDING_FAILED(9000, "Sending email failed"),
+ EMAIL_PROPERTIES_FILE_MISSING(9001, "The properties file for email configuration could not be found."),
+ MISSING_TRANSLATION_RESOURCE(9010, "The resources for %s translation could not be found."),
+ MISSING_DEFAULT_TRANSLATION_RESOURCE(9011, "The default resource for %s translation could not be found.")
;
private int code;
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceNotifier.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceNotifier.java
index 13026c7..7a7fbc4 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceNotifier.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceNotifier.java
@@ -16,8 +16,9 @@
package com.ning.billing.invoice.api;
+import com.ning.billing.BillingExceptionBase;
import com.ning.billing.account.api.Account;
public interface InvoiceNotifier {
- public void notify(Account account, Invoice invoice);
+ public void notify(Account account, Invoice invoice) throws BillingExceptionBase;
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
index ba63bf1..41b782d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
@@ -16,6 +16,9 @@
package com.ning.billing.invoice.glue;
+import com.ning.billing.invoice.api.InvoiceNotifier;
+import com.ning.billing.invoice.notification.EmailInvoiceNotifier;
+import com.ning.billing.util.email.EmailConfig;
import org.skife.config.ConfigurationObjectFactory;
import com.google.inject.AbstractModule;
@@ -39,7 +42,6 @@ import com.ning.billing.invoice.notification.NextBillingDateNotifier;
import com.ning.billing.invoice.notification.NextBillingDatePoster;
import com.ning.billing.util.glue.GlobalLockerModule;
-
public class InvoiceModule extends AbstractModule {
protected void installInvoiceDao() {
bind(InvoiceDao.class).to(DefaultInvoiceDao.class).asEagerSingleton();
@@ -56,6 +58,9 @@ public class InvoiceModule extends AbstractModule {
protected void installConfig() {
final InvoiceConfig config = new ConfigurationObjectFactory(System.getProperties()).build(InvoiceConfig.class);
bind(InvoiceConfig.class).toInstance(config);
+
+ final EmailConfig emailConfig = new ConfigurationObjectFactory(System.getProperties()).build(EmailConfig.class);
+ bind(EmailConfig.class).toInstance(emailConfig);
}
protected void installInvoiceService() {
@@ -66,9 +71,10 @@ public class InvoiceModule extends AbstractModule {
bind(InvoiceMigrationApi.class).to(DefaultInvoiceMigrationApi.class).asEagerSingleton();
}
- protected void installNotifier() {
+ protected void installNotifiers() {
bind(NextBillingDateNotifier.class).to(DefaultNextBillingDateNotifier.class).asEagerSingleton();
bind(NextBillingDatePoster.class).to(DefaultNextBillingDatePoster.class).asEagerSingleton();
+ bind(InvoiceNotifier.class).to(EmailInvoiceNotifier.class).asEagerSingleton();
}
protected void installGlobalLocker() {
@@ -82,11 +88,11 @@ public class InvoiceModule extends AbstractModule {
@Override
protected void configure() {
installInvoiceService();
- installNotifier();
+ installConfig();
+ installNotifiers();
installInvoiceListener();
bind(InvoiceGenerator.class).to(DefaultInvoiceGenerator.class).asEagerSingleton();
- installConfig();
installInvoiceDao();
installInvoiceUserApi();
installInvoicePaymentApi();
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 043c670..820c57d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -21,6 +21,7 @@ import java.util.List;
import java.util.SortedSet;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceNotifier;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
import com.ning.billing.util.bus.BusEvent;
@@ -59,6 +60,7 @@ public class InvoiceDispatcher {
private final EntitlementBillingApi entitlementBillingApi;
private final AccountUserApi accountUserApi;
private final InvoiceDao invoiceDao;
+ private final InvoiceNotifier invoiceNotifier;
private final GlobalLocker locker;
private final Bus eventBus;
private final Clock clock;
@@ -69,6 +71,7 @@ public class InvoiceDispatcher {
public InvoiceDispatcher(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
final EntitlementBillingApi entitlementBillingApi,
final InvoiceDao invoiceDao,
+ final InvoiceNotifier invoiceNotifier,
final GlobalLocker locker,
final Bus eventBus,
final Clock clock) {
@@ -76,6 +79,7 @@ public class InvoiceDispatcher {
this.entitlementBillingApi = entitlementBillingApi;
this.accountUserApi = accountUserApi;
this.invoiceDao = invoiceDao;
+ this.invoiceNotifier = invoiceNotifier;
this.locker = locker;
this.eventBus = eventBus;
this.clock = clock;
@@ -175,6 +179,11 @@ public class InvoiceDispatcher {
invoiceDao.create(invoice, context);
}
}
+
+ if (account.isNotifiedForInvoices()) {
+
+ }
+
return invoice;
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/notification/EmailInvoiceNotifier.java b/invoice/src/main/java/com/ning/billing/invoice/notification/EmailInvoiceNotifier.java
new file mode 100644
index 0000000..aee0f66
--- /dev/null
+++ b/invoice/src/main/java/com/ning/billing/invoice/notification/EmailInvoiceNotifier.java
@@ -0,0 +1,69 @@
+/*
+ * 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.invoice.notification;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountEmail;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceNotifier;
+import com.ning.billing.util.email.DefaultEmailSender;
+import com.ning.billing.util.email.EmailApiException;
+import com.ning.billing.util.email.EmailConfig;
+import com.ning.billing.util.email.EmailSender;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class EmailInvoiceNotifier implements InvoiceNotifier {
+ private final AccountUserApi accountUserApi;
+ private final EmailConfig config;
+
+ @Inject
+ public EmailInvoiceNotifier(AccountUserApi accountUserApi, EmailConfig config) {
+ this.accountUserApi = accountUserApi;
+ this.config = config;
+ }
+
+ @Override
+ public void notify(Account account, Invoice invoice) throws EmailApiException {
+ List<String> to = new ArrayList<String>();
+ to.add(account.getEmail());
+
+ List<AccountEmail> accountEmailList = accountUserApi.getEmails(account.getId());
+ List<String> cc = new ArrayList<String>();
+ for (AccountEmail email : accountEmailList) {
+ cc.add(email.getEmail());
+ }
+
+ // TODO: get html body from template
+ String htmlBody = "";
+
+ // TODO: get subject
+ String subject = "";
+
+ EmailSender sender = new DefaultEmailSender(config);
+ try {
+ sender.sendSecureEmail(to, cc, subject, htmlBody);
+ } catch (IOException e) {
+ throw new EmailApiException(e, ErrorCode.EMAIL_SENDING_FAILED);
+ }
+ }
+}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/notification/NullInvoiceNotifier.java b/invoice/src/main/java/com/ning/billing/invoice/notification/NullInvoiceNotifier.java
new file mode 100644
index 0000000..460e779
--- /dev/null
+++ b/invoice/src/main/java/com/ning/billing/invoice/notification/NullInvoiceNotifier.java
@@ -0,0 +1,28 @@
+/*
+ * 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.invoice.notification;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceNotifier;
+
+public class NullInvoiceNotifier implements InvoiceNotifier {
+ @Override
+ public void notify(Account account, Invoice invoice) {
+ // deliberate no-op
+ }
+}
\ No newline at end of file
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 300313c..e317734 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
@@ -19,11 +19,13 @@ package com.ning.billing.invoice.api.migration;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
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.notification.DefaultNextBillingDateNotifier;
import com.ning.billing.invoice.notification.DefaultNextBillingDatePoster;
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.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
@@ -44,11 +46,12 @@ public class MockModuleNoEntitlement extends MockModule {
install(new InvoiceModule(){
@Override
- protected void installNotifier() {
+ protected void installNotifiers() {
bind(NextBillingDateNotifier.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(NextBillingDateNotifier.class));
NextBillingDatePoster poster = BrainDeadProxyFactory.createBrainDeadProxyFor(NextBillingDatePoster.class);
((ZombieControl)poster).addResult("insertNextBillingNotification",BrainDeadProxyFactory.ZOMBIE_VOID);
bind(NextBillingDatePoster.class).toInstance(poster);
+ bind(InvoiceNotifier.class).to(NullInvoiceNotifier.class).asEagerSingleton();
}
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 3aee83d..58d94dd 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
@@ -23,6 +23,8 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceNotifier;
+import com.ning.billing.invoice.notification.NullInvoiceNotifier;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallOrigin;
import com.ning.billing.util.callcontext.UserType;
@@ -169,6 +171,7 @@ public class TestDefaultInvoiceMigrationApi {
((ZombieControl)accountUserApi).addResult("getAccountById", account);
((ZombieControl)account).addResult("getCurrency", Currency.USD);
((ZombieControl)account).addResult("getId", accountId);
+ ((ZombieControl)account).addResult("isNotifiedForInvoices", true);
Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
((ZombieControl)subscription).addResult("getId", subscriptionId);
@@ -185,7 +188,10 @@ public class TestDefaultInvoiceMigrationApi {
EntitlementBillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementBillingApi.class);
((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
- InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao, locker, busService.getBus(), clock);
+
+ InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
+ InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi,
+ invoiceDao, invoiceNotifier, locker, busService.getBus(), clock);
CallContext context = new DefaultCallContextFactory(clock).createCallContext("Migration test", CallOrigin.TEST, UserType.TEST);
Invoice invoice = dispatcher.processAccount(accountId, date_regular, true, context);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index a3b8888..b1c038f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -57,7 +57,7 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
-@Test(groups = {"invoicing", "invoicing-invoiceDao"})
+@Test(groups = {"slow", "invoicing", "invoicing-invoiceDao"})
public class InvoiceDaoTests extends InvoiceDaoTestBase {
@Test
public void testCreationAndRetrievalByAccount() {
@@ -406,8 +406,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
MockPlanPhase phase1 = new MockPlanPhase(recurringPrice, null, BillingPeriod.MONTHLY, PhaseType.TRIAL);
MockPlan plan1 = new MockPlan(phase1);
- Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
- ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ Subscription subscription = getZombieSubscription();
DateTime effectiveDate1 = new DateTime(2011, 2, 1, 0, 0, 0, 0);
BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan1, phase1, null,
@@ -457,8 +456,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
MockPlanPhase phase = new MockPlanPhase(recurringPrice, null);
MockPlan plan = new MockPlan(phase);
- Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
- ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ Subscription subscription = getZombieSubscription();
DateTime effectiveDate = buildDateTime(2011, 1, 1);
BillingEvent event = new DefaultBillingEvent(null, subscription, effectiveDate, plan, phase, null,
@@ -475,6 +473,13 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
assertEquals(invoice.getTotalAmount().compareTo(ZERO), 0);
}
+ private Subscription getZombieSubscription() {
+ Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+ ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ ((ZombieControl) subscription).addResult("getBundleId", UUID.randomUUID());
+ return subscription;
+ }
+
@Test
public void testInvoiceForFreeTrialWithRecurringDiscount() throws InvoiceApiException, CatalogApiException {
Currency currency = Currency.USD;
@@ -490,8 +495,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
MockPlan plan = new MockPlan();
- Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
- ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ Subscription subscription = getZombieSubscription();
DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
@@ -550,8 +554,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
MockPlan plan = new MockPlan();
- Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
- ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ Subscription subscription = getZombieSubscription();
DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan, phase1,
@@ -586,8 +589,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
DateTime targetDate1 = DateTime.now().plusMonths(1);
DateTime targetDate2 = DateTime.now().plusMonths(2);
- Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
- ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ Subscription subscription = getZombieSubscription();
Plan plan = BrainDeadProxyFactory.createBrainDeadProxyFor(Plan.class);
((ZombieControl) plan).addResult("getName", "plan");
@@ -626,8 +628,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
@Test
public void testAddingWrittenOffTag() throws InvoiceApiException {
- Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
- ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ Subscription subscription = getZombieSubscription();
Plan plan = BrainDeadProxyFactory.createBrainDeadProxyFor(Plan.class);
((ZombieControl) plan).addResult("getName", "plan");
@@ -657,8 +658,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
@Test
public void testRemoveWrittenOffTag() throws InvoiceApiException {
- Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
- ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+ Subscription subscription = getZombieSubscription();
Plan plan = BrainDeadProxyFactory.createBrainDeadProxyFor(Plan.class);
((ZombieControl) plan).addResult("getName", "plan");
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 368b74f..cc5ad02 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,6 +21,8 @@ import static org.testng.Assert.assertNotNull;
import java.io.IOException;
import java.net.URL;
+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;
@@ -80,9 +82,10 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
}
@Override
- protected void installNotifier() {
+ protected void installNotifiers() {
bind(NextBillingDateNotifier.class).to(MockNextBillingDateNotifier.class).asEagerSingleton();
bind(NextBillingDatePoster.class).to(MockNextBillingDatePoster.class).asEagerSingleton();
+ bind(InvoiceNotifier.class).to(NullInvoiceNotifier.class).asEagerSingleton();
}
@Override
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 fe4feb4..0206bb2 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
@@ -16,8 +16,10 @@
package com.ning.billing.invoice.glue;
+import com.ning.billing.invoice.api.InvoiceNotifier;
import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.dao.MockInvoiceDao;
+import com.ning.billing.invoice.notification.NullInvoiceNotifier;
import com.ning.billing.util.globallocker.GlobalLocker;
import com.ning.billing.util.globallocker.MockGlobalLocker;
import com.ning.billing.util.glue.CallContextModule;
@@ -45,8 +47,8 @@ public class InvoiceModuleWithMocks extends InvoiceModule {
}
@Override
- protected void installNotifier() {
-
+ protected void installNotifiers() {
+ bind(InvoiceNotifier.class).to(NullInvoiceNotifier.class).asEagerSingleton();
}
@Override
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 e70626f..9c02629 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
@@ -24,6 +24,7 @@ import java.sql.SQLException;
import java.util.UUID;
import java.util.concurrent.Callable;
+import com.ning.billing.invoice.api.InvoiceNotifier;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.skife.config.ConfigurationObjectFactory;
@@ -125,6 +126,7 @@ public class TestNextBillingDateNotifier {
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);
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 45f1db4..6d8ec75 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -23,6 +23,8 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceNotifier;
+import com.ning.billing.invoice.notification.NullInvoiceNotifier;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
@@ -135,6 +137,7 @@ public class TestInvoiceDispatcher {
((ZombieControl)accountUserApi).addResult("getAccountById", account);
((ZombieControl)account).addResult("getCurrency", Currency.USD);
((ZombieControl)account).addResult("getId", accountId);
+ ((ZombieControl)account).addResult(("isNotifiedForInvoices"), true);
Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
((ZombieControl)subscription).addResult("getId", subscriptionId);
@@ -154,7 +157,9 @@ public class TestInvoiceDispatcher {
DateTime target = new DateTime();
- InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao, locker, busService.getBus(), clock);
+ InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
+ InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao,
+ invoiceNotifier, locker, busService.getBus(), clock);
Invoice invoice = dispatcher.processAccount(accountId, target, true, context);
Assert.assertNotNull(invoice);
pom.xml 17(+16 -1)
diff --git a/pom.xml b/pom.xml
index f7ab718..fef0a80 100644
--- a/pom.xml
+++ b/pom.xml
@@ -243,9 +243,19 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-email</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.studio</groupId>
+ <artifactId>org.apache.commons.io</artifactId>
+ <version>2.1</version>
+ </dependency>
+ <dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
- <version>2.0.1</version>
+ <version>2.0</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
@@ -317,6 +327,11 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>com.samskivert</groupId>
+ <artifactId>jmustache</artifactId>
+ <version>1.5</version>
+ </dependency>
+ <dependency>
<groupId>com.jayway.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>1.3.3</version>
util/pom.xml 16(+16 -0)
diff --git a/util/pom.xml b/util/pom.xml
index e0d256c..d9f7924 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -65,6 +65,14 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-email</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.studio</groupId>
+ <artifactId>org.apache.commons.io</artifactId>
+ </dependency>
+ <dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<scope>test</scope>
@@ -83,6 +91,14 @@
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.samskivert</groupId>
+ <artifactId>jmustache</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
</dependencies>
<build>
<plugins>
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
new file mode 100644
index 0000000..103a87b
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/DefaultEmailSender.java
@@ -0,0 +1,68 @@
+/*
+ * 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.email;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import org.apache.commons.mail.EmailException;
+import org.apache.commons.mail.HtmlEmail;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class DefaultEmailSender implements EmailSender {
+ private final Logger log = LoggerFactory.getLogger(EmailSender.class);
+ private final EmailConfig config;
+
+ @Inject
+ public DefaultEmailSender(EmailConfig emailConfig) {
+ this.config = emailConfig;
+ }
+
+ @Override
+ public void sendSecureEmail(List<String> to, List<String> cc, String subject, String htmlBody) throws EmailApiException {
+ HtmlEmail email;
+ try {
+ email = new HtmlEmail();
+
+ email.setSmtpPort(config.getSmtpPort());
+ email.setAuthentication(config.getSmtpUserName(), config.getSmtpPassword());
+ email.setHostName(config.getSmtpServerName());
+ email.setFrom(config.getSmtpUserName());
+ email.setSubject(subject);
+ email.setHtmlMsg(htmlBody);
+
+ if (to != null) {
+ for (String recipient : to) {
+ email.addTo(recipient);
+ }
+ }
+
+ if (cc != null) {
+ for (String recipient : cc) {
+ email.addCc(recipient);
+ }
+ }
+
+ email.setSSL(true);
+ email.send();
+ } catch (EmailException ee) {
+ log.warn("Failed to send e-mail", ee);
+ }
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/EmailApiException.java b/util/src/main/java/com/ning/billing/util/email/EmailApiException.java
new file mode 100644
index 0000000..9b5d6ba
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/EmailApiException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.email;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+
+public class EmailApiException extends BillingExceptionBase {
+ private static final long serialVersionUID = 1L;
+
+ public EmailApiException(Throwable cause, int code, final String msg) {
+ super(cause, code, msg);
+ }
+
+ public EmailApiException(Throwable cause, ErrorCode code, final Object... args) {
+ super(cause, code, args);
+ }
+
+ public EmailApiException(ErrorCode code, final Object... args) {
+ super(code, args);
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/EmailConfig.java b/util/src/main/java/com/ning/billing/util/email/EmailConfig.java
new file mode 100644
index 0000000..427f9df
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/EmailConfig.java
@@ -0,0 +1,45 @@
+/*
+ * 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.email;
+
+import com.ning.billing.config.KillbillConfig;
+import org.skife.config.Config;
+import org.skife.config.Default;
+
+import java.util.Locale;
+
+public interface EmailConfig extends KillbillConfig {
+ @Config("mail.smtp.host")
+ @Default("smtp.gmail.com")
+ public String getSmtpServerName();
+
+ @Config("mail.smtp.port")
+ @Default("465")
+ public int getSmtpPort();
+
+ @Config("mail.smtp.user")
+ @Default("killbill.ning@gmail.com")
+ public String getSmtpUserName();
+
+ @Config("mail.smtp.password")
+ @Default("killbill@ning!")
+ public String getSmtpPassword();
+
+ @Config("email.default.locale")
+ @Default("en_US")
+ public String getDefaultLocale();
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/EmailSender.java b/util/src/main/java/com/ning/billing/util/email/EmailSender.java
new file mode 100644
index 0000000..198a2eb
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/EmailSender.java
@@ -0,0 +1,24 @@
+/*
+ * 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.email;
+
+import java.io.IOException;
+import java.util.List;
+
+public interface EmailSender {
+ public void sendSecureEmail(List<String> to, List<String> cc, String subject, String htmlBody) throws IOException, EmailApiException;
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/formatters/DefaultInvoiceFormatter.java b/util/src/main/java/com/ning/billing/util/email/formatters/DefaultInvoiceFormatter.java
new file mode 100644
index 0000000..80d11a3
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/formatters/DefaultInvoiceFormatter.java
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.email.formatters;
+
+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.email.EmailConfig;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+
+public class DefaultInvoiceFormatter implements InvoiceFormatter {
+ private final EmailConfig config;
+ private final Invoice invoice;
+ private final DateTimeFormatter dateFormatter;
+ private final Locale locale;
+
+ public DefaultInvoiceFormatter(EmailConfig config, Invoice invoice, Locale locale) {
+ this.config = config;
+ this.invoice = invoice;
+ dateFormatter = DateTimeFormat.mediumDate().withLocale(locale);
+ this.locale = locale;
+ }
+
+ @Override
+ public Integer getInvoiceNumber() {
+ return invoice.getInvoiceNumber();
+ }
+
+ @Override
+ public List<InvoiceItem> getInvoiceItems() {
+ List<InvoiceItem> formatters = new ArrayList<InvoiceItem>();
+ for (InvoiceItem item : invoice.getInvoiceItems()) {
+ formatters.add(new DefaultInvoiceItemFormatter(config, item, dateFormatter, locale));
+ }
+ return formatters;
+ }
+
+ @Override
+ public boolean addInvoiceItem(InvoiceItem item) {
+ return invoice.addInvoiceItem(item);
+ }
+
+ @Override
+ public boolean addInvoiceItems(List<InvoiceItem> items) {
+ return invoice.addInvoiceItems(items);
+ }
+
+ @Override
+ public <T extends InvoiceItem> List<InvoiceItem> getInvoiceItems(Class<T> clazz) {
+ return invoice.getInvoiceItems(clazz);
+ }
+
+ @Override
+ public int getNumberOfItems() {
+ return invoice.getNumberOfItems();
+ }
+
+ @Override
+ public boolean addPayment(InvoicePayment payment) {
+ return invoice.addPayment(payment);
+ }
+
+ @Override
+ public boolean addPayments(List<InvoicePayment> payments) {
+ return invoice.addPayments(payments);
+ }
+
+ @Override
+ public List<InvoicePayment> getPayments() {
+ return invoice.getPayments();
+ }
+
+ @Override
+ public int getNumberOfPayments() {
+ return invoice.getNumberOfPayments();
+ }
+
+ @Override
+ public UUID getAccountId() {
+ return invoice.getAccountId();
+ }
+
+ @Override
+ public BigDecimal getTotalAmount() {
+ return invoice.getTotalAmount();
+ }
+
+ @Override
+ public BigDecimal getBalance() {
+ return invoice.getBalance();
+ }
+
+ @Override
+ public boolean isDueForPayment(DateTime targetDate, int numberOfDays) {
+ return invoice.isDueForPayment(targetDate, numberOfDays);
+ }
+
+ @Override
+ public boolean isMigrationInvoice() {
+ return invoice.isMigrationInvoice();
+ }
+
+ @Override
+ public DateTime getInvoiceDate() {
+ return invoice.getInvoiceDate();
+ }
+
+ @Override
+ public DateTime getTargetDate() {
+ return invoice.getTargetDate();
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return invoice.getCurrency();
+ }
+
+ @Override
+ public DateTime getLastPaymentAttempt() {
+ return invoice.getLastPaymentAttempt();
+ }
+
+ @Override
+ public BigDecimal getAmountPaid() {
+ return invoice.getAmountPaid();
+ }
+
+ @Override
+ public String getFormattedInvoiceDate() {
+ return invoice.getInvoiceDate().toString(dateFormatter);
+ }
+
+ @Override
+ public String getFieldValue(String fieldName) {
+ return invoice.getFieldValue(fieldName);
+ }
+
+ @Override
+ public void setFieldValue(String fieldName, String fieldValue) {
+ invoice.setFieldValue(fieldName, fieldValue);
+ }
+
+ @Override
+ public void saveFieldValue(String fieldName, String fieldValue, CallContext context) {
+ invoice.saveFieldValue(fieldName, fieldValue, context);
+ }
+
+ @Override
+ public List<CustomField> getFieldList() {
+ return invoice.getFieldList();
+ }
+
+ @Override
+ public void setFields(List<CustomField> fields) {
+ invoice.setFields(fields);
+ }
+
+ @Override
+ public void saveFields(List<CustomField> fields, CallContext context) {
+ invoice.saveFields(fields, context);
+ }
+
+ @Override
+ public void clearFields() {
+ invoice.clearFields();
+ }
+
+ @Override
+ public void clearPersistedFields(CallContext context) {
+ invoice.clearPersistedFields(context);
+ }
+
+ @Override
+ public String getObjectName() {
+ return invoice.getObjectName();
+ }
+
+ @Override
+ public UUID getId() {
+ return invoice.getId();
+ }
+
+ @Override
+ public String getCreatedBy() {
+ return invoice.getCreatedBy();
+ }
+
+ @Override
+ public DateTime getCreatedDate() {
+ return invoice.getCreatedDate();
+ }
+
+ @Override
+ public List<Tag> getTagList() {
+ return invoice.getTagList();
+ }
+
+ @Override
+ public boolean hasTag(String tagName) {
+ return invoice.hasTag(tagName);
+ }
+
+ @Override
+ public void addTag(TagDefinition definition) {
+ invoice.addTag(definition);
+ }
+
+ @Override
+ public void addTags(List<Tag> tags) {
+ invoice.addTags(tags);
+ }
+
+ @Override
+ public void clearTags() {
+ invoice.clearTags();
+ }
+
+ @Override
+ public void removeTag(TagDefinition definition) {
+ invoice.removeTag(definition);
+ }
+
+ @Override
+ public boolean generateInvoice() {
+ return invoice.generateInvoice();
+ }
+
+ @Override
+ public boolean processPayment() {
+ return invoice.processPayment();
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/formatters/DefaultInvoiceItemFormatter.java b/util/src/main/java/com/ning/billing/util/email/formatters/DefaultInvoiceItemFormatter.java
new file mode 100644
index 0000000..1b24cf1
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/formatters/DefaultInvoiceItemFormatter.java
@@ -0,0 +1,135 @@
+/*
+ * 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.email.formatters;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.util.email.EmailConfig;
+import com.ning.billing.util.email.translation.CatalogTranslation;
+import com.ning.billing.util.email.translation.DefaultCatalogTranslation;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormatter;
+
+import java.math.BigDecimal;
+import java.util.Locale;
+import java.util.UUID;
+
+public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
+ private final CatalogTranslation catalogTranslation;
+
+ private final InvoiceItem item;
+ private final DateTimeFormatter dateFormatter;
+ private final Locale locale;
+
+ public DefaultInvoiceItemFormatter(EmailConfig config, InvoiceItem item, DateTimeFormatter dateFormatter, Locale locale) {
+ this.item = item;
+ this.dateFormatter = dateFormatter;
+ this.locale = locale;
+
+ this.catalogTranslation = new DefaultCatalogTranslation(config);
+ }
+
+ @Override
+ public BigDecimal getAmount() {
+ return item.getAmount();
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return item.getCurrency();
+ }
+
+ @Override
+ public InvoiceItem asCredit() {
+ return item.asCredit();
+ }
+
+ @Override
+ public String getDescription() {
+ return item.getDescription();
+ }
+
+ @Override
+ public DateTime getStartDate() {
+ return item.getStartDate();
+ }
+
+ @Override
+ public DateTime getEndDate() {
+ return item.getEndDate();
+ }
+
+ @Override
+ public String getFormattedStartDate() {
+ return item.getStartDate().toString(dateFormatter);
+ }
+
+ @Override
+ public String getFormattedEndDate() {
+ return item.getEndDate().toString(dateFormatter);
+ }
+
+ @Override
+ public UUID getInvoiceId() {
+ return item.getInvoiceId();
+ }
+
+ @Override
+ public UUID getAccountId() {
+ return item.getAccountId();
+ }
+
+ @Override
+ public UUID getBundleId() {
+ return item.getBundleId();
+ }
+
+ @Override
+ public UUID getSubscriptionId() {
+ return item.getSubscriptionId();
+ }
+
+ @Override
+ public String getPlanName() {
+ return catalogTranslation.getTranslation(locale, item.getPlanName());
+ }
+
+ @Override
+ public String getPhaseName() {
+ return catalogTranslation.getTranslation(locale, item.getPhaseName());
+ }
+
+ @Override
+ public int compareTo(InvoiceItem invoiceItem) {
+ return item.compareTo(invoiceItem);
+ }
+
+ @Override
+ public UUID getId() {
+ return item.getId();
+ }
+
+ @Override
+ public String getCreatedBy() {
+ return item.getCreatedBy();
+ }
+
+ @Override
+ public DateTime getCreatedDate() {
+ return item.getCreatedDate();
+ }
+}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/email/formatters/InvoiceFormatter.java b/util/src/main/java/com/ning/billing/util/email/formatters/InvoiceFormatter.java
new file mode 100644
index 0000000..5107828
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/formatters/InvoiceFormatter.java
@@ -0,0 +1,23 @@
+/*
+ * 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.email.formatters;
+
+import com.ning.billing.invoice.api.Invoice;
+
+public interface InvoiceFormatter extends Invoice {
+ public String getFormattedInvoiceDate();
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/formatters/InvoiceItemFormatter.java b/util/src/main/java/com/ning/billing/util/email/formatters/InvoiceItemFormatter.java
new file mode 100644
index 0000000..f811b78
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/formatters/InvoiceItemFormatter.java
@@ -0,0 +1,24 @@
+/*
+ * 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.email.formatters;
+
+import com.ning.billing.invoice.api.InvoiceItem;
+
+public interface InvoiceItemFormatter extends InvoiceItem {
+ public String getFormattedStartDate();
+ public String getFormattedEndDate();
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/templates/HtmlInvoiceGenerator.java b/util/src/main/java/com/ning/billing/util/email/templates/HtmlInvoiceGenerator.java
new file mode 100644
index 0000000..f6e7710
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/templates/HtmlInvoiceGenerator.java
@@ -0,0 +1,65 @@
+/*
+ * 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.email.templates;
+
+import com.google.inject.Inject;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.util.email.EmailConfig;
+import com.ning.billing.util.email.formatters.DefaultInvoiceFormatter;
+import com.ning.billing.util.email.formatters.InvoiceFormatter;
+import com.ning.billing.util.email.translation.DefaultInvoiceTranslation;
+import com.samskivert.mustache.Mustache;
+import com.samskivert.mustache.Template;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.lang.String;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class HtmlInvoiceGenerator {
+ private final EmailConfig config;
+
+ @Inject
+ public HtmlInvoiceGenerator(EmailConfig config) {
+ this.config = config;
+ }
+
+ public String generateInvoice(Account account, Invoice invoice, String templateName) throws IOException {
+ InputStream templateStream = this.getClass().getResourceAsStream(templateName + ".mustache");
+ StringWriter writer = new StringWriter();
+ IOUtils.copy(templateStream, writer, "UTF-8");
+ String templateText = writer.toString();
+
+ Template template = Mustache.compiler().compile(templateText);
+
+ Map<String, Object> data = new HashMap<String, Object>();
+
+ data.put("text", new DefaultInvoiceTranslation(config));
+ data.put("account", account);
+ Locale locale = new Locale(account.getLocale());
+
+ InvoiceFormatter formattedInvoice = new DefaultInvoiceFormatter(config, invoice, locale);
+ data.put("invoice", formattedInvoice);
+
+ return template.execute(data);
+ }
+}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/email/templates/InvoiceStrings.java b/util/src/main/java/com/ning/billing/util/email/templates/InvoiceStrings.java
new file mode 100644
index 0000000..47c0857
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/templates/InvoiceStrings.java
@@ -0,0 +1,40 @@
+package com.ning.billing.util.email.templates;/*
+ * 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.
+ */
+
+public interface InvoiceStrings {
+ String getInvoiceTitle();
+ String getInvoiceDate();
+ String getInvoiceNumber();
+ String getAccountOwnerName();
+ String getAccountOwnerEmail();
+ String getAccountOwnerPhone();
+
+ // company name and address
+ String getCompanyName();
+ String getCompanyAddress();
+ String getCompanyCityProvincePostalCode();
+ String getCompanyCountry();
+ String getCompanyUrl();
+
+ String getInvoiceItemBundleName();
+ String getInvoiceItemDescription();
+ String getInvoiceItemServicePeriod();
+ String getInvoiceItemAmount();
+
+ String getInvoiceAmount();
+ String getInvoiceAmountPaid();
+ String getInvoiceBalance();
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/translation/CatalogTranslation.java b/util/src/main/java/com/ning/billing/util/email/translation/CatalogTranslation.java
new file mode 100644
index 0000000..eac06a1
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/translation/CatalogTranslation.java
@@ -0,0 +1,23 @@
+/*
+ * 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.email.translation;
+
+import java.util.Locale;
+
+public interface CatalogTranslation {
+ public String getTranslation(Locale locale, String originalText);
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/translation/DefaultCatalogTranslation.java b/util/src/main/java/com/ning/billing/util/email/translation/DefaultCatalogTranslation.java
new file mode 100644
index 0000000..be01630
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/translation/DefaultCatalogTranslation.java
@@ -0,0 +1,37 @@
+/*
+ * 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.email.translation;
+
+import com.google.inject.Inject;
+import com.ning.billing.util.email.EmailConfig;
+
+public class DefaultCatalogTranslation extends DefaultTranslationBase {
+ @Inject
+ public DefaultCatalogTranslation(EmailConfig config) {
+ super(config);
+ }
+
+ @Override
+ protected String getBundlePath() {
+ return "com/ning/billing/util/email/translation/CatalogTranslation";
+ }
+
+ @Override
+ protected String getTranslationType() {
+ return "catalog";
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/translation/DefaultInvoiceTranslation.java b/util/src/main/java/com/ning/billing/util/email/translation/DefaultInvoiceTranslation.java
new file mode 100644
index 0000000..8ef9f16
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/translation/DefaultInvoiceTranslation.java
@@ -0,0 +1,136 @@
+/*
+ * 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.email.translation;
+
+import com.google.inject.Inject;
+import com.ning.billing.util.email.EmailConfig;
+import com.ning.billing.util.email.templates.InvoiceStrings;
+
+import java.util.Locale;
+
+public class DefaultInvoiceTranslation extends DefaultTranslationBase implements InvoiceStrings {
+ private Locale locale;
+
+ @Inject
+ public DefaultInvoiceTranslation(EmailConfig config) {
+ super(config);
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+ @Override
+ protected String getBundlePath() {
+ return "com/ning/billing/util/email/translation/InvoiceTranslation";
+ }
+
+ @Override
+ protected String getTranslationType() {
+ return "invoice";
+ }
+
+ @Override
+ public String getInvoiceTitle() {
+ return getTranslation(locale, "invoiceTitle");
+ }
+
+ @Override
+ public String getInvoiceDate() {
+ return getTranslation(locale, "invoiceDate");
+ }
+
+ @Override
+ public String getInvoiceNumber() {
+ return getTranslation(locale, "invoiceNumber");
+ }
+
+ @Override
+ public String getAccountOwnerName() {
+ return getTranslation(locale, "accountOwnerName");
+ }
+
+ @Override
+ public String getAccountOwnerEmail() {
+ return getTranslation(locale, "accountOwnerEmail");
+ }
+
+ @Override
+ public String getAccountOwnerPhone() {
+ return getTranslation(locale, "accountOwnerPhone");
+ }
+
+ @Override
+ public String getCompanyName() {
+ return getTranslation(locale, "companyName");
+ }
+
+ @Override
+ public String getCompanyAddress() {
+ return getTranslation(locale, "companyAddress");
+ }
+
+ @Override
+ public String getCompanyCityProvincePostalCode() {
+ return getTranslation(locale, "");
+ }
+
+ @Override
+ public String getCompanyCountry() {
+ return getTranslation(locale, "companyCountry");
+ }
+
+ @Override
+ public String getCompanyUrl() {
+ return getTranslation(locale, "companyUrl");
+ }
+
+ @Override
+ public String getInvoiceItemBundleName() {
+ return getTranslation(locale, "invoiceItemBundleName");
+ }
+
+ @Override
+ public String getInvoiceItemDescription() {
+ return getTranslation(locale, "invoiceItemDescription");
+ }
+
+ @Override
+ public String getInvoiceItemServicePeriod() {
+ return getTranslation(locale, "invoiceItemServicePeriod");
+ }
+
+ @Override
+ public String getInvoiceItemAmount() {
+ return getTranslation(locale, "invoiceItemAmount");
+ }
+
+ @Override
+ public String getInvoiceAmount() {
+ return getTranslation(locale, "invoiceAmount");
+ }
+
+ @Override
+ public String getInvoiceAmountPaid() {
+ return getTranslation(locale, "invoiceAmountPaid");
+ }
+
+ @Override
+ public String getInvoiceBalance() {
+ return getTranslation(locale, "invoiceBalance");
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/email/translation/DefaultTranslationBase.java b/util/src/main/java/com/ning/billing/util/email/translation/DefaultTranslationBase.java
new file mode 100644
index 0000000..82a799a
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/email/translation/DefaultTranslationBase.java
@@ -0,0 +1,73 @@
+/*
+ * 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.email.translation;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.util.email.EmailConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public abstract class DefaultTranslationBase implements CatalogTranslation {
+ protected final EmailConfig config;
+ protected final Logger log = LoggerFactory.getLogger(DefaultTranslationBase.class);
+
+ @Inject
+ public DefaultTranslationBase(EmailConfig config) {
+ this.config = config;
+ }
+
+ protected abstract String getBundlePath();
+
+ /*
+ * string used for exception handling
+ */
+ protected abstract String getTranslationType();
+
+ @Override
+ public String getTranslation(Locale locale, String originalText) {
+ ResourceBundle bundle = null;
+ try {
+ bundle = ResourceBundle.getBundle(getBundlePath(), locale);
+ } catch (MissingResourceException mrex) {
+ log.warn(String.format(ErrorCode.MISSING_TRANSLATION_RESOURCE.toString(), getTranslationType()));
+ }
+
+ if ((bundle != null) && (bundle.containsKey(originalText))) {
+ return bundle.getString(originalText);
+ } else {
+ // TODO: make the default local a configuration item
+ try {
+ Locale defaultLocale = new Locale(config.getDefaultLocale());
+ bundle = ResourceBundle.getBundle(getBundlePath(), Locale.US);
+
+ if ((bundle != null) && (bundle.containsKey(originalText))) {
+ return bundle.getString(originalText);
+ } else {
+ return originalText;
+ }
+ } catch (MissingResourceException mrex) {
+ log.warn(String.format(ErrorCode.MISSING_TRANSLATION_RESOURCE.toString(), getTranslationType()));
+ return originalText;
+ }
+ }
+ }
+}
diff --git a/util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache b/util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache
new file mode 100644
index 0000000..73c70b3
--- /dev/null
+++ b/util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache
@@ -0,0 +1,96 @@
+<html>
+ <head>
+ <style type="text/css">
+ th {align=left; width=225px; border-bottom: solid 2px black;}
+ </style>
+ </head>
+ <body>
+ <h1>{{text.invoiceTitle}}</h1>
+ <table>
+ <tr>
+ <td rowspan=3 width=350px>Insert image here</td>
+ <td width=100px/>
+ <td width=225px/>
+ <td width=225px/>
+ </tr>
+ <tr>
+ <td />
+ <td align=right>{{text.invoiceDate}}</td>
+ <td>{{invoice.formattedInvoiceDate}}</td>
+ </tr>
+ <tr>
+ <td />
+ <td align=right>{{text.invoiceNumber}}</td>
+ <td>{{invoice.invoiceNumber}}</td>
+ </tr>
+ <tr>
+ <td>{{text.companyName}}</td>
+ <td></td>
+ <td align=right>{{text.accountOwnerName}}</td>
+ <td>{{account.name}}</td>
+ </tr>
+ <tr>
+ <td>{{text.companyAddress}}</td>
+ <td />
+ <td />
+ <td>{{account.email}}</td>
+ </tr>
+ <tr>
+ <td>{{text.companyCityProvincePostalCode}}</td>
+ <td />
+ <td />
+ <td>{{account.phone}}</td>
+ </tr>
+ <tr>
+ <td>{{text.companyCountry}}</td>
+ <td />
+ <td />
+ <td />
+ </tr>
+ <tr>
+ <td><{{text.companyUrl}}</td>
+ <td />
+ <td />
+ <td />
+ </tr>
+ </table>
+ <br />
+ <br />
+ <br />
+ <table>
+ <tr>
+ <th>{{text.invoiceItemBundleName}}</td>
+ <th>{{text.invoiceItemDescription}}</td>
+ <th>{{text.invoiceItemServicePeriod}}</td>
+ <th>{{text.invoiceItemAmount}}</td>
+ </tr>
+ {{#invoice.invoiceItems}}
+ <tr>
+ <td>{{description}}</td>
+ <td>{{planName}}</td>
+ <td>{{formattedStartDate}} - {{formattedEndDate}}</td>
+ <td>{{invoice.currency}} {{amount}}</td>
+ </tr>
+ {{/invoice.invoiceItems}}
+ <tr>
+ <td colspan=4 />
+ </tr>
+ <tr>
+ <td colspan=2 />
+ <td align=right><strong>{{text.invoiceAmount}}</strong></td>
+ <td align=right><strong>{{invoice.totalAmount}}</strong></td>
+ </tr>
+ <tr>
+ <td colspan=2 />
+ <td align=right><strong>{{text.invoiceAmountPaid}}</strong></td>
+ <td align=right><strong>{{invoice.amountPaid}}</strong></td>
+ </tr>
+ <tr>
+ <td colspan=2 />
+ <td align=right><strong>{{text.invoiceBalance}}</strong></td>
+ <td align=right><strong>{{invoice.balance}}</strong></td>
+ </tr>
+ </table>
+ </body>
+</html>
+
diff --git a/util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_EN_US.properties b/util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_EN_US.properties
new file mode 100644
index 0000000..b05a595
--- /dev/null
+++ b/util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_EN_US.properties
@@ -0,0 +1,2 @@
+ning-pro = Pro
+ning-plus = Plus
\ No newline at end of file
diff --git a/util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_FR_CA.properties b/util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_FR_CA.properties
new file mode 100644
index 0000000..e025a88
--- /dev/null
+++ b/util/src/main/resources/com/ning/billing/util/email/translation/CatalogTranslation_FR_CA.properties
@@ -0,0 +1 @@
+ning-plus = Plus en francais
\ No newline at end of file
diff --git a/util/src/main/resources/com/ning/billing/util/email/translation/InvoiceTranslation_EN_US.properties b/util/src/main/resources/com/ning/billing/util/email/translation/InvoiceTranslation_EN_US.properties
new file mode 100644
index 0000000..0162671
--- /dev/null
+++ b/util/src/main/resources/com/ning/billing/util/email/translation/InvoiceTranslation_EN_US.properties
@@ -0,0 +1,20 @@
+invoiceTitle=INVOICE
+invoiceDate=Date:
+invoiceNumber=Invoice #
+invoiceAmount=New Charges
+invoiceAmountPaid=Payment
+invoiceBalance=Balance
+
+accountOwnerName=Network Creator
+
+companyName=Ning, Inc.
+companyAddress=P.O. Box 1622
+companyCityProvincePostalCode=Palo Alto, CA 94302
+companyCountry=USA
+companyUrl=http://www.ning.com
+
+invoiceItemBundleName=NetworkName
+invoiceItemDescription=Description
+invoiceItemServicePeriod=Service Period
+invoiceItemAmount=Amount
+
diff --git a/util/src/test/java/com/ning/billing/util/email/DefaultCatalogTranslationTest.java b/util/src/test/java/com/ning/billing/util/email/DefaultCatalogTranslationTest.java
new file mode 100644
index 0000000..c704f18
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/email/DefaultCatalogTranslationTest.java
@@ -0,0 +1,83 @@
+package com.ning.billing.util.email;/*
+ * 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.
+ */
+
+import com.ning.billing.util.email.translation.CatalogTranslation;
+import com.ning.billing.util.email.translation.DefaultCatalogTranslation;
+import org.skife.config.ConfigurationObjectFactory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.Locale;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = {"fast", "email"})
+public class DefaultCatalogTranslationTest {
+ private CatalogTranslation translation;
+
+ @BeforeClass(groups={"fast", "email"})
+ public void setup() {
+ final EmailConfig config = new ConfigurationObjectFactory(System.getProperties()).build(EmailConfig.class);
+ translation = new DefaultCatalogTranslation(config);
+ }
+
+ @Test(groups = {"fast", "email"})
+ public void testInitialization() {
+ String ningPlusText = "ning-plus";
+ String ningProText = "ning-pro";
+ String badText = "Bad text";
+
+ assertEquals(translation.getTranslation(Locale.US, ningPlusText), "Plus");
+ assertEquals(translation.getTranslation(Locale.US, ningProText), "Pro");
+ assertEquals(translation.getTranslation(Locale.US, badText), badText);
+
+ assertEquals(translation.getTranslation(Locale.CANADA_FRENCH, ningPlusText), "Plus en francais");
+ assertEquals(translation.getTranslation(Locale.CANADA_FRENCH, ningProText), "Pro");
+ assertEquals(translation.getTranslation(Locale.CANADA_FRENCH, badText), badText);
+
+ assertEquals(translation.getTranslation(Locale.CHINA, ningPlusText), "Plus");
+ assertEquals(translation.getTranslation(Locale.CHINA, ningProText), "Pro");
+ assertEquals(translation.getTranslation(Locale.CHINA, badText), badText);
+ }
+
+ @Test
+ public void testExistingTranslation() {
+ // if the translation exists, return the translation
+ String originalText = "ning-plus";
+ assertEquals(translation.getTranslation(Locale.US, originalText), "Plus");
+ }
+
+ @Test
+ public void testMissingTranslation() {
+ // if the translation is missing from the file, return the original text
+ String originalText = "missing translation";
+ assertEquals(translation.getTranslation(Locale.US, originalText), originalText);
+ }
+
+ @Test
+ public void testMissingTranslationFileWithEnglishText() {
+ // if the translation file doesn't exist, return the "English" translation
+ String originalText = "ning-plus";
+ assertEquals(translation.getTranslation(Locale.CHINA, originalText), "Plus");
+ }
+
+ @Test
+ public void testMissingFileAndText() {
+ // if the file is missing, and the "English" translation is missing, return the original text
+ String originalText = "missing translation";
+ assertEquals(translation.getTranslation(Locale.CHINA, originalText), originalText);
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/util/email/EmailSenderTest.java b/util/src/test/java/com/ning/billing/util/email/EmailSenderTest.java
new file mode 100644
index 0000000..1685628
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/email/EmailSenderTest.java
@@ -0,0 +1,42 @@
+package com.ning.billing.util.email;/*
+ * 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.
+ */
+
+import org.skife.config.ConfigurationObjectFactory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Test(groups = {"slow", "email"})
+public class EmailSenderTest {
+ private EmailConfig config;
+
+ @BeforeClass
+ public void setup() {
+ config = new ConfigurationObjectFactory(System.getProperties()).build(EmailConfig.class);
+ }
+
+ @Test
+ public void testSendEmail() throws Exception {
+ String html = "<html><body><h1>Test E-mail</h1></body></html>";
+ List<String> recipients = new ArrayList<String>();
+ recipients.add("killbill.ning@gmail.com");
+
+ EmailSender sender = new DefaultEmailSender(config);
+ sender.sendSecureEmail(recipients, null, "Test message", html);
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/util/email/HtmlInvoiceGeneratorTest.java b/util/src/test/java/com/ning/billing/util/email/HtmlInvoiceGeneratorTest.java
new file mode 100644
index 0000000..51ea400
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/email/HtmlInvoiceGeneratorTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.email;
+
+import com.ning.billing.account.api.Account;
+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.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.email.templates.HtmlInvoiceGenerator;
+import org.apache.commons.mail.Email;
+import org.joda.time.DateTime;
+import org.skife.config.ConfigurationObjectFactory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import static org.testng.Assert.assertNotNull;
+
+@Test(groups = {"fast", "email"})
+public class HtmlInvoiceGeneratorTest {
+ private HtmlInvoiceGenerator g;
+ private final static String TEST_TEMPLATE_NAME = "HtmlInvoiceTemplate";
+
+ @BeforeClass
+ public void setup() {
+ EmailConfig config = new ConfigurationObjectFactory(System.getProperties()).build(EmailConfig.class);
+ g = new HtmlInvoiceGenerator(config);
+ }
+
+ @Test
+ public void testGenerateInvoice() throws Exception {
+ String output = g.generateInvoice(createAccount(), createInvoice(), TEST_TEMPLATE_NAME);
+ assertNotNull(output);
+ System.out.print(output);
+ }
+
+ private Account createAccount() {
+ Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+ ZombieControl zombieControl = (ZombieControl) account;
+ zombieControl.addResult("getExternalKey", "1234abcd");
+ zombieControl.addResult("getName", "Jim Smith");
+ zombieControl.addResult("getFirstNameLength", 3);
+ zombieControl.addResult("getEmail", "jim.smith@mail.com");
+ zombieControl.addResult("getLocale", Locale.US.toString());
+ zombieControl.addResult("getAddress1", "123 Some Street");
+ zombieControl.addResult("getAddress2", "Apt 456");
+ zombieControl.addResult("getCity", "Some City");
+ zombieControl.addResult("getStateOrProvince", "Some State");
+ zombieControl.addResult("getPostalCode", "12345-6789");
+ zombieControl.addResult("getCountry", "USA");
+ zombieControl.addResult("getPhone", "123-456-7890");
+
+ return account;
+ }
+
+ private Invoice createInvoice() {
+ DateTime startDate = new DateTime().minusMonths(1);
+ DateTime endDate = new DateTime();
+
+ BigDecimal price1 = new BigDecimal("29.95");
+ BigDecimal price2 = new BigDecimal("59.95");
+ Invoice dummyInvoice = BrainDeadProxyFactory.createBrainDeadProxyFor(Invoice.class);
+ ZombieControl zombie = (ZombieControl) dummyInvoice;
+ zombie.addResult("getInvoiceDate", startDate);
+ zombie.addResult("getInvoiceNumber", 42);
+ zombie.addResult("getCurrency", Currency.USD);
+ zombie.addResult("getTotalAmount", price1.add(price2));
+ zombie.addResult("getAmountPaid", BigDecimal.ZERO);
+ zombie.addResult("getBalance", price1.add(price2));
+
+ List<InvoiceItem> items = new ArrayList<InvoiceItem>();
+ items.add(createInvoiceItem(price1, "Domain 1", startDate, endDate, "ning-plus"));
+ items.add(createInvoiceItem(price2, "Domain 2", startDate, endDate, "ning-pro"));
+ zombie.addResult("getInvoiceItems", items);
+
+ return dummyInvoice;
+ }
+
+ private InvoiceItem createInvoiceItem(BigDecimal amount, String networkName, DateTime startDate, DateTime endDate, String planName) {
+ InvoiceItem item = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceItem.class);
+ ZombieControl zombie = (ZombieControl) item;
+ zombie.addResult("getAmount", amount);
+ zombie.addResult("getStartDate", startDate);
+ zombie.addResult("getEndDate", endDate);
+ zombie.addResult("getPlanName", planName);
+ zombie.addResult("getDescription", networkName);
+
+
+ return item;
+ }
+}