diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f793ef..0d74c37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,7 @@ name: ci on: - push + - pull_request - workflow_dispatch jobs: @@ -9,6 +10,5 @@ jobs: uses: killbill/gh-actions-shared/.github/workflows/ci.yml@main with: test-profile-matrix: '[ "travis", "integration-mysql", "integration-postgresql" ]' - jdk-matrix: '[ "8", "11" ]' secrets: extra-env: '{ "VERTEX_URL": "${{ secrets.VERTEX_URL }}", "VERTEX_CLIENT_ID": "${{ secrets.VERTEX_CLIENT_ID }}", "VERTEX_CLIENT_SECRET": "${{ secrets.VERTEX_CLIENT_SECRET }}", "VERTEX_COMPANY_NAME": "${{ secrets.VERTEX_COMPANY_NAME }}", "VERTEX_COMPANY_DIVISION": "${{ secrets.VERTEX_COMPANY_DIVISION }}"}' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c8bfeeb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,91 @@ +name: release + +on: + workflow_dispatch: + inputs: + parent_version: + description: 'New killbill-oss-parent version' + required: false + default: '' + perform_version: + description: 'tag to (re-)perform (in case of release:perform failure)' + required: false + default: '' + +env: + MAVEN_FLAGS: "-B --no-transfer-progress" + MAVEN_OPTS: "-Xmx2G -XX:+ExitOnOutOfMemoryError -Dmaven.wagon.rto=60000 -Dmaven.wagon.httpconnectionManager.ttlSeconds=25 -Dmaven.wagon.http.retryHandler.count=3" + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + if: github.event.inputs.perform_version == '' + uses: actions/checkout@v2 + - name: Checkout full repository + # Required when performing an existing release. + if: github.event.inputs.perform_version != '' + uses: actions/checkout@v2 + with: + fetch-depth: '0' + - name: Setup git user + env: + BUILD_USER: ${{ secrets.BUILD_USER }} + BUILD_TOKEN: ${{ secrets.BUILD_TOKEN }} + run: | + git config --global user.email "contact@killbill.io" + git config --global user.name "Kill Bill core team" + git config --global url."https://${BUILD_USER}:${BUILD_TOKEN}@github.com/".insteadOf "git@github.com:" + - name: Configure Java + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Download Java dependencies + # We do as much as we can, but it may not be enough (https://issues.apache.org/jira/browse/MDEP-82) + run: | + mvn ${MAVEN_FLAGS} clean install dependency:resolve dependency:resolve-plugins -DskipTests=true -Dgpg.skip=true -Psonatype-oss-release + - name: Update killbill-oss-parent + if: github.event.inputs.parent_version != '' + run: | + echo "Updating killbill-oss-parent pom.xml to ${{ github.event.inputs.parent_version }}:" + mvn ${MAVEN_FLAGS} versions:update-parent -DgenerateBackupPoms=false -DparentVersion="[${{ github.event.inputs.parent_version }}]" + echo "killbill-oss-parent pom.xml changes:" + git --no-pager diff + echo "Downloading new dependencies:" + mvn ${MAVEN_FLAGS} -U clean install -DskipTests=true + + git add pom.xml + # Will be pushed as part of the release process, only if the release is successful + git commit -m "pom.xml: update killbill-oss-parent to ${{ github.event.inputs.parent_version }}" + - name: Configure settings.xml for release + uses: actions/setup-java@v3 + with: + java-version: 11 + distribution: temurin + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.GPG_SIGNING_KEY }} + gpg-passphrase: GPG_PASSPHRASE + - name: Release artifacts + if: github.event.inputs.perform_version == '' + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + # It will still check the remote but hopefully not download much (0 B at 0 B/s). -o isn't safe because of MDEP-82 (see above). + run: | + mvn ${MAVEN_FLAGS} release:clean release:prepare release:perform + - name: Perform release + if: github.event.inputs.perform_version != '' + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + # It will still check the remote but hopefully not download much (0 B at 0 B/s). -o isn't safe because of MDEP-82 (see above). + # See https://issues.apache.org/jira/browse/SCM-729 for why the release.properties file is required. + run: | + echo "scm.url=scm\:git\:git@github.com\:${GITHUB_REPOSITORY}.git" > release.properties + echo "scm.tag=${{ github.event.inputs.perform_version }}" >> release.properties + mvn ${MAVEN_FLAGS} release:perform diff --git a/README.md b/README.md index 6632158..9bbe469 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,16 @@ Kill Bill compatibility ----------------------- | Plugin version | Kill Bill version | -| -------------: | ----------------: | -| 0.1.y | 0.22.z | +|---------------:|------------------:| +| 0.1.y | 0.22.z | +| 0.2.y | 0.24.z | +Requirements +------------- + +The plugin needs a database. The latest version of the schema can be found [here](https://github.com/killbill/killbill-vertex-plugin/tree/master/src/main/resources). + Configuration ------------- diff --git a/pom.xml b/pom.xml index 1dc51a3..97fd806 100644 --- a/pom.xml +++ b/pom.xml @@ -20,11 +20,11 @@ org.kill-bill.billing killbill-oss-parent - 0.144.85 + 0.146.63 org.kill-bill.billing.plugin.java vertex-plugin - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT bundle Kill Bill OSGI Vertex plugin Kill Bill Vertex plugin @@ -57,7 +57,8 @@ com.fasterxml.jackson.core jackson-databind - 2.13.4.1 + 2.13.4.1 + com.fasterxml.jackson.datatype @@ -88,17 +89,12 @@ io.airlift - testing-mysql-server + units test - io.airlift - testing-postgresql-server - test - - - io.airlift - units + io.zonky.test + embedded-postgres test @@ -107,13 +103,13 @@ 1.3.5 - javax.inject - javax.inject + jakarta.servlet + jakarta.servlet-api + provided - javax.servlet - javax.servlet-api - provided + javax.inject + javax.inject joda-time @@ -147,10 +143,6 @@ org.slf4j slf4j-api - - org.reactivestreams - reactive-streams - @@ -170,6 +162,12 @@ org.kill-bill.billing killbill-platform-test test + + + com.fasterxml.jackson.core + jackson-databind + + org.kill-bill.billing.plugin @@ -179,12 +177,37 @@ org.kill-bill.billing.plugin.java killbill-base-plugin + + + org.jooq + jooq + + + com.fasterxml.jackson.core + jackson-databind + + + org.kill-bill.billing.plugin.java killbill-base-plugin test-jar test + + + org.reactivestreams + reactive-streams + + + com.fasterxml.jackson.core + jackson-databind + + + org.jooq + jooq + + org.kill-bill.commons @@ -205,6 +228,11 @@ + + org.kill-bill.testing + testing-mysql-server + test + org.mockito mockito-core diff --git a/src/main/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApi.java b/src/main/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApi.java index 73fb025..ec2adde 100644 --- a/src/main/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApi.java +++ b/src/main/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApi.java @@ -28,12 +28,14 @@ import org.killbill.billing.account.api.Account; import org.killbill.billing.invoice.api.Invoice; import org.killbill.billing.invoice.api.InvoiceItem; +import org.killbill.billing.invoice.plugin.api.AdditionalItemsResult; import org.killbill.billing.invoice.plugin.api.InvoiceContext; import org.killbill.billing.invoice.plugin.api.OnSuccessInvoiceResult; import org.killbill.billing.osgi.libs.killbill.OSGIConfigPropertiesService; import org.killbill.billing.osgi.libs.killbill.OSGIKillbillAPI; import org.killbill.billing.payment.api.PluginProperty; import org.killbill.billing.plugin.api.PluginProperties; +import org.killbill.billing.plugin.api.invoice.PluginAdditionalItemsResult; import org.killbill.billing.plugin.api.invoice.PluginInvoicePluginApi; import org.killbill.billing.plugin.vertex.dao.VertexDao; import org.killbill.billing.plugin.vertex.gen.ApiException; @@ -71,12 +73,12 @@ public VertexInvoicePluginApi(final VertexApiConfigurationHandler vertexApiConfi } @Override - public List getAdditionalInvoiceItems(final Invoice invoice, - final boolean dryRun, - final Iterable properties, - final CallContext context) { + public AdditionalItemsResult getAdditionalInvoiceItems(final Invoice invoice, + final boolean dryRun, + final Iterable properties, + final InvoiceContext context) { if (PluginProperties.findPluginPropertyValue("VERTEX_SKIP", properties) != null) { - return ImmutableList.of(); + return null; } final Collection pluginProperties = Lists.newArrayList(properties); @@ -86,7 +88,9 @@ public List getAdditionalInvoiceItems(final Invoice invoice, checkForTaxCodes(invoice, pluginProperties, context); try { - return calculator.compute(account, invoice, dryRun, pluginProperties, context); + List invoiceItems = calculator.compute(account, invoice, dryRun, pluginProperties, context); + final AdditionalItemsResult additionalItemsResult = new PluginAdditionalItemsResult(invoiceItems, null); + return additionalItemsResult; } catch (final Exception e) { // Prevent invoice generation throw new RuntimeException(e); diff --git a/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiITest.java b/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiITest.java index 4d521e5..dc421db 100644 --- a/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiITest.java +++ b/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiITest.java @@ -32,6 +32,7 @@ import org.killbill.billing.invoice.api.InvoiceItem; import org.killbill.billing.invoice.api.InvoiceItemType; import org.killbill.billing.invoice.api.InvoiceUserApi; +import org.killbill.billing.invoice.plugin.api.boilerplate.plugin.InvoiceContextImp; import org.killbill.billing.osgi.libs.killbill.OSGIConfigPropertiesService; import org.killbill.billing.osgi.libs.killbill.OSGIKillbillAPI; import org.killbill.billing.payment.api.PluginProperty; @@ -107,7 +108,7 @@ public void testItemAdjustments() { final InvoiceItem taxableItem1 = TestUtils.buildInvoiceItem(invoice, InvoiceItemType.EXTERNAL_CHARGE, new BigDecimal("100"), null); invoiceItems.add(taxableItem1); pluginProperties.add(new PluginProperty(String.format("%s_%s", VertexTaxCalculator.TAX_CODE, taxableItem1.getId()), "D9999999", false)); - List additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, callContext); + List additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()).getAdditionalItems(); // TAX expected (total $8.63) checkTaxes(additionalInvoiceItems, new BigDecimal("8.63")); @@ -117,7 +118,7 @@ public void testItemAdjustments() { * $8.63 Tax */ invoiceItems.addAll(additionalInvoiceItems); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()).getAdditionalItems(); checkTaxes(additionalInvoiceItems, BigDecimal.ZERO); /* @@ -129,7 +130,7 @@ public void testItemAdjustments() { */ final InvoiceItem itemAdjustment2 = TestUtils.buildInvoiceItem(invoice, InvoiceItemType.ITEM_ADJ, new BigDecimal("-50"), taxableItem1.getId()); invoiceItems.add(itemAdjustment2); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()).getAdditionalItems(); // TAX expected (total -$4.32) checkTaxes(additionalInvoiceItems, new BigDecimal("-4.31")); @@ -141,7 +142,7 @@ public void testItemAdjustments() { * -$4.32 Tax */ invoiceItems.addAll(additionalInvoiceItems); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()).getAdditionalItems(); checkTaxes(additionalInvoiceItems, BigDecimal.ZERO); /* @@ -154,7 +155,7 @@ public void testItemAdjustments() { */ final InvoiceItem itemAdjustment3 = TestUtils.buildInvoiceItem(invoice, InvoiceItemType.ITEM_ADJ, new BigDecimal("-50"), taxableItem1.getId()); invoiceItems.add(itemAdjustment3); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()).getAdditionalItems(); checkTaxes(additionalInvoiceItems, new BigDecimal("-4.31")); /* @@ -167,7 +168,7 @@ public void testItemAdjustments() { * -$4.32 Tax */ invoiceItems.addAll(additionalInvoiceItems); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()).getAdditionalItems(); checkTaxes(additionalInvoiceItems, BigDecimal.ZERO); } @@ -196,7 +197,7 @@ public void testRepair() throws Exception { final InvoiceItem taxableItem1 = TestUtils.buildInvoiceItem(invoice1, InvoiceItemType.RECURRING, new BigDecimal("100"), null); invoiceItems1.add(taxableItem1); pluginProperties.add(new PluginProperty(String.format("%s_%s", VertexTaxCalculator.TAX_CODE, taxableItem1.getId()), "D9999999", false)); - List additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice1, false, pluginProperties, callContext); + List additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice1, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice1).withIsDryRun(false).build()).getAdditionalItems(); // TAX expected (total $8.63) checkTaxes(additionalInvoiceItems, new BigDecimal("8.63")); @@ -206,7 +207,7 @@ public void testRepair() throws Exception { * $8.63 Tax */ invoiceItems1.addAll(additionalInvoiceItems); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice1, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice1, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice1).withIsDryRun(false).build()).getAdditionalItems(); checkTaxes(additionalInvoiceItems, BigDecimal.ZERO); /* @@ -220,7 +221,7 @@ public void testRepair() throws Exception { invoiceItems2.add(repair2); Mockito.when(osgiKillbillAPI.getInvoiceUserApi().getInvoiceByInvoiceItem(Mockito.eq(taxableItem1.getId()), Mockito.any())) .thenReturn(invoice1); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice2, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice2, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice1).withIsDryRun(false).build()).getAdditionalItems(); // TAX expected (total -$4.32) checkTaxes(additionalInvoiceItems, new BigDecimal("-4.31")); @@ -230,7 +231,7 @@ public void testRepair() throws Exception { * -$4.32 Tax */ invoiceItems2.addAll(additionalInvoiceItems); - additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice2, false, pluginProperties, callContext); + additionalInvoiceItems = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice2, false, pluginProperties, new InvoiceContextImp.Builder<>().withInvoice(invoice1).withIsDryRun(false).build()).getAdditionalItems(); checkTaxes(additionalInvoiceItems, BigDecimal.ZERO); } diff --git a/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiTest.java b/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiTest.java index 291b547..2fb2e04 100644 --- a/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiTest.java +++ b/src/test/java/org/killbill/billing/plugin/vertex/VertexInvoicePluginApiTest.java @@ -29,8 +29,10 @@ import org.killbill.billing.account.api.AccountUserApi; import org.killbill.billing.invoice.api.Invoice; import org.killbill.billing.invoice.api.InvoiceItem; +import org.killbill.billing.invoice.plugin.api.AdditionalItemsResult; import org.killbill.billing.invoice.plugin.api.InvoiceContext; import org.killbill.billing.invoice.plugin.api.OnSuccessInvoiceResult; +import org.killbill.billing.invoice.plugin.api.boilerplate.plugin.InvoiceContextImp; import org.killbill.billing.osgi.libs.killbill.OSGIKillbillAPI; import org.killbill.billing.payment.api.PluginProperty; import org.killbill.billing.plugin.vertex.dao.VertexDao; @@ -38,6 +40,7 @@ import org.killbill.billing.plugin.vertex.gen.dao.model.tables.records.VertexResponsesRecord; import org.killbill.billing.util.api.CustomFieldUserApi; import org.killbill.billing.util.callcontext.CallContext; +import org.killbill.billing.util.callcontext.TenantContext; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; @@ -50,6 +53,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; @@ -98,7 +102,7 @@ public void setUp() throws AccountApiException { final UUID accountId = UUID.randomUUID(); given(account.getId()).willReturn(accountId); - given(accountUserApi.getAccountById(account.getId(), callContext)).willReturn(account); + given(accountUserApi.getAccountById(eq(account.getId()), any(TenantContext.class))).willReturn(account); given(invoice.getAccountId()).willReturn(accountId); @@ -127,15 +131,8 @@ public void testGetAdditionalInvoiceItemsWhenVertexSkipPropertyPresent() throws final Iterable properties = Collections.singletonList(new PluginProperty("VERTEX_SKIP", "anyValue", false)); //when - List result = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, properties, callContext); - - //then - assertEquals(0, result.size()); - verify(vertexTaxCalculator, times(0)).compute(any(Account.class), any(Invoice.class), anyBoolean(), anyList(), any(CallContext.class)); - verify(invoice, times(0)).getInvoiceItems(); - verify(invoice, times(0)).getAccountId(); - verify(killbillAPI, times(0)).getAccountUserApi(); - verify(accountUserApi, times(0)).getAccountById(any(UUID.class), any(CallContext.class)); + AdditionalItemsResult result = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, properties, new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()); + assertEquals(null, result); } @Test(groups = "fast", expectedExceptions = {RuntimeException.class}) @@ -144,7 +141,7 @@ public void testPreventInvoiceGenerationOnExceptionInGetAdditionalInvoiceItems() doThrow(Exception.class).when(vertexTaxCalculator).compute(any(Account.class), any(Invoice.class), anyBoolean(), anyList(), any(CallContext.class)); //when - vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, Collections.emptyList(), callContext); + vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, Collections.emptyList(), new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build()).getAdditionalItems(); } @Test(groups = "fast") @@ -152,16 +149,17 @@ public void testGetAdditionalInvoiceItemsWithoutCustomFields() throws Exception //given final Iterable properties = Collections.emptyList(); final List invoiceItems = Collections.singletonList(Mockito.mock(InvoiceItem.class)); - given(vertexTaxCalculator.compute(account, invoice, false, properties, callContext)).willReturn(invoiceItems); + final InvoiceContext invContext = new InvoiceContextImp.Builder<>().withInvoice(invoice).withIsDryRun(false).build(); + given(vertexTaxCalculator.compute(account, invoice, false, properties, invContext)).willReturn(invoiceItems); given(customFieldUserApi.getCustomFieldsForAccountType(invoice.getAccountId(), ObjectType.INVOICE_ITEM, callContext)).willReturn(Collections.emptyList()); //when - List result = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, properties, callContext); + List result = vertexInvoicePluginApi.getAdditionalInvoiceItems(invoice, false, properties, invContext).getAdditionalItems(); //then assertEquals(invoiceItems.size(), result.size()); - verify(vertexTaxCalculator).compute(account, invoice, false, properties, callContext); + verify(vertexTaxCalculator).compute(account, invoice, false, properties, invContext); verify(killbillAPI).getAccountUserApi(); verify(accountUserApi).getAccountById(any(UUID.class), any(CallContext.class));