Search in sources :

Example 6 with AccountModelDao

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);
}
Also used : DefaultAccount(org.killbill.billing.account.api.DefaultAccount) Account(org.killbill.billing.account.api.Account) AccountModelDao(org.killbill.billing.account.dao.AccountModelDao) DefaultAccount(org.killbill.billing.account.api.DefaultAccount) Invoice(org.killbill.billing.invoice.api.Invoice) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Example 7 with AccountModelDao

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);
}
Also used : DefaultAccount(org.killbill.billing.account.api.DefaultAccount) Account(org.killbill.billing.account.api.Account) AccountModelDao(org.killbill.billing.account.dao.AccountModelDao) DefaultMutableAccountData(org.killbill.billing.account.api.DefaultMutableAccountData) MutableAccountData(org.killbill.billing.account.api.MutableAccountData) AccountApiException(org.killbill.billing.account.api.AccountApiException)

Example 8 with AccountModelDao

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));
}
Also used : DefaultAccount(org.killbill.billing.account.api.DefaultAccount) Account(org.killbill.billing.account.api.Account) AccountModelDao(org.killbill.billing.account.dao.AccountModelDao) DefaultAccount(org.killbill.billing.account.api.DefaultAccount)

Example 9 with AccountModelDao

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));
}
Also used : DefaultAccount(org.killbill.billing.account.api.DefaultAccount) Account(org.killbill.billing.account.api.Account) AccountModelDao(org.killbill.billing.account.dao.AccountModelDao) DefaultAccount(org.killbill.billing.account.api.DefaultAccount) AccountApiException(org.killbill.billing.account.api.AccountApiException)

Example 10 with AccountModelDao

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);
}
Also used : AccountModelDao(org.killbill.billing.account.dao.AccountModelDao) DefaultAccount(org.killbill.billing.account.api.DefaultAccount) AccountApiException(org.killbill.billing.account.api.AccountApiException) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext)

Aggregations

AccountModelDao (org.killbill.billing.account.dao.AccountModelDao)15 DefaultAccount (org.killbill.billing.account.api.DefaultAccount)14 Account (org.killbill.billing.account.api.Account)11 Test (org.testng.annotations.Test)9 AccountApiException (org.killbill.billing.account.api.AccountApiException)6 AccountData (org.killbill.billing.account.api.AccountData)6 DefaultMutableAccountData (org.killbill.billing.account.api.DefaultMutableAccountData)6 MutableAccountData (org.killbill.billing.account.api.MutableAccountData)6 AccountTestUtils.createAccountData (org.killbill.billing.account.AccountTestUtils.createAccountData)5 AccountTestUtils.createTestAccount (org.killbill.billing.account.AccountTestUtils.createTestAccount)5 UUID (java.util.UUID)2 DateTime (org.joda.time.DateTime)2 Invoice (org.killbill.billing.invoice.api.Invoice)2 BigDecimal (java.math.BigDecimal)1 DateTimeZone (org.joda.time.DateTimeZone)1 DefaultImmutableAccountData (org.killbill.billing.account.api.DefaultImmutableAccountData)1 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)1 Currency (org.killbill.billing.catalog.api.Currency)1 AccountCreationInternalEvent (org.killbill.billing.events.AccountCreationInternalEvent)1