private void checkForTaxCodesInCustomFields(
      final Invoice invoice,
      final Collection<PluginProperty> properties,
      final TenantContext context) {
    final List<CustomField> customFields =
        killbillAPI
            .getCustomFieldUserApi()
            .getCustomFieldsForAccountType(
                invoice.getAccountId(), ObjectType.INVOICE_ITEM, context);
    if (customFields.isEmpty()) {
      return;
    }

    final Collection<UUID> invoiceItemIds = new HashSet<UUID>();
    for (final InvoiceItem invoiceItem : invoice.getInvoiceItems()) {
      invoiceItemIds.add(invoiceItem.getId());
    }

    final Iterable<CustomField> taxCodeCustomFieldsForInvoiceItems =
        Iterables.<CustomField>filter(
            customFields,
            new Predicate<CustomField>() {
              @Override
              public boolean apply(final CustomField customField) {
                return AvaTaxTaxCalculator.TAX_CODE.equals(customField.getFieldName())
                    && invoiceItemIds.contains(customField.getObjectId());
              }
            });
    for (final CustomField customField : taxCodeCustomFieldsForInvoiceItems) {
      final UUID invoiceItemId = customField.getObjectId();
      final String taxCode = customField.getFieldValue();
      addTaxCodeToInvoiceItem(invoiceItemId, taxCode, properties);
    }
  }
 private InvoiceItem createTaxInvoiceItem(final Invoice invoice) {
   return new TaxInvoiceItem(
       invoice.getId(),
       invoice.getAccountId(),
       null,
       "Tax Item",
       clock.getUTCNow().toLocalDate(),
       BigDecimal.ONE,
       invoice.getCurrency());
 }
  private void checkForTaxExemption(
      final Invoice invoice,
      final Collection<PluginProperty> properties,
      final TenantContext context) {
    // Overridden by plugin properties?
    if (PluginProperties.findPluginPropertyValue(
            AvaTaxTaxCalculator.CUSTOMER_USAGE_TYPE, properties)
        != null) {
      return;
    }

    final List<CustomField> customFields =
        killbillAPI
            .getCustomFieldUserApi()
            .getCustomFieldsForObject(invoice.getAccountId(), ObjectType.ACCOUNT, context);
    final CustomField customField =
        Iterables.<CustomField>tryFind(
                customFields,
                new Predicate<CustomField>() {
                  @Override
                  public boolean apply(final CustomField customField) {
                    return AvaTaxTaxCalculator.CUSTOMER_USAGE_TYPE.equals(
                        customField.getFieldName());
                  }
                })
            .orNull();

    if (customField != null) {
      properties.add(
          new PluginProperty(
              AvaTaxTaxCalculator.CUSTOMER_USAGE_TYPE, customField.getFieldValue(), false));
    }
  }
Example #4
0
 private List<PluginProperty> createPropertiesForInvoice(final Invoice invoice) {
   final List<PluginProperty> result = new ArrayList<PluginProperty>();
   result.add(
       new PluginProperty(
           InvoicePaymentRoutingPluginApi.PROP_IPCD_INVOICE_ID,
           invoice.getId().toString(),
           false));
   return result;
 }
  private void checkForTaxCodesOnProducts(
      final Invoice invoice,
      final Collection<PluginProperty> properties,
      final TenantContext context) {
    final Map<String, String> planToProductCache = new HashMap<String, String>();
    final Map<String, String> productToTaxCodeCache = new HashMap<String, String>();

    for (final InvoiceItem invoiceItem : invoice.getInvoiceItems()) {
      final String planName = invoiceItem.getPlanName();
      if (planName == null) {
        continue;
      }

      if (planToProductCache.get(planName) == null) {
        try {
          final StaticCatalog catalog =
              killbillAPI.getCatalogUserApi().getCurrentCatalog(null, context);
          final Plan plan = catalog.findCurrentPlan(planName);
          planToProductCache.put(planName, plan.getProduct().getName());
        } catch (final CatalogApiException e) {
          continue;
        }
      }
      final String productName = planToProductCache.get(planName);
      if (productName == null) {
        continue;
      }

      if (productToTaxCodeCache.get(productName) == null) {
        try {
          final String taxCode = dao.getTaxCode(productName, context.getTenantId());
          productToTaxCodeCache.put(productName, taxCode);
        } catch (final SQLException e) {
          continue;
        }
      }

      final String taxCode = productToTaxCodeCache.get(productName);
      if (taxCode != null) {
        addTaxCodeToInvoiceItem(
            invoiceItem.getId(), productToTaxCodeCache.get(productName), properties);
      }
    }
  }
  private void setupIntegration(
      final PaymentPluginApiException expectedException,
      final RuntimeException expectedRuntimeException)
      throws Exception {

    final PaymentPluginApiWithTestControl paymentPluginApi = getTestPluginPaymentApi();

    final AccountData accountData = getAccountData(1);
    final Account account = createAccountWithOsgiPaymentMethod(accountData);

    // We take april as it has 30 days (easier to play with BCD)
    // Set clock to the initial start date - we implicitly assume here that the account timezone is
    // UTC
    clock.setDay(new LocalDate(2012, 4, 1));
    //
    // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
    //
    final DefaultEntitlement baseEntitlement =
        createBaseEntitlementAndCheckForCompletion(
            account.getId(),
            "externalKey",
            "Shotgun",
            ProductCategory.BASE,
            BillingPeriod.MONTHLY,
            NextEvent.CREATE,
            NextEvent.INVOICE);
    //
    // ADD ADD_ON ON THE SAME DAY TO TRIGGER PAYMENT
    //

    final List<NextEvent> expectedEvents = new LinkedList<NextEvent>();
    expectedEvents.add(NextEvent.CREATE);
    expectedEvents.add(NextEvent.INVOICE);
    if (expectedException == null && expectedRuntimeException == null) {
      expectedEvents.add(NextEvent.PAYMENT);
    } else if (expectedException != null) {
      expectedEvents.add(NextEvent.PAYMENT_PLUGIN_ERROR);
      paymentPluginApi.setPaymentPluginApiExceptionOnNextCalls(expectedException);
    } else if (expectedRuntimeException != null) {
      expectedEvents.add(NextEvent.PAYMENT_PLUGIN_ERROR);
      paymentPluginApi.setPaymentRuntimeExceptionOnNextCalls(expectedRuntimeException);
    }

    final DefaultEntitlement aoEntitlement =
        addAOEntitlementAndCheckForCompletion(
            baseEntitlement.getBundleId(),
            "Telescopic-Scope",
            ProductCategory.ADD_ON,
            BillingPeriod.MONTHLY,
            expectedEvents.toArray(new NextEvent[expectedEvents.size()]));

    final Invoice invoice =
        invoiceChecker.checkInvoice(
            account.getId(),
            2,
            callContext,
            new ExpectedInvoiceItemCheck(
                new LocalDate(2012, 4, 1),
                new LocalDate(2012, 5, 1),
                InvoiceItemType.RECURRING,
                new BigDecimal("399.95")));

    if (expectedException == null && expectedRuntimeException == null) {
      paymentChecker.checkPayment(
          account.getId(),
          1,
          callContext,
          new ExpectedPaymentCheck(
              new LocalDate(2012, 4, 1),
              new BigDecimal("399.95"),
              PaymentStatus.SUCCESS,
              invoice.getId(),
              Currency.USD));
    } else if (expectedException != null) {
      paymentChecker.checkPayment(
          account.getId(),
          1,
          callContext,
          new ExpectedPaymentCheck(
              new LocalDate(2012, 4, 1),
              new BigDecimal("399.95"),
              PaymentStatus.PLUGIN_FAILURE,
              invoice.getId(),
              Currency.USD));
    } else if (expectedRuntimeException != null) {
      paymentChecker.checkPayment(
          account.getId(),
          1,
          callContext,
          new ExpectedPaymentCheck(
              new LocalDate(2012, 4, 1),
              new BigDecimal("399.95"),
              PaymentStatus.PLUGIN_FAILURE,
              invoice.getId(),
              Currency.USD));
    }
  }
Example #7
0
  @Test(groups = "slow")
  public void testCreateSuccessRefundPaymentControlWithItemAdjustments()
      throws PaymentApiException, InvoiceApiException, EventBusException {

    final BigDecimal requestedAmount = BigDecimal.TEN;
    final UUID subscriptionId = UUID.randomUUID();
    final UUID bundleId = UUID.randomUUID();
    final LocalDate now = clock.getUTCToday();

    final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD);

    final String paymentExternalKey = invoice.getId().toString();
    final String transactionExternalKey = "craboom";
    final String transactionExternalKey2 = "qwerty";

    final InvoiceItem invoiceItem =
        new MockRecurringInvoiceItem(
            invoice.getId(),
            account.getId(),
            subscriptionId,
            bundleId,
            "test plan",
            "test phase",
            null,
            now,
            now.plusMonths(1),
            requestedAmount,
            new BigDecimal("1.0"),
            Currency.USD);
    invoice.addInvoiceItem(invoiceItem);

    final Payment payment =
        paymentApi.createPurchaseWithPaymentControl(
            account,
            account.getPaymentMethodId(),
            null,
            requestedAmount,
            Currency.USD,
            paymentExternalKey,
            transactionExternalKey,
            createPropertiesForInvoice(invoice),
            INVOICE_PAYMENT,
            callContext);

    final List<PluginProperty> refundProperties = new ArrayList<PluginProperty>();
    final HashMap<UUID, BigDecimal> uuidBigDecimalHashMap = new HashMap<UUID, BigDecimal>();
    uuidBigDecimalHashMap.put(invoiceItem.getId(), new BigDecimal("1.0"));
    final PluginProperty refundIdsProp =
        new PluginProperty(
            InvoicePaymentRoutingPluginApi.PROP_IPCD_REFUND_IDS_WITH_AMOUNT_KEY,
            uuidBigDecimalHashMap,
            false);
    refundProperties.add(refundIdsProp);

    final Payment payment2 =
        paymentApi.createRefundWithPaymentControl(
            account,
            payment.getId(),
            null,
            Currency.USD,
            transactionExternalKey2,
            refundProperties,
            INVOICE_PAYMENT,
            callContext);

    assertEquals(payment2.getTransactions().size(), 2);
    PaymentTransaction refundTransaction = payment2.getTransactions().get(1);
    assertEquals(refundTransaction.getTransactionType(), TransactionType.REFUND);

    final List<PaymentAttemptModelDao> attempts =
        paymentDao.getPaymentAttempts(paymentExternalKey, internalCallContext);
    assertEquals(attempts.size(), 2);

    final PaymentAttemptModelDao refundAttempt = attempts.get(1);
    assertEquals(refundAttempt.getTransactionType(), TransactionType.REFUND);

    // Ok now the fun part starts... we modify the attempt state to be 'INIT' and wait the the
    // Janitor to do its job.
    paymentDao.updatePaymentAttempt(
        refundAttempt.getId(), refundAttempt.getTransactionId(), "INIT", internalCallContext);
    final PaymentAttemptModelDao attempt2 =
        paymentDao.getPaymentAttempt(refundAttempt.getId(), internalCallContext);
    assertEquals(attempt2.getStateName(), "INIT");

    clock.addDays(1);
    try {
      Thread.sleep(1500);
    } catch (InterruptedException e) {
    }

    final PaymentAttemptModelDao attempt3 =
        paymentDao.getPaymentAttempt(refundAttempt.getId(), internalCallContext);
    assertEquals(attempt3.getStateName(), "SUCCESS");
  }
Example #8
0
  @Test(groups = "slow")
  public void testCreateSuccessPurchaseWithPaymentControl()
      throws PaymentApiException, InvoiceApiException, EventBusException {

    final BigDecimal requestedAmount = BigDecimal.TEN;
    final UUID subscriptionId = UUID.randomUUID();
    final UUID bundleId = UUID.randomUUID();
    final LocalDate now = clock.getUTCToday();

    final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD);

    final String paymentExternalKey = invoice.getId().toString();
    final String transactionExternalKey = "wouf wouf";

    invoice.addInvoiceItem(
        new MockRecurringInvoiceItem(
            invoice.getId(),
            account.getId(),
            subscriptionId,
            bundleId,
            "test plan",
            "test phase",
            null,
            now,
            now.plusMonths(1),
            requestedAmount,
            new BigDecimal("1.0"),
            Currency.USD));

    final Payment payment =
        paymentApi.createPurchaseWithPaymentControl(
            account,
            account.getPaymentMethodId(),
            null,
            requestedAmount,
            Currency.USD,
            paymentExternalKey,
            transactionExternalKey,
            createPropertiesForInvoice(invoice),
            INVOICE_PAYMENT,
            callContext);
    assertEquals(payment.getTransactions().size(), 1);
    assertEquals(
        payment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.SUCCESS);
    assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);

    final List<PaymentAttemptModelDao> attempts =
        paymentDao.getPaymentAttempts(paymentExternalKey, internalCallContext);
    assertEquals(attempts.size(), 1);

    final PaymentAttemptModelDao attempt = attempts.get(0);
    assertEquals(attempt.getStateName(), "SUCCESS");

    // Ok now the fun part starts... we modify the attempt state to be 'INIT' and wait the the
    // Janitor to do its job.
    paymentDao.updatePaymentAttempt(
        attempt.getId(), attempt.getTransactionId(), "INIT", internalCallContext);
    final PaymentAttemptModelDao attempt2 =
        paymentDao.getPaymentAttempt(attempt.getId(), internalCallContext);
    assertEquals(attempt2.getStateName(), "INIT");

    clock.addDays(1);
    try {
      Thread.sleep(1500);
    } catch (InterruptedException e) {
    }

    final PaymentAttemptModelDao attempt3 =
        paymentDao.getPaymentAttempt(attempt.getId(), internalCallContext);
    assertEquals(attempt3.getStateName(), "SUCCESS");
  }