Skip to content

Conversation

@turip
Copy link
Member

@turip turip commented Jan 22, 2026

Overview

Rename standard invoice related types from Invoice to StandardInvoice and adjust other calls.

This is a prerequisite to split gathering invoice handling from standard invoices.

This is a non-breaking change as it is only a type/file rename.

Notes for reviewer

Summary by CodeRabbit

Release Notes

  • Refactor
    • Standardized invoice and line handling across the billing system by adopting consistent type naming conventions throughout the invoice lifecycle, improving overall system maintainability and reducing ambiguity in invoice processing.

✏️ Tip: You can customize this high-level summary in your review settings.

Rename standard invoice related types from Invoice to StandardInvoice
and adjust other calls.

This is a prerequisite to split gathering invoice handling from standard
invoices.
@turip turip requested a review from a team as a code owner January 22, 2026 17:25
@turip turip added the release-note/ignore Ignore this change when generating release notes label Jan 22, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

This PR systematically renames the billing domain's invoice and line types from generic Invoice/Line to StandardInvoice/StandardLine variants throughout the codebase, including related result types, status enums, and event types. The refactoring is consistent and mechanical, affecting service interfaces, adapters, HTTP drivers, workers, and integration layers.

Changes

Cohort / File(s) Summary
Domain Models
openmeter/billing/stdinvoice.go, openmeter/billing/stdinvoiceline.go, openmeter/billing/stdinvoicestate.go
New/updated domain files introducing StandardInvoice/StandardLine types, StandardInvoiceStatus enums, StandardInvoiceOperation constants, and comprehensive validation/lifecycle logic
Adapter Layer
openmeter/billing/adapter.go, openmeter/billing/adapter/invoice.go, openmeter/billing/adapter/stdinvoicelines.go, openmeter/billing/adapter/stdinvoicelinemapper.go, openmeter/billing/adapter/stdinvoicelinediff.go
Return type updates from Invoice/Line to StandardInvoice/StandardLine; mapping functions renamed; line diffing and upsert logic refactored to use Standard* types
Service Layer
openmeter/billing/service.go, openmeter/billing/service/invoice.go, openmeter/billing/service/invoiceapp.go, openmeter/billing/service/gatheringinvoicependinglines.go, openmeter/billing/service/stdinvoiceline.go, openmeter/billing/service/stdinvoicestate.go
All invoice/line service methods updated to return StandardInvoice/StandardLine; state machine and event handling refactored; status constants renamed
Calculator/Calculations
openmeter/billing/service/invoicecalc/*
Calculation functions and interfaces updated to operate on StandardInvoice/StandardLine; status checks and type assertions updated
Line Service
openmeter/billing/service/lineservice/*
Line entity translation, validation, and detailed-line handling updated to StandardLine types
HTTP Driver
openmeter/billing/httpdriver/invoice.go, openmeter/billing/httpdriver/invoiceline.go
API mapping functions updated to handle StandardInvoice/StandardLine; status enum usage updated; input/output type handling refactored
Event System
openmeter/billing/events.go
Event types renamed: EventInvoice → EventStandardInvoice, InvoiceCreatedEvent → StandardInvoiceCreatedEvent, InvoiceUpdatedEvent → StandardInvoiceUpdatedEvent, AdvanceInvoiceEvent → AdvanceStandardInvoiceEvent
Custom Invoicing App
openmeter/app/custominvoicing/app.go, openmeter/app/custominvoicing/httpdriver/*, openmeter/app/custominvoicing/service.go
Public methods renamed: ValidateInvoice → ValidateStandardInvoice, UpsertInvoice → UpsertStandardInvoice, FinalizeInvoice → FinalizeStandardInvoice, DeleteInvoice → DeleteStandardInvoice; result types updated
Stripe App
openmeter/app/stripe/entity/app/invoice.go, openmeter/app/stripe/entity/input.go, openmeter/app/stripe/httpdriver/webhook.go, openmeter/app/stripe/service/billing.go
Invoice operation/status types refactored; public API methods renamed to Standard* variants; input structs updated
Sandbox App
openmeter/app/sandbox/app.go, openmeter/app/sandbox/mock.go
Mock/test app methods renamed; result types and callback signatures updated
Worker Systems
openmeter/billing/worker/advance/advance.go, openmeter/billing/worker/asyncadvance/asyncadvance.go, openmeter/billing/worker/collect/collect.go, openmeter/billing/worker/subscriptionsync/*
Return types updated from Invoice/Line to StandardInvoice/StandardLine; event handler signatures updated; line patching and sync logic refactored
Notification System
openmeter/notification/consumer/consumer.go, openmeter/notification/consumer/invoice.go, openmeter/notification/eventpayload.go, openmeter/notification/invoice.go, openmeter/notification/internal/rule.go
Event type references updated; payload field types refactored; invoice line construction uses Standard* types
Database Schema
openmeter/ent/schema/billing.go
BillingInvoice field types updated: status GoType and status_details_cache JSON type use StandardInvoice* types
Test Fixtures & Mocks
openmeter/server/server_test.go, test/*
Mock service implementations and test helpers updated to use StandardInvoice/StandardLine; status checks and type assertions refactored

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • feat: custom invoicing api #2712: Changes to custom invoicing mapper functions (mapUpsertInvoiceResultFromAPI, mapFinalizeInvoiceResultFromAPI) that directly overlap with this PR's renaming of those same functions to Standard* variants.

  • refactor: remove recursive line lookups #3517: Modifies invoice line mapping functions (mapInvoiceLineFromDB and expand/mapping paths) that are renamed and migrated in this PR to their StandardLine equivalents.

  • feat: custom invocing app #2705: Updates the custom invoicing app surface (ValidateInvoice, UpsertInvoice, FinalizeInvoice, CanDraftSyncAdvance, CanIssuingSyncAdvance) which this PR renames to their StandardInvoice variants.

Suggested labels

release-note/misc, kind/refactor, area/billing

Suggested reviewers

  • tothandras
  • chrisgacsal
  • GAlexIHU
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'chore: rename invoice types' accurately summarizes the primary change—a systematic refactoring that renames Invoice-related types to StandardInvoice throughout the codebase.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/rename-invoice-types

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
openmeter/billing/stdinvoice_test.go (1)

14-56: StandardLines elements need to be pointers, but DetailedLines are correct as-is.

StandardLines is []*StandardLine (pointer slice), so each element must be &StandardLine{...}. However, DetailedLines is []DetailedLine (non-pointer slice), so the current value literals are correct—no & needed there.

Suggested fix
-lines := StandardLines{
-	{
+lines := StandardLines{
+	&StandardLine{
 		StandardLineBase: StandardLineBase{
 			ManagedResource: models.NewManagedResource(models.ManagedResourceInput{
 				Name:        "usage-based-line",
 				Description: lo.ToPtr("index=1"),
 			}),
 			Period: Period{
 				Start: time.Now().Add(time.Hour * 24),
 			},
 		},
 		DetailedLines: DetailedLines{
 			{
 				DetailedLineBase: DetailedLineBase{
 					ManagedResource: models.NewManagedResource(models.ManagedResourceInput{
 						Name:        "child-2",
 						Description: lo.ToPtr("index=1.1"),
 					}),
 					Index: lo.ToPtr(1),
 				},
 			},
 			{
 				DetailedLineBase: DetailedLineBase{
 					ManagedResource: models.NewManagedResource(models.ManagedResourceInput{
 						Name:        "child-1",
 						Description: lo.ToPtr("index=1.0"),
 					}),
 					Index: lo.ToPtr(0),
 				},
 			},
 		},
 	},
-	{
+	&StandardLine{
 		StandardLineBase: StandardLineBase{
 			ManagedResource: models.NewManagedResource(models.ManagedResourceInput{
 				Name:        "usage-based-line",
 				Description: lo.ToPtr("index=0"),
 			}),
 			Period: Period{
 				Start: time.Now(),
 			},
 		},
 	},
 }
🤖 Fix all issues with AI agents
In `@openmeter/billing/customer.go`:
- Around line 13-16: The comment above the type assertion is incorrect: it
references streaming.CustomerUsageAttribution while the code asserts var _
streaming.Customer = &InvoiceCustomer{}; update the comment to accurately
describe that InvoiceCustomer implements the streaming.Customer interface (or
change the assertion if you intended CustomerUsageAttribution). Locate the
InvoiceCustomer declaration and replace the misleading comment so it matches the
asserted interface name (streaming.Customer) and clearly states purpose, e.g.,
"InvoiceCustomer implements the streaming.Customer interface used to query
customer usage."
- Around line 38-44: InvoiceCustomer's CustomerID is required but currently has
`json:"customerId,omitempty"` which can drop it during marshaling; remove
`omitempty` from the `CustomerID` struct tag in the InvoiceCustomer type so the
field is always emitted (update the tag on the CustomerID field in the
InvoiceCustomer struct), and run/check any serialization tests and callers of
InvoiceCustomer.Validate() to ensure they no longer rely on the field being
omitted.
- Around line 57-71: The Validate method on InvoiceCustomer lacks a nil receiver
guard and will panic if called on a nil pointer; update InvoiceCustomer.Validate
to first check if i == nil and return a clear error (e.g., "invoice customer is
nil") before accessing i.CustomerID, i.Key, or i.Name so all subsequent
validations are safe.

In `@openmeter/billing/gatheringinvoice.go`:
- Around line 18-52: The Validate method CreatePendingInvoiceLinesInput.Validate
currently mutates caller data and can panic if a nil pointer exists in c.Lines;
change the loop to guard against nil entries (if line == nil append a validation
error and continue) and operate on a local copy before setting Currency (e.g.,
copy the pointed-to Line into a local variable like l := *line) so you set
l.Currency and call l.Validate() and inspect l.InvoiceID, l.DetailedLines,
l.ParentLineID, and l.SplitLineGroupID — this prevents altering the original
slice elements and avoids nil dereference panics.

In `@openmeter/billing/stdinvoiceline.go`:
- Around line 251-323: ValidateUsageBased currently dereferences i.UsageBased
and i.UsageBased.Price and can panic if those pointers are nil; update
ValidateUsageBased (and the similar UsageBasedLine.Validate at the other
location) to defensively check for nil before calling methods or accessing
fields: if i.UsageBased == nil append a validation error like "usageBased:
missing" and skip calling i.UsageBased.Validate or accessing i.UsageBased.Price,
and likewise guard the call to RateCardDiscounts.ValidateForPrice by only
invoking it when i.UsageBased != nil and i.UsageBased.Price != nil; ensure you
append readable fmt.Errorf-wrapped errors to errs and return
errors.Join(errs...) as before.
🧹 Nitpick comments (1)
openmeter/billing/customer.go (1)

18-30: Avoid calling GetUsageAttribution twice.
Tiny, but caching it reads cleaner and avoids repeated work.

♻️ Proposed refactor
 func NewInvoiceCustomer(cust customer.Customer) InvoiceCustomer {
 	ic := InvoiceCustomer{
 		Key:            cust.Key,
 		CustomerID:     cust.ID,
 		Name:           cust.Name,
 		BillingAddress: cust.BillingAddress,
 	}
 
 	// If the customer has a usage attribution, we add it to the invoice customer
 	// We use the validator but this is not an error, we allow non usage based invoices without usage attribution.
-	if err := cust.GetUsageAttribution().Validate(); err == nil {
-		ic.UsageAttribution = lo.ToPtr(cust.GetUsageAttribution())
+	ua := cust.GetUsageAttribution()
+	if err := ua.Validate(); err == nil {
+		ic.UsageAttribution = lo.ToPtr(ua)
 	}
 
 	return ic
 }

@turip turip merged commit 0ab57fa into main Jan 22, 2026
29 of 30 checks passed
@turip turip deleted the refactor/rename-invoice-types branch January 22, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/ignore Ignore this change when generating release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants