use of org.killbill.billing.account.dao.AccountModelDao in project killbill by killbill.
the class TestIntegrationParentInvoice method testUnParentingWithUnpaidInvoice.
@Test(groups = "slow")
public void testUnParentingWithUnpaidInvoice() throws Exception {
final int billingDay = 14;
final DateTime initialCreationDate = new DateTime(2015, 5, 15, 0, 0, 0, 0, testTimeZone);
// set clock to the initial start date
clock.setTime(initialCreationDate);
final Account parentAccount = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
Account childAccount = createAccountWithNonOsgiPaymentMethod(getChildAccountData(billingDay, parentAccount.getId(), true));
// Verify mapping
childAccount = accountUserApi.getAccountById(childAccount.getId(), callContext);
assertEquals(childAccount.getParentAccountId(), parentAccount.getId());
assertTrue(childAccount.isPaymentDelegatedToParent());
List<Account> childrenAccounts = accountUserApi.getChildrenAccounts(parentAccount.getId(), callContext);
assertEquals(childrenAccounts.size(), 1);
assertEquals(childrenAccounts.get(0).getId(), childAccount.getId());
// Create subscription
createBaseEntitlementAndCheckForCompletion(childAccount.getId(), "bundleKey1", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// Moving a day the NotificationQ calls the commitInvoice. No payment is expected
busHandler.pushExpectedEvents(NextEvent.INVOICE);
clock.addDays(1);
assertListenerStatus();
// First Parent invoice over TRIAL period
List<Invoice> parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), false, callContext);
assertEquals(parentInvoices.size(), 1);
Invoice parentInvoice = parentInvoices.get(0);
assertEquals(parentInvoice.getNumberOfItems(), 1);
assertEquals(parentInvoice.getStatus(), InvoiceStatus.COMMITTED);
assertTrue(parentInvoice.isParentInvoice());
assertEquals(parentInvoice.getBalance().compareTo(BigDecimal.ZERO), 0);
// First child invoice over TRIAL period
List<Invoice> childInvoices = invoiceUserApi.getInvoicesByAccount(childAccount.getId(), false, callContext);
assertEquals(childInvoices.size(), 1);
assertEquals(childInvoices.get(0).getBalance().compareTo(BigDecimal.ZERO), 0);
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE);
clock.addDays(29);
assertListenerStatus();
paymentPlugin.makeNextPaymentFailWithError();
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.INVOICE_PAYMENT_ERROR);
clock.addDays(1);
assertListenerStatus();
// Second Parent invoice over Recurring period
parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), false, callContext);
assertEquals(parentInvoices.size(), 2);
parentInvoice = parentInvoices.get(1);
assertEquals(parentInvoice.getNumberOfItems(), 1);
assertEquals(parentInvoice.getStatus(), InvoiceStatus.COMMITTED);
assertTrue(parentInvoice.isParentInvoice());
assertEquals(parentInvoice.getBalance().compareTo(new BigDecimal("249.95")), 0);
// The parent has attempted to pay the child invoice
assertEquals(parentInvoice.getPayments().size(), 1);
assertEquals(paymentApi.getPayment(parentInvoice.getPayments().get(0).getPaymentId(), false, false, ImmutableList.<PluginProperty>of(), callContext).getPaymentMethodId(), parentAccount.getPaymentMethodId());
// Second child invoice over Recurring period
childInvoices = invoiceUserApi.getInvoicesByAccount(childAccount.getId(), false, callContext);
assertEquals(childInvoices.size(), 2);
assertEquals(childInvoices.get(1).getBalance().compareTo(new BigDecimal("249.95")), 0);
// Verify balances
assertEquals(invoiceUserApi.getAccountBalance(parentAccount.getId(), callContext).compareTo(new BigDecimal("249.95")), 0);
assertEquals(invoiceUserApi.getAccountBalance(childAccount.getId(), callContext).compareTo(new BigDecimal("249.95")), 0);
// Un-parent the child
final AccountModelDao childAccountModelDao = new AccountModelDao(childAccount.getId(), childAccount);
childAccountModelDao.setParentAccountId(null);
childAccountModelDao.setIsPaymentDelegatedToParent(false);
accountUserApi.updateAccount(new DefaultAccount(childAccountModelDao), callContext);
// Verify mapping
childAccount = accountUserApi.getAccountById(childAccount.getId(), callContext);
assertNull(childAccount.getParentAccountId());
assertFalse(childAccount.isPaymentDelegatedToParent());
childrenAccounts = accountUserApi.getChildrenAccounts(parentAccount.getId(), callContext);
assertEquals(childrenAccounts.size(), 0);
// Verify balances
// TODO Should we automatically adjust the invoice at the parent level or should it be the responsibility of the user?
assertEquals(invoiceUserApi.getAccountBalance(parentAccount.getId(), callContext).compareTo(new BigDecimal("249.95")), 0);
assertEquals(invoiceUserApi.getAccountBalance(childAccount.getId(), callContext).compareTo(new BigDecimal("249.95")), 0);
final int nbDaysBeforeRetry = paymentConfig.getPaymentFailureRetryDays(internalCallContext).get(0);
// Move time for retry to happen
busHandler.pushExpectedEvents(NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addDays(nbDaysBeforeRetry + 1);
assertListenerStatus();
// Second Parent invoice over Recurring period
parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), false, callContext);
// Note that the parent still owns both invoices
assertEquals(parentInvoices.size(), 2);
parentInvoice = parentInvoices.get(1);
assertEquals(parentInvoice.getNumberOfItems(), 1);
assertEquals(parentInvoice.getStatus(), InvoiceStatus.COMMITTED);
assertTrue(parentInvoice.isParentInvoice());
assertEquals(parentInvoice.getBalance().compareTo(BigDecimal.ZERO), 0);
// Even if the child-parent mapping has been removed, the parent has retried and successfully paid the summary invoice
// TODO Should we automatically disable payment retries when un-parenting?
assertEquals(parentInvoice.getPayments().size(), 1);
assertEquals(paymentApi.getPayment(parentInvoice.getPayments().get(0).getPaymentId(), false, false, ImmutableList.<PluginProperty>of(), callContext).getPaymentMethodId(), parentAccount.getPaymentMethodId());
// Second child invoice over Recurring period
childInvoices = invoiceUserApi.getInvoicesByAccount(childAccount.getId(), false, callContext);
assertEquals(childInvoices.size(), 2);
assertEquals(childInvoices.get(1).getBalance().compareTo(BigDecimal.ZERO), 0);
// Verify balances (the parent has paid the summary invoice, so the child invoice is automatically paid)
assertEquals(invoiceUserApi.getAccountBalance(parentAccount.getId(), callContext).compareTo(BigDecimal.ZERO), 0);
assertEquals(invoiceUserApi.getAccountBalance(childAccount.getId(), callContext).compareTo(BigDecimal.ZERO), 0);
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addDays(29 - nbDaysBeforeRetry - 1);
assertListenerStatus();
// No new invoice for the parent
parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), false, callContext);
assertEquals(parentInvoices.size(), 2);
// Third child invoice over second Recurring period
childInvoices = invoiceUserApi.getInvoicesByAccount(childAccount.getId(), false, callContext);
assertEquals(childInvoices.size(), 3);
assertEquals(childInvoices.get(2).getBalance().compareTo(BigDecimal.ZERO), 0);
// Verify the child paid the invoice this time
assertEquals(childInvoices.get(2).getPayments().size(), 1);
assertEquals(paymentApi.getPayment(childInvoices.get(2).getPayments().get(0).getPaymentId(), false, false, ImmutableList.<PluginProperty>of(), callContext).getPaymentMethodId(), childAccount.getPaymentMethodId());
// Verify balances
assertEquals(invoiceUserApi.getAccountBalance(parentAccount.getId(), callContext).compareTo(BigDecimal.ZERO), 0);
assertEquals(invoiceUserApi.getAccountBalance(childAccount.getId(), callContext).compareTo(BigDecimal.ZERO), 0);
}
use of org.killbill.billing.account.dao.AccountModelDao in project killbill by killbill.
the class DefaultAccountInternalApi method updateBCD.
@Override
public void updateBCD(final String externalKey, final int bcd, final InternalCallContext context) throws AccountApiException {
final Account currentAccount = getAccountByKey(externalKey, context);
if (currentAccount == null) {
throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, externalKey);
}
if (currentAccount.getBillCycleDayLocal() != DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL) {
throw new AccountApiException(ErrorCode.ACCOUNT_UPDATE_FAILED);
}
final MutableAccountData mutableAccountData = currentAccount.toMutableAccountData();
mutableAccountData.setBillCycleDayLocal(bcd);
final AccountModelDao accountToUpdate = new AccountModelDao(currentAccount.getId(), mutableAccountData);
bcdCacheController.remove(currentAccount.getId());
bcdCacheController.putIfAbsent(currentAccount.getId(), new Integer(bcd));
accountDao.update(accountToUpdate, context);
}
use of org.killbill.billing.account.dao.AccountModelDao in project killbill by killbill.
the class DefaultAccountUserApi method updateAccount.
private void updateAccount(final Account currentAccount, final AccountData accountData, final CallContext context) throws AccountApiException {
final Account updatedAccount = new DefaultAccount(currentAccount.getId(), accountData);
// Set unspecified (null) fields to their current values
final Account mergedAccount = updatedAccount.mergeWithDelegate(currentAccount);
final AccountModelDao updatedAccountModelDao = new AccountModelDao(currentAccount.getId(), mergedAccount);
accountDao.update(updatedAccountModelDao, internalCallContextFactory.createInternalCallContext(updatedAccountModelDao.getId(), context));
}
use of org.killbill.billing.account.dao.AccountModelDao in project killbill by killbill.
the class DefaultAccountUserApi method updateAccount.
@Override
public void updateAccount(final Account account, final CallContext context) throws AccountApiException {
// Convert to DefaultAccount to make sure we can safely call validateAccountUpdateInput
final DefaultAccount input = new DefaultAccount(account.getId(), account);
final Account currentAccount = getAccountById(input.getId(), context);
if (currentAccount == null) {
throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, input.getId());
}
input.validateAccountUpdateInput(currentAccount, true);
final AccountModelDao updatedAccountModelDao = new AccountModelDao(currentAccount.getId(), input);
accountDao.update(updatedAccountModelDao, internalCallContextFactory.createInternalCallContext(updatedAccountModelDao.getId(), context));
}
use of org.killbill.billing.account.dao.AccountModelDao in project killbill by killbill.
the class DefaultAccountUserApi method createAccount.
@Override
public Account createAccount(final AccountData data, final CallContext context) throws AccountApiException {
// Not transactional, but there is a db constraint on that column
if (data.getExternalKey() != null && getIdFromKey(data.getExternalKey(), context) != null) {
throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, data.getExternalKey());
}
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(context);
if (data.getParentAccountId() != null) {
// verify that parent account exists if parentAccountId is not null
getAccountById(data.getParentAccountId(), internalContext);
}
final AccountModelDao account = new AccountModelDao(data);
if (null != account.getExternalKey() && account.getExternalKey().length() > 255) {
throw new AccountApiException(ErrorCode.EXTERNAL_KEY_LIMIT_EXCEEDED);
}
accountDao.create(account, internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(context));
return new DefaultAccount(account);
}
Aggregations