[plugin-invoice] Unable to implement InvoicePluginApi

51 views
Skip to first unread message

Ismaël PANOR

unread,
Jun 4, 2025, 11:00:19 AM6/4/25
to Kill Bill users mailing-list

I’m developing an Invoice Control Plugin for Kill Bill v0.27.3, but I’m hitting compilation errors due to missing symbols and method signatures that don’t match the API in killbill-plugin-api-invoice-0.27.3.jar

Kill Bill API: org.kill-bill.billing:killbill-api:0.54.0

Invoice Plugin API: org.kill-bill.billing.plugin:killbill-plugin-api-invoice:0.27.3

Joda-Time (for retry): joda-time:2.12.5

Java 8, Maven 3.8+, macOS

----------------------------------------------
pom.xml

<dependencies>
  <!-- Usage API -->
  <dependency>
    <groupId>org.kill-bill.billing</groupId>
    <artifactId>killbill-api</artifactId>
    <version>0.54.0</version>
    <scope>provided</scope>
  </dependency>

  <!-- Invoice Plugin API -->
  <dependency>
    <groupId>org.kill-bill.billing.plugin</groupId>
    <artifactId>killbill-plugin-api-invoice</artifactId>
    <version>0.27.3</version>
    <scope>provided</scope>
  </dependency>

  <!-- Joda-Time -->
  <dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.12.5</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

----------------------------------------------------
Java code

package com.monsociete.plugin;

import org.killbill.billing.invoice.plugin.api.InvoicePluginApi;
import org.killbill.billing.invoice.plugin.api.InvoicePluginApiException;
import org.killbill.billing.invoice.plugin.api.InvoicePluginApiRetryException;
import org.killbill.billing.invoice.plugin.api.InvoiceContext;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceItem;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.usage.api.UsageUserApi;
import org.killbill.billing.usage.api.UsageRecord;
import org.killbill.billing.util.callcontext.TenantContext;

import org.joda.time.Period;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.UUID;


public class MyInvoiceControlPlugin implements InvoicePluginApi {

    private final UsageUserApi usageUserApi;

    public MyInvoiceControlPlugin(final UsageUserApi usageUserApi) {
        this.usageUserApi = usageUserApi;
    }

    @Override
    public Iterable<InvoiceItem> getAdditionalInvoiceItems(final Invoice invoice,
                                                           final Iterable<PluginProperty> properties,
                                                           final InvoiceContext context)
            throws InvoicePluginApiException {

        UUID accountId = context.getAccountId();
        TenantContext tenantContext = context.getTenantContext();

        if (!accountHasUsagePlans(accountId, tenantContext)) {
            return Collections.emptyList();
        }

        if (!areUsageDataUpToDate(accountId, tenantContext)) {
            throw new InvoicePluginApiRetryException(Collections.singletonList(Period.hours(1)));
        }

        return Collections.emptyList();
    }

    private boolean accountHasUsagePlans(final UUID accountId,
                                         final TenantContext tenantContext) {
        return true;
    }

    private boolean areUsageDataUpToDate(final UUID accountId,
                                         final TenantContext tenantContext) {
        try {
            LocalDate today = LocalDate.now();
            LocalDateTime start = today.minusDays(1).atStartOfDay();
            LocalDateTime end   = today.atTime(23, 59);

            List<UsageRecord> records = usageUserApi.getUsageForAccount(
                    accountId, start, end, tenantContext
            );
            return !records.isEmpty();
        } catch (Exception e) {
            return false;
        }
    }
}

--------------------------------------------------------

Is there a built-in feature that automatically prevents an invoice from being generated if usage data is not up to date?

Reshma Bidikar

unread,
Jun 6, 2025, 12:33:06 AM6/6/25
to Kill Bill users mailing-list
Hello,

The latest KB version is 0.24.11 and it requires Java 11. It appears that you are using Java 8. Could you fix your Java version and give it a try?

Regards,
Reshma

Ismaël PANOR

unread,
Jun 18, 2025, 11:06:56 AM6/18/25
to Kill Bill users mailing-list
Hi Reshma, 

Thank you for your feedback.

I've configured my pom.xml to use Java 11, however I'm still encountering errors that I haven't been able to resolve despite several attempts.

Pom.xml 

<modelVersion>4.0.0</modelVersion>

<groupId>com.monsociete.plugin</groupId>
<artifactId>my-invoice-control-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<killbill.plugin.api.invoice.version>0.27.3</killbill.plugin.api.invoice.version>
<killbill.api.version>0.54.0</killbill.api.version>
</properties>

<repositories>
<repository>
<id>central</id>
</repository>
<repository>
<id>kill-bill</id>
</repository>
</repositories>

<dependencies>
<!-- Kill Bill API for UsageUserApi -->
<dependency>
<groupId>org.kill-bill.billing</groupId>
<artifactId>killbill-api</artifactId>
<version>${killbill.api.version}</version>
<scope>provided</scope>
</dependency>
<!-- Invoice Plugin API -->
<dependency>
<groupId>org.kill-bill.billing.plugin</groupId>
<artifactId>killbill-plugin-api-invoice</artifactId>
<version>${killbill.plugin.api.invoice.version}</version>
<scope>provided</scope>
</dependency>
<!-- Joda-Time for retry exception -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.12.5</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>


Java code

package com.monsociete.plugin;

import org.killbill.billing.invoice.plugin.api.*;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceItem;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.usage.api.UsageUserApi;
import org.killbill.billing.usage.api.RolledUpUsage;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.TenantContext;
import org.joda.time.Period;
import org.joda.time.DateTime;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

public class MyInvoiceControlPlugin implements InvoicePluginApi {

private final UsageUserApi usageUserApi;

public MyInvoiceControlPlugin(final UsageUserApi usageUserApi) {
this.usageUserApi = usageUserApi;
}

// Méthode manquante - OBLIGATOIRE dans les nouvelles versions
@Override
public InvoiceGroupingResult getInvoiceGrouping(final Invoice invoice,
final boolean dryRun,
final Iterable<PluginProperty> properties,
final InvoiceContext context) {
// Retourne null pour désactiver le grouping d'invoices personnalisé
return null;
}

@Override
public Iterable<InvoiceItem> getAdditionalInvoiceItems(final Invoice invoice,
final boolean dryRun,
final Iterable<PluginProperty> properties,
final InvoiceContext context) {
UUID accountId = context.getAccountId();
// CORRECTION: utiliser toCallContext() au lieu de getCallContext()
CallContext callContext = context.toCallContext(null);

if (!accountHasUsagePlans(accountId, callContext)) {
return Collections.emptyList();
}

if (!areUsageDataUpToDate(accountId, callContext)) {
throw new InvoicePluginApiRetryException(Collections.singletonList(Period.hours(1)));
}

return Collections.emptyList();
}

@Override
public OnFailureInvoiceResult onFailureCall(final InvoiceContext context,
final Iterable<PluginProperty> properties) {
// CORRECTION: utiliser une implémentation concrète
return new DefaultOnFailureInvoiceResult();
}

@Override
public OnSuccessInvoiceResult onSuccessCall(final InvoiceContext context,
final Iterable<PluginProperty> properties) {
// CORRECTION: utiliser une implémentation concrète
return new DefaultOnSuccessInvoiceResult();
}

private boolean accountHasUsagePlans(final UUID accountId,
final TenantContext tenantContext) {
return true;
}

private boolean areUsageDataUpToDate(final UUID accountId,
final TenantContext tenantContext) {
try {
LocalDate today = LocalDate.now();
LocalDateTime startLocal = today.minusDays(1).atStartOfDay();
LocalDateTime endLocal = today.atTime(23, 59);

DateTime start = new DateTime(startLocal.getYear(), startLocal.getMonthValue(),
startLocal.getDayOfMonth(), startLocal.getHour(), startLocal.getMinute());
DateTime end = new DateTime(endLocal.getYear(), endLocal.getMonthValue(),
endLocal.getDayOfMonth(), endLocal.getHour(), endLocal.getMinute());

// CORRECTION: utiliser getRolledUpUsage au lieu de getUsageForAccount
List<RolledUpUsage> records = usageUserApi.getRolledUpUsage(
accountId, start, end, tenantContext);

return records != null && !records.isEmpty();
} catch (Exception e) {
return false;
}
}
}

Errors :

[ERROR] /Applications/Projects/killbill/plugins/my-invoice-control-plugin/src/main/java/com/novatec/plugin/MyInvoiceControlPlugin.java:[20,8] com.monsociete.plugin.MyInvoiceControlPlugin is not abstract and does not override abstract method getAdditionalInvoiceItems(org.killbill.billing.invoice.api.Invoice,boolean,java.lang.Iterable<org.killbill.billing.payment.api.PluginProperty>,org.killbill.billing.invoice.plugin.api.InvoiceContext) in org.killbill.billing.invoice.plugin.api.InvoicePluginApi

[ERROR] /Applications/Projects/killbill/plugins/my-invoice-control-plugin/src/main/java/com/novatec/plugin/MyInvoiceControlPlugin.java:[39,34] getAdditionalInvoiceItems(org.killbill.billing.invoice.api.Invoice,boolean,java.lang.Iterable<org.killbill.billing.payment.api.PluginProperty>,org.killbill.billing.invoice.plugin.api.InvoiceContext) in com.monsociete.plugin.MyInvoiceControlPlugin cannot implement getAdditionalInvoiceItems(org.killbill.billing.invoice.api.Invoice,boolean,java.lang.Iterable<org.killbill.billing.payment.api.PluginProperty>,org.killbill.billing.invoice.plugin.api.InvoiceContext) in org.killbill.billing.invoice.plugin.api.InvoicePluginApi

[ERROR]   return type java.lang.Iterable<org.killbill.billing.invoice.api.InvoiceItem> is not compatible with org.killbill.billing.invoice.plugin.api.AdditionalItemsResult

[ERROR] /Applications/Projects/killbill/plugins/my-invoice-control-plugin/src/main/java/com/novatec/plugin/MyInvoiceControlPlugin.java:[38,5] method does not override or implement a method from a supertype

[ERROR] /Applications/Projects/killbill/plugins/my-invoice-control-plugin/src/main/java/com/novatec/plugin/MyInvoiceControlPlugin.java:[45,42] cannot find symbol

[ERROR]   symbol:   method toCallContext(<nulltype>)

[ERROR]   location: variable context of type org.killbill.billing.invoice.plugin.api.InvoiceContext

[ERROR] /Applications/Projects/killbill/plugins/my-invoice-control-plugin/src/main/java/com/novatec/plugin/MyInvoiceControlPlugin.java:[62,20] cannot find symbol

[ERROR]   symbol:   class DefaultOnFailureInvoiceResult

[ERROR]   location: class com.monsociete.plugin.MyInvoiceControlPlugin

[ERROR] /Applications/Projects/killbill/plugins/my-invoice-control-plugin/src/main/java/com/novatec/plugin/MyInvoiceControlPlugin.java:[69,20] cannot find symbol

[ERROR]   symbol:   class DefaultOnSuccessInvoiceResult

[ERROR]   location: class com.monsociete.plugin.MyInvoiceControlPlugin

[ERROR] /Applications/Projects/killbill/plugins/my-invoice-control-plugin/src/main/java/com/novatec/plugin/MyInvoiceControlPlugin.java:[90,55] cannot find symbol

[ERROR]   symbol:   method getRolledUpUsage(java.util.UUID,org.joda.time.DateTime,org.joda.time.DateTime,org.killbill.billing.util.callcontext.TenantContext)

[ERROR]   location: variable usageUserApi of type org.killbill.billing.usage.api.UsageUserApi

[ERROR] -> [Help 1]

[ERROR

[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.

[ERROR] Re-run Maven using the -X switch to enable full debug logging.

[ERROR

[ERROR] For more information about the errors and possible solutions, please read the following articles:

[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

Reply all
Reply to author
Forward
0 new messages