Skip to content

feat: app stripe credits support#4315

Merged
turip merged 3 commits into
mainfrom
feat/app-stripe-credits-support
May 8, 2026
Merged

feat: app stripe credits support#4315
turip merged 3 commits into
mainfrom
feat/app-stripe-credits-support

Conversation

@turip
Copy link
Copy Markdown
Member

@turip turip commented May 7, 2026

Overview

Add support for credit lines on stripe invoices.

Notes for reviewer

Summary by CodeRabbit

  • New Features

    • Added support for applying and tracking external credits on Stripe invoices across creation and updates, ensuring applied credits are preserved and updated rather than removed.
    • Improved invoice line description formatting to handle negative quantities consistently.
  • Tests

    • Added end-to-end tests covering progressive "credit then invoice" billing, including ledger-backed charge initialization and multi-phase invoice verification.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 17c83b3b-dd6b-4b3d-bdf4-962dded2c825

📥 Commits

Reviewing files that changed from the base of the PR and between 3ddb256 and 2f63cf9.

📒 Files selected for processing (2)
  • openmeter/app/stripe/appinvoice.go
  • test/app/stripe/invoice_credits_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/app/stripe/invoice_credits_test.go
  • openmeter/app/stripe/appinvoice.go

📝 Walkthrough

Walkthrough

Adds credit-type Stripe invoice lines, persists CreditRealizationID in line metadata, reconciles applied credits during invoice create/update, updates description formatting, skips credit lines in external ID mapping, and adds ledger-backed integration tests verifying credit-then-invoice progressive billing.

Changes

Stripe Invoice Credit Line Support

Layer / File(s) Summary
Data Shape
openmeter/app/stripe/appinvoice.go
New constant invoiceLineMetadataTypeCredit identifies credit-type invoice lines.
Credit Line Builders
openmeter/app/stripe/appinvoice.go
Adds getCreditStripeInvoiceItemParams, getCreditStripeAddInvoiceItemParams, getCreditStripeUpdateInvoiceItemParams to build Stripe params containing credit metadata.
Quantity Formatting
openmeter/app/stripe/appinvoice.go
getStripeInvoiceItemParams now applies "quantity expanded" description when quantity > 1 or quantity < 0.
Invoice Creation
openmeter/app/stripe/appinvoice.go
createInvoice appends Stripe invoice item params for each CreditsApplied entry and errors on missing CreditRealizationID.
Invoice Update
openmeter/app/stripe/appinvoice.go
updateInvoice indexes existing Stripe credit lines by CreditRealizationID, updates matching lines or adds new ones, and prevents deletion of preserved credits.
Credit Line Naming
openmeter/app/stripe/appinvoice.go
Adds getCreditLineName to generate human-readable applied-credit descriptions.
Result Mapping
openmeter/app/stripe/appinvoice.go
addResultExternalIDs skips credit-type lines to avoid adding them to result external ID mappings.
Test Infrastructure
test/app/stripe/invoice_test.go
Extends StripeInvoiceTestSuite with ledger-backed charges/ledger resolver fields and initializes ledger/charges stack in SetupSuite.
Test Helpers
test/app/stripe/invoice_credits_test.go
Adds helpers: expectedStripeInvoiceItem, mock expectation builders, createMockChargeIntent, createCreditPurchaseIntent, createStripeLedgerBackedCustomer, and mustSettleExternalCreditPurchase.
Integration Test
test/app/stripe/invoice_credits_test.go
TestUsageBasedCreditThenInvoiceProgressiveBillingCreditAllocation validates mid-period and final-period invoices with applied credits and asserts Stripe CreateInvoice/AddInvoiceLines metadata and amounts.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

area/billing, release-note/feature

Suggested reviewers

  • tothandras
  • GAlexIHU
  • mark-vass-konghq
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: app stripe credits support' clearly and directly summarizes the main change: adding credit line support to Stripe invoices.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/app-stripe-credits-support

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.

@turip turip force-pushed the feat/app-stripe-credits-support branch from c3446c9 to c6eead3 Compare May 7, 2026 11:43
@turip turip force-pushed the chore/allow-negative-detailed-lines branch from 33b72f9 to 47295fb Compare May 8, 2026 14:29
Base automatically changed from chore/allow-negative-detailed-lines to main May 8, 2026 14:36
@turip turip force-pushed the feat/app-stripe-credits-support branch from c6eead3 to 3ddb256 Compare May 8, 2026 15:06
@turip turip marked this pull request as ready for review May 8, 2026 15:06
@turip turip requested a review from a team as a code owner May 8, 2026 15:06
Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (1)
test/app/stripe/invoice_credits_test.go (1)

167-171: ⚡ Quick win

Add AssertExpectations after each UpsertStandardInvoice call to verify the mocks were actually hit.

Both expectStripeInvoiceCreate and expectStripeInvoiceAddLines use .Once(), but without AssertExpectations, the Once() constraint is never enforced. If the mock matcher in expectStripeInvoiceAddLines doesn't fire (e.g., descriptions or amounts are subtly wrong), the call silently falls back to zero values, UpsertStandardInvoice returns an error caught by s.NoError, but the "expected call wasn't invoked" would go undetected.

✅ Proposed fix
 upsertResult, err := stripeInvoicingApp.UpsertStandardInvoice(ctx, stripePartialInvoice)
 s.NoError(err)
 externalID, ok := upsertResult.GetExternalID()
 s.True(ok)
 s.Equal("stripe-partial-invoice-id", externalID)
+s.StripeAppClient.AssertExpectations(s.T())

And similarly after the final invoice upsert:

 upsertResult, err := stripeInvoicingApp.UpsertStandardInvoice(ctx, stripeFinalInvoice)
 s.NoError(err)
 externalID, ok := upsertResult.GetExternalID()
 s.True(ok)
 s.Equal("stripe-final-invoice-id", externalID)
+s.StripeAppClient.AssertExpectations(s.T())

Also applies to: 229-233

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/app/stripe/invoice_credits_test.go` around lines 167 - 171, The test
currently calls stripeInvoicingApp.UpsertStandardInvoice(...) twice but doesn't
verify the mock expectations; after each UpsertStandardInvoice invocation add a
call to the suite/mocks' AssertExpectations (e.g., s.T().Helper();
s.AssertExpectations(s.T()) or s.mockStripe.AssertExpectations(s.T())) so the
.Once() expectations in expectStripeInvoiceCreate and
expectStripeInvoiceAddLines are enforced; apply this right after the block that
checks upsertResult/GetExternalID and again after the later
UpsertStandardInvoice call around lines referenced (229-233) so any missed mock
call fails the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@openmeter/app/stripe/appinvoice.go`:
- Around line 231-233: createInvoice is currently appending credits from
line.CreditsApplied without checking credit.CreditRealizationID, which allows
empty IDs into Stripe metadata and causes the add/remove thrash; updateInvoice
already guards against this. Modify the loop in createInvoice that builds
stripeLineAdd (the one calling getCreditStripeAddInvoiceItemParams) to skip any
credit where credit.CreditRealizationID == "" (same guard used in
updateInvoice), so only credits with a non-empty CreditRealizationID are
converted to Stripe params.

In `@test/app/stripe/invoice_credits_test.go`:
- Around line 124-128: Add a defer call to reset the streaming connector after
adding test events to avoid leaking events across tests: after calling
s.MockStreamingConnector.AddSimpleEvent (and the other AddSimpleEvent calls
around lines corresponding to this block and the block at 186-190), add defer
s.MockStreamingConnector.Reset() so the events added by the test are cleared;
this ensures the suite-level TearDownTest (which only restores the Stripe mock)
won't leave stale events that can affect TestComplexInvoice or other tests.

---

Nitpick comments:
In `@test/app/stripe/invoice_credits_test.go`:
- Around line 167-171: The test currently calls
stripeInvoicingApp.UpsertStandardInvoice(...) twice but doesn't verify the mock
expectations; after each UpsertStandardInvoice invocation add a call to the
suite/mocks' AssertExpectations (e.g., s.T().Helper();
s.AssertExpectations(s.T()) or s.mockStripe.AssertExpectations(s.T())) so the
.Once() expectations in expectStripeInvoiceCreate and
expectStripeInvoiceAddLines are enforced; apply this right after the block that
checks upsertResult/GetExternalID and again after the later
UpsertStandardInvoice call around lines referenced (229-233) so any missed mock
call fails the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 644f56bd-9f40-45a2-947f-94d7d9fa0926

📥 Commits

Reviewing files that changed from the base of the PR and between 9f2e9e8 and 3ddb256.

📒 Files selected for processing (3)
  • openmeter/app/stripe/appinvoice.go
  • test/app/stripe/invoice_credits_test.go
  • test/app/stripe/invoice_test.go

Comment thread openmeter/app/stripe/appinvoice.go
Comment thread test/app/stripe/invoice_credits_test.go
@turip turip added area/billing release-note/feature Release note: Exciting New Features labels May 8, 2026
@turip turip enabled auto-merge (squash) May 8, 2026 15:54
@turip turip merged commit 821e693 into main May 8, 2026
25 checks passed
@turip turip deleted the feat/app-stripe-credits-support branch May 8, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/billing release-note/feature Release note: Exciting New Features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants