From d9111f6351c05c32a1f73dbc5e0cf51cea7712f2 Mon Sep 17 00:00:00 2001 From: jutur Date: Tue, 16 Jun 2026 21:43:43 -0700 Subject: [PATCH] usage: expose transition times as a typed accessor on UsageContext The invoice engine previously passed billing transition times to usage plugins via an untyped PluginProperty keyed USAGE_TRANSITIONS (a Map, Set>). Plugin authors had to know the internal property name and cast the raw Object value, making the contract fragile and undiscoverable. Add a default getUsageTransitions() method to UsageContext that returns the same map in a type-safe way. The default returns null so all existing UsageContext implementations remain binary-compatible. Kill Bill core will populate this in UsageInvoiceItemGenerator instead of (or alongside) the plugin property so plugins can migrate to the new accessor at their own pace. Fixes killbill/killbill#2257 --- .../usage/plugin/api/UsageContext.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/usage/src/main/java/org/killbill/billing/usage/plugin/api/UsageContext.java b/usage/src/main/java/org/killbill/billing/usage/plugin/api/UsageContext.java index 938ea13..0df2d2c 100644 --- a/usage/src/main/java/org/killbill/billing/usage/plugin/api/UsageContext.java +++ b/usage/src/main/java/org/killbill/billing/usage/plugin/api/UsageContext.java @@ -17,6 +17,11 @@ package org.killbill.billing.usage.plugin.api; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.killbill.billing.invoice.api.DryRunType; import org.killbill.billing.util.callcontext.TenantContext; @@ -25,6 +30,27 @@ public interface UsageContext extends TenantContext { // Specify the type of dry-run operation or null otherwise DryRunType getDryRunType(); + // Specify targetDate Associated with the invoice run LocalDate getInputTargetDate(); + + /** + * Returns the billing transition times per (subscriptionId, unit-type CSV) pair for the + * current invoice run, or {@code null} if this information was not provided. + *

+ * Previously this data was smuggled through as a plugin property keyed + * {@code USAGE_TRANSITIONS}. Exposing it as a typed accessor on {@code UsageContext} lets + * usage plugins consume it without depending on an undocumented property name, and without + * the overhead of serialising and deserialising an arbitrary {@code Object}. + *

+ * The map key is a {@code Map.Entry} where the UUID is the subscription id and + * the String is a comma-separated list of unit type names for that usage interval. + * The value is the ordered set of transition {@link DateTime} instants within that interval. + *

+ * The default implementation returns {@code null} for backwards compatibility with existing + * {@code UsageContext} implementations. + */ + default Map, Set> getUsageTransitions() { + return null; + } }