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)); } }
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)); } }
@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"); }
@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"); }